shibori 1.0.0.beta1

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.
Files changed (239) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +27 -0
  5. data/Procfile +1 -0
  6. data/README.md +24 -0
  7. data/Rakefile +2 -0
  8. data/app.json +11 -0
  9. data/builder/lineage_hunter.js +80 -0
  10. data/builder/list_item_hunter.js +106 -0
  11. data/builder/media_hunter.js +51 -0
  12. data/builder/object_factory.js +60 -0
  13. data/builder/parameter_hunter.js +69 -0
  14. data/builder/pattern_assembler.js +258 -0
  15. data/builder/pattern_exporter.js +43 -0
  16. data/builder/patternlab.js +365 -0
  17. data/builder/patternlab_grunt.js +38 -0
  18. data/builder/patternlab_gulp.js +26 -0
  19. data/builder/pseudopattern_hunter.js +78 -0
  20. data/config.json +34 -0
  21. data/docs/Pattern Lab Node.md +225 -0
  22. data/favicon.ico +0 -0
  23. data/gulpfile.js +148 -0
  24. data/index.js +20 -0
  25. data/lib/shibori/version.rb +3 -0
  26. data/lib/shibori.rb +11 -0
  27. data/package.json +44 -0
  28. data/public/data/annotations.js +109 -0
  29. data/public/styleguide/css/static.css +458 -0
  30. data/public/styleguide/css/static.scss +404 -0
  31. data/public/styleguide/css/styleguide-specific.css +170 -0
  32. data/public/styleguide/css/styleguide-specific.scss +204 -0
  33. data/public/styleguide/css/styleguide.css +880 -0
  34. data/public/styleguide/css/styleguide.scss +950 -0
  35. data/public/styleguide/css/vendor/prism.css +112 -0
  36. data/public/styleguide/css/vendor/typeahead.css +66 -0
  37. data/public/styleguide/fonts/icomoon.eot +0 -0
  38. data/public/styleguide/fonts/icomoon.svg +22 -0
  39. data/public/styleguide/fonts/icomoon.ttf +0 -0
  40. data/public/styleguide/fonts/icomoon.woff +0 -0
  41. data/public/styleguide/html/README +1 -0
  42. data/public/styleguide/images/spinner.gif +0 -0
  43. data/public/styleguide/js/annotations-pattern.js +308 -0
  44. data/public/styleguide/js/annotations-viewer.js +289 -0
  45. data/public/styleguide/js/code-pattern.js +120 -0
  46. data/public/styleguide/js/code-viewer.js +443 -0
  47. data/public/styleguide/js/data-saver.js +169 -0
  48. data/public/styleguide/js/pattern-finder.js +114 -0
  49. data/public/styleguide/js/postmessage.js +127 -0
  50. data/public/styleguide/js/styleguide.js +600 -0
  51. data/public/styleguide/js/url-handler.js +182 -0
  52. data/public/styleguide/js/vendor/classlist-polyfill.js +176 -0
  53. data/public/styleguide/js/vendor/jquery.js +4 -0
  54. data/public/styleguide/js/vendor/jwerty.js +523 -0
  55. data/public/styleguide/js/vendor/prism.js +7 -0
  56. data/public/styleguide/js/vendor/typeahead.bundle.min.js +7 -0
  57. data/script/bootstrap +58 -0
  58. data/shibori.gemspec +18 -0
  59. data/shibori.jpg +0 -0
  60. data/source/_data/annotations.js +109 -0
  61. data/source/_data/data.json +93 -0
  62. data/source/_data/listitems.json +782 -0
  63. data/source/_patternlab-files/README +1 -0
  64. data/source/_patternlab-files/index.mustache +94 -0
  65. data/source/_patternlab-files/partials/ishControls.mustache +64 -0
  66. data/source/_patternlab-files/partials/patternNav.mustache +17 -0
  67. data/source/_patternlab-files/partials/patternPaths.mustache +3 -0
  68. data/source/_patternlab-files/partials/viewAllPaths.mustache +3 -0
  69. data/source/_patternlab-files/pattern-header-footer/README +1 -0
  70. data/source/_patternlab-files/pattern-header-footer/footer.html +34 -0
  71. data/source/_patternlab-files/pattern-header-footer/header.html +44 -0
  72. data/source/_patternlab-files/styleguide.mustache +75 -0
  73. data/source/_patternlab-files/viewall.mustache +75 -0
  74. data/source/_patterns/00-atoms/00-typography/00-headings.mustache +6 -0
  75. data/source/_patterns/00-atoms/00-typography/01-headings-options.mustache +7 -0
  76. data/source/_patterns/00-atoms/00-typography/02-body.mustache +2 -0
  77. data/source/_patterns/00-atoms/00-typography/03-text-manipulation.mustache +12 -0
  78. data/source/_patterns/00-atoms/00-typography/04-blockquotes.mustache +3 -0
  79. data/source/_patterns/00-atoms/00-typography/05-lists.mustache +64 -0
  80. data/source/_patterns/00-atoms/01-colors/00-colors-monochromatic.mustache +36 -0
  81. data/source/_patterns/00-atoms/01-colors/01-colors-brand.mustache +26 -0
  82. data/source/_patterns/00-atoms/01-colors/02-colors-gradients.mustache +38 -0
  83. data/source/_patterns/00-atoms/02-buttons/00-btn-lg.mustache +7 -0
  84. data/source/_patterns/00-atoms/02-buttons/01-btn-sm.mustache +7 -0
  85. data/source/_patterns/00-atoms/02-buttons/02-btn-xs.mustache +7 -0
  86. data/source/_patterns/00-atoms/02-buttons/03-btn-block.mustache +7 -0
  87. data/source/_patterns/00-atoms/02-buttons/04-btn-deploy.mustache +4 -0
  88. data/source/_patterns/00-atoms/03-forms/00-text-fields.mustache +24 -0
  89. data/source/_patterns/00-atoms/03-forms/01-select-menu.mustache +6 -0
  90. data/source/_patterns/00-atoms/03-forms/02-checkbox.mustache +10 -0
  91. data/source/_patterns/00-atoms/03-forms/03-radios.mustache +10 -0
  92. data/source/_patterns/00-atoms/03-forms/04-validation.mustache +14 -0
  93. data/source/_patterns/00-atoms/04-quote/00-pullquote.mustache +7 -0
  94. data/source/_patterns/00-atoms/04-quote/01-quote-small.mustache +7 -0
  95. data/source/_patterns/00-atoms/05-code/01-pre.mustache +11 -0
  96. data/source/_patterns/00-atoms/06-tooltips/00-text.mustache +3 -0
  97. data/source/_patterns/00-atoms/06-tooltips/01-diagram-callout.mustache +1 -0
  98. data/source/_patterns/00-atoms/07-loader/00-spinner.mustache +5 -0
  99. data/source/_patterns/00-atoms/08-readmore/00-readmore.mustache +3 -0
  100. data/source/_patterns/00-atoms/09-slider/00-dots.mustache +8 -0
  101. data/source/_patterns/00-atoms/10-tables/00-tables.mustache +26 -0
  102. data/source/_patterns/00-atoms/12-modal/00-modal.mustache +14 -0
  103. data/source/_patterns/00-atoms/13-panel/00-panel.mustache +3 -0
  104. data/source/_patterns/00-atoms/14-users/00-avatar.mustache +3 -0
  105. data/source/_patterns/00-atoms/15-icons/00-icons.mustache +333 -0
  106. data/source/_patterns/00-atoms/15-icons/04-icon-colors.mustache +38 -0
  107. data/source/_patterns/00-atoms/15-icons/05-icon-sizes.mustache +31 -0
  108. data/source/_patterns/00-atoms/15-icons/_02-languages.mustache +0 -0
  109. data/source/_patterns/00-atoms/15-icons/_03-social.mustache +0 -0
  110. data/source/_patterns/00-atoms/15-icons/_05-icon-containers.mustache +0 -0
  111. data/source/_patterns/00-atoms/16-video/01-video.mustache +3 -0
  112. data/source/_patterns/00-atoms/16-video/_00-play-button.mustache +0 -0
  113. data/source/_patterns/00-atoms/17-utilities/00-visibility.mustache +8 -0
  114. data/source/_patterns/00-atoms/17-utilities/01-ui-elements.mustache +3 -0
  115. data/source/_patterns/00-atoms/18-grid/_00-grid.mustache +0 -0
  116. data/source/_patterns/01-molecules/00-text/00-header-groups.mustache +4 -0
  117. data/source/_patterns/01-molecules/00-text/01-intro-text.mustache +5 -0
  118. data/source/_patterns/01-molecules/01-layout/00-one-up.mustache +8 -0
  119. data/source/_patterns/01-molecules/01-layout/01-two-up.mustache +9 -0
  120. data/source/_patterns/01-molecules/01-layout/02-three-up.mustache +10 -0
  121. data/source/_patterns/01-molecules/01-layout/03-four-up.mustache +11 -0
  122. data/source/_patterns/01-molecules/01-layout/04-masonary-2.mustache +24 -0
  123. data/source/_patterns/01-molecules/01-layout/05-masonary-3.mustache +24 -0
  124. data/source/_patterns/01-molecules/02-navigation/01-subnav.mustache +21 -0
  125. data/source/_patterns/01-molecules/02-navigation/02-breadcrumbs.mustache +25 -0
  126. data/source/_patterns/01-molecules/02-navigation/03-side-nav.mustache +11 -0
  127. data/source/_patterns/01-molecules/02-navigation/04-side-nav-small.mustache +32 -0
  128. data/source/_patterns/01-molecules/02-navigation/05-pagination.mustache +0 -0
  129. data/source/_patterns/01-molecules/02-navigation/06-tabs.mustache +46 -0
  130. data/source/_patterns/01-molecules/03-forms/_00-search.mustache +0 -0
  131. data/source/_patterns/01-molecules/04-slider/00-slider.mustache +8 -0
  132. data/source/_patterns/01-molecules/05-messages/00-alert.mustache +15 -0
  133. data/source/_patterns/01-molecules/06-components/_00-social-share.mustache +0 -0
  134. data/source/_patterns/01-molecules/07-Elements/01-Addons-Card.mustache +79 -0
  135. data/source/_patterns/01-molecules/07-Elements/02-Buttons-Card.mustache +131 -0
  136. data/source/_patterns/01-molecules/07-Elements/03-Buildpack-Card.mustache +109 -0
  137. data/source/_patterns/01-molecules/08-vertical-tabs/01-vertical-tabs.mustache +30 -0
  138. data/source/_patterns/02-organisms/03-sections/00-purple.mustache +11 -0
  139. data/source/_patterns/02-organisms/03-sections/01-purple-dark.mustache +12 -0
  140. data/source/_patterns/02-organisms/03-sections/03-gray-light.mustache +12 -0
  141. data/source/css/hk-icon-rails.scss +13 -0
  142. data/source/css/scss/base/_base.scss +62 -0
  143. data/source/css/scss/base/_fonts.scss +12 -0
  144. data/source/css/scss/base/_normalize.scss +431 -0
  145. data/source/css/scss/base/_type.scss +128 -0
  146. data/source/css/scss/base/_utilities.scss +78 -0
  147. data/source/css/scss/components/_alert.scss +38 -0
  148. data/source/css/scss/components/_animate.scss +3340 -0
  149. data/source/css/scss/components/_animation.scss +15 -0
  150. data/source/css/scss/components/_buttons.scss +175 -0
  151. data/source/css/scss/components/_code.scss +26 -0
  152. data/source/css/scss/components/_forms.scss +136 -0
  153. data/source/css/scss/components/_hero.scss +18 -0
  154. data/source/css/scss/components/_hr.scss +11 -0
  155. data/source/css/scss/components/_icons.scss +85 -0
  156. data/source/css/scss/components/_lists.scss +45 -0
  157. data/source/css/scss/components/_logos.scss +15 -0
  158. data/source/css/scss/components/_masonary.scss +46 -0
  159. data/source/css/scss/components/_modal.scss +218 -0
  160. data/source/css/scss/components/_owlCarousel.scss +270 -0
  161. data/source/css/scss/components/_panel.scss +11 -0
  162. data/source/css/scss/components/_pill-box.scss +38 -0
  163. data/source/css/scss/components/_quote.scss +96 -0
  164. data/source/css/scss/components/_readmore.scss +11 -0
  165. data/source/css/scss/components/_slider.scss +96 -0
  166. data/source/css/scss/components/_spinner.scss +64 -0
  167. data/source/css/scss/components/_sprites.scss +3 -0
  168. data/source/css/scss/components/_sr-only.scss +10 -0
  169. data/source/css/scss/components/_tables.scss +62 -0
  170. data/source/css/scss/components/_tooltips.scss +93 -0
  171. data/source/css/scss/components/_users.scss +11 -0
  172. data/source/css/scss/components/_vertical-tabs.scss +129 -0
  173. data/source/css/scss/components/_video.scss +7 -0
  174. data/source/css/scss/ecosystem/_addons-card.scss +3 -0
  175. data/source/css/scss/ecosystem/_cards.scss +369 -0
  176. data/source/css/scss/ecosystem/_elements-brand.scss +32 -0
  177. data/source/css/scss/ecosystem/_elements.scss +4 -0
  178. data/source/css/scss/globals/_colors.scss +189 -0
  179. data/source/css/scss/globals/_mixins.scss +45 -0
  180. data/source/css/scss/globals/_variables.scss +87 -0
  181. data/source/css/scss/layout/_grid-settings.scss +13 -0
  182. data/source/css/scss/layout/_layout.scss +95 -0
  183. data/source/css/scss/page-elements/_headers.scss +3 -0
  184. data/source/css/scss/page-elements/_navigation.scss +254 -0
  185. data/source/css/scss/page-elements/_sections.scss +66 -0
  186. data/source/css/scss/page-elements/_sidebar.scss +34 -0
  187. data/source/css/shibori.scss +63 -0
  188. data/source/fonts/bentonsans/bentonsans-book.eot +0 -0
  189. data/source/fonts/bentonsans/bentonsans-book.svg +400 -0
  190. data/source/fonts/bentonsans/bentonsans-book.ttf +0 -0
  191. data/source/fonts/bentonsans/bentonsans-book.woff +0 -0
  192. data/source/fonts/bentonsans/bentonsans-medium.eot +0 -0
  193. data/source/fonts/bentonsans/bentonsans-medium.svg +416 -0
  194. data/source/fonts/bentonsans/bentonsans-medium.ttf +0 -0
  195. data/source/fonts/bentonsans/bentonsans-medium.woff +0 -0
  196. data/source/fonts/bentonsans/bentonsans-regular.eot +0 -0
  197. data/source/fonts/bentonsans/bentonsans-regular.svg +416 -0
  198. data/source/fonts/bentonsans/bentonsans-regular.ttf +0 -0
  199. data/source/fonts/bentonsans/bentonsans-regular.woff +0 -0
  200. data/source/fonts/hk-icon/hk-icon.eot +0 -0
  201. data/source/fonts/hk-icon/hk-icon.svg +261 -0
  202. data/source/fonts/hk-icon/hk-icon.ttf +0 -0
  203. data/source/fonts/hk-icon/hk-icon.woff +0 -0
  204. data/source/fonts/inconsolata/inconsolata-bold.eot +0 -0
  205. data/source/fonts/inconsolata/inconsolata-bold.svg +239 -0
  206. data/source/fonts/inconsolata/inconsolata-bold.ttf +0 -0
  207. data/source/fonts/inconsolata/inconsolata-bold.woff +0 -0
  208. data/source/fonts/inconsolata/inconsolata-regular.eot +0 -0
  209. data/source/fonts/inconsolata/inconsolata-regular.svg +239 -0
  210. data/source/fonts/inconsolata/inconsolata-regular.ttf +0 -0
  211. data/source/fonts/inconsolata/inconsolata-regular.woff +0 -0
  212. data/source/images/blockquote/close-sm.png +0 -0
  213. data/source/images/blockquote/close.png +0 -0
  214. data/source/images/blockquote/close@2x.png +0 -0
  215. data/source/images/blockquote/open-sm.png +0 -0
  216. data/source/images/blockquote/open.png +0 -0
  217. data/source/images/blockquote/open@2x.png +0 -0
  218. data/source/images/elements/heroku_suported.svg +32 -0
  219. data/source/images/forms/select-input-arrows.svg +8 -0
  220. data/source/js/init.js +26 -0
  221. data/source/js/main.js +22 -0
  222. data/source/js/vendor/bourbon-modal.js +17 -0
  223. data/source/js/vendor/fitvids.js +77 -0
  224. data/source/js/vendor/fixto.js +719 -0
  225. data/source/js/vendor/jquery-2.0.0b2.js +8690 -0
  226. data/source/js/vendor/modernizr.js +4 -0
  227. data/source/js/vendor/owl.carousel.js +3069 -0
  228. data/source/js/vendor/readmore.js +11 -0
  229. data/source/js/vendor/unslider.js +1 -0
  230. data/source/js/vendor/vertical-tabs.js +34 -0
  231. data/test/files/test.css +19 -0
  232. data/test/lineage_hunter_tests.js +262 -0
  233. data/test/list_item_hunter_tests.js +167 -0
  234. data/test/media_hunter_tests.js +74 -0
  235. data/test/object_factory_tests.js +62 -0
  236. data/test/parameter_hunter_tests.js +298 -0
  237. data/test/pattern_assembler_tests.js +43 -0
  238. data/test/patternlab_tests.js +8 -0
  239. metadata +320 -0
@@ -0,0 +1,3069 @@
1
+ /**
2
+ * Owl carousel
3
+ * @version 2.0.0
4
+ * @author Bartosz Wojciechowski
5
+ * @license The MIT License (MIT)
6
+ * @todo Lazy Load Icon
7
+ * @todo prevent animationend bubling
8
+ * @todo itemsScaleUp
9
+ * @todo Test Zepto
10
+ * @todo stagePadding calculate wrong active classes
11
+ */
12
+ ;(function($, window, document, undefined) {
13
+
14
+ var drag, state, e;
15
+
16
+ /**
17
+ * Template for status information about drag and touch events.
18
+ * @private
19
+ */
20
+ drag = {
21
+ start: 0,
22
+ startX: 0,
23
+ startY: 0,
24
+ current: 0,
25
+ currentX: 0,
26
+ currentY: 0,
27
+ offsetX: 0,
28
+ offsetY: 0,
29
+ distance: null,
30
+ startTime: 0,
31
+ endTime: 0,
32
+ updatedX: 0,
33
+ targetEl: null
34
+ };
35
+
36
+ /**
37
+ * Template for some status informations.
38
+ * @private
39
+ */
40
+ state = {
41
+ isTouch: false,
42
+ isScrolling: false,
43
+ isSwiping: false,
44
+ direction: false,
45
+ inMotion: false
46
+ };
47
+
48
+ /**
49
+ * Event functions references.
50
+ * @private
51
+ */
52
+ e = {
53
+ _onDragStart: null,
54
+ _onDragMove: null,
55
+ _onDragEnd: null,
56
+ _transitionEnd: null,
57
+ _resizer: null,
58
+ _responsiveCall: null,
59
+ _goToLoop: null,
60
+ _checkVisibile: null
61
+ };
62
+
63
+ /**
64
+ * Creates a carousel.
65
+ * @class The Owl Carousel.
66
+ * @public
67
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
68
+ * @param {Object} [options] - The options
69
+ */
70
+ function Owl(element, options) {
71
+
72
+ /**
73
+ * Current settings for the carousel.
74
+ * @public
75
+ */
76
+ this.settings = null;
77
+
78
+ /**
79
+ * Current options set by the caller including defaults.
80
+ * @public
81
+ */
82
+ this.options = $.extend({}, Owl.Defaults, options);
83
+
84
+ /**
85
+ * Plugin element.
86
+ * @public
87
+ */
88
+ this.$element = $(element);
89
+
90
+ /**
91
+ * Caches informations about drag and touch events.
92
+ */
93
+ this.drag = $.extend({}, drag);
94
+
95
+ /**
96
+ * Caches some status informations.
97
+ * @protected
98
+ */
99
+ this.state = $.extend({}, state);
100
+
101
+ /**
102
+ * @protected
103
+ * @todo Must be documented
104
+ */
105
+ this.e = $.extend({}, e);
106
+
107
+ /**
108
+ * References to the running plugins of this carousel.
109
+ * @protected
110
+ */
111
+ this._plugins = {};
112
+
113
+ /**
114
+ * Currently suppressed events to prevent them from beeing retriggered.
115
+ * @protected
116
+ */
117
+ this._supress = {};
118
+
119
+ /**
120
+ * Absolute current position.
121
+ * @protected
122
+ */
123
+ this._current = null;
124
+
125
+ /**
126
+ * Animation speed in milliseconds.
127
+ * @protected
128
+ */
129
+ this._speed = null;
130
+
131
+ /**
132
+ * Coordinates of all items in pixel.
133
+ * @todo The name of this member is missleading.
134
+ * @protected
135
+ */
136
+ this._coordinates = [];
137
+
138
+ /**
139
+ * Current breakpoint.
140
+ * @todo Real media queries would be nice.
141
+ * @protected
142
+ */
143
+ this._breakpoint = null;
144
+
145
+ /**
146
+ * Current width of the plugin element.
147
+ */
148
+ this._width = null;
149
+
150
+ /**
151
+ * All real items.
152
+ * @protected
153
+ */
154
+ this._items = [];
155
+
156
+ /**
157
+ * All cloned items.
158
+ * @protected
159
+ */
160
+ this._clones = [];
161
+
162
+ /**
163
+ * Merge values of all items.
164
+ * @todo Maybe this could be part of a plugin.
165
+ * @protected
166
+ */
167
+ this._mergers = [];
168
+
169
+ /**
170
+ * Invalidated parts within the update process.
171
+ * @protected
172
+ */
173
+ this._invalidated = {};
174
+
175
+ /**
176
+ * Ordered list of workers for the update process.
177
+ * @protected
178
+ */
179
+ this._pipe = [];
180
+
181
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
182
+ this._plugins[key[0].toLowerCase() + key.slice(1)]
183
+ = new plugin(this);
184
+ }, this));
185
+
186
+ $.each(Owl.Pipe, $.proxy(function(priority, worker) {
187
+ this._pipe.push({
188
+ 'filter': worker.filter,
189
+ 'run': $.proxy(worker.run, this)
190
+ });
191
+ }, this));
192
+
193
+ this.setup();
194
+ this.initialize();
195
+ }
196
+
197
+ /**
198
+ * Default options for the carousel.
199
+ * @public
200
+ */
201
+ Owl.Defaults = {
202
+ items: 3,
203
+ loop: false,
204
+ center: false,
205
+
206
+ mouseDrag: true,
207
+ touchDrag: true,
208
+ pullDrag: true,
209
+ freeDrag: false,
210
+
211
+ margin: 0,
212
+ stagePadding: 0,
213
+
214
+ merge: false,
215
+ mergeFit: true,
216
+ autoWidth: false,
217
+
218
+ startPosition: 0,
219
+ rtl: false,
220
+
221
+ smartSpeed: 250,
222
+ fluidSpeed: false,
223
+ dragEndSpeed: false,
224
+
225
+ responsive: {},
226
+ responsiveRefreshRate: 200,
227
+ responsiveBaseElement: window,
228
+ responsiveClass: false,
229
+
230
+ fallbackEasing: 'swing',
231
+
232
+ info: false,
233
+
234
+ nestedItemSelector: false,
235
+ itemElement: 'div',
236
+ stageElement: 'div',
237
+
238
+ // Classes and Names
239
+ themeClass: 'owl-theme',
240
+ baseClass: 'owl-carousel',
241
+ itemClass: 'owl-item',
242
+ centerClass: 'center',
243
+ activeClass: 'active'
244
+ };
245
+
246
+ /**
247
+ * Enumeration for width.
248
+ * @public
249
+ * @readonly
250
+ * @enum {String}
251
+ */
252
+ Owl.Width = {
253
+ Default: 'default',
254
+ Inner: 'inner',
255
+ Outer: 'outer'
256
+ };
257
+
258
+ /**
259
+ * Contains all registered plugins.
260
+ * @public
261
+ */
262
+ Owl.Plugins = {};
263
+
264
+ /**
265
+ * Update pipe.
266
+ */
267
+ Owl.Pipe = [ {
268
+ filter: [ 'width', 'items', 'settings' ],
269
+ run: function(cache) {
270
+ cache.current = this._items && this._items[this.relative(this._current)];
271
+ }
272
+ }, {
273
+ filter: [ 'items', 'settings' ],
274
+ run: function() {
275
+ var cached = this._clones,
276
+ clones = this.$stage.children('.cloned');
277
+
278
+ if (clones.length !== cached.length || (!this.settings.loop && cached.length > 0)) {
279
+ this.$stage.children('.cloned').remove();
280
+ this._clones = [];
281
+ }
282
+ }
283
+ }, {
284
+ filter: [ 'items', 'settings' ],
285
+ run: function() {
286
+ var i, n,
287
+ clones = this._clones,
288
+ items = this._items,
289
+ delta = this.settings.loop ? clones.length - Math.max(this.settings.items * 2, 4) : 0;
290
+
291
+ for (i = 0, n = Math.abs(delta / 2); i < n; i++) {
292
+ if (delta > 0) {
293
+ this.$stage.children().eq(items.length + clones.length - 1).remove();
294
+ clones.pop();
295
+ this.$stage.children().eq(0).remove();
296
+ clones.pop();
297
+ } else {
298
+ clones.push(clones.length / 2);
299
+ this.$stage.append(items[clones[clones.length - 1]].clone().addClass('cloned'));
300
+ clones.push(items.length - 1 - (clones.length - 1) / 2);
301
+ this.$stage.prepend(items[clones[clones.length - 1]].clone().addClass('cloned'));
302
+ }
303
+ }
304
+ }
305
+ }, {
306
+ filter: [ 'width', 'items', 'settings' ],
307
+ run: function() {
308
+ var rtl = (this.settings.rtl ? 1 : -1),
309
+ width = (this.width() / this.settings.items).toFixed(3),
310
+ coordinate = 0, merge, i, n;
311
+
312
+ this._coordinates = [];
313
+ for (i = 0, n = this._clones.length + this._items.length; i < n; i++) {
314
+ merge = this._mergers[this.relative(i)];
315
+ merge = (this.settings.mergeFit && Math.min(merge, this.settings.items)) || merge;
316
+ coordinate += (this.settings.autoWidth ? this._items[this.relative(i)].width() + this.settings.margin : width * merge) * rtl;
317
+
318
+ this._coordinates.push(coordinate);
319
+ }
320
+ }
321
+ }, {
322
+ filter: [ 'width', 'items', 'settings' ],
323
+ run: function() {
324
+ var i, n, width = (this.width() / this.settings.items).toFixed(3), css = {
325
+ 'width': Math.abs(this._coordinates[this._coordinates.length - 1]) + this.settings.stagePadding * 2,
326
+ 'padding-left': this.settings.stagePadding || '',
327
+ 'padding-right': this.settings.stagePadding || ''
328
+ };
329
+
330
+ this.$stage.css(css);
331
+
332
+ css = { 'width': this.settings.autoWidth ? 'auto' : width - this.settings.margin };
333
+ css[this.settings.rtl ? 'margin-left' : 'margin-right'] = this.settings.margin;
334
+
335
+ if (!this.settings.autoWidth && $.grep(this._mergers, function(v) { return v > 1 }).length > 0) {
336
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
337
+ css.width = Math.abs(this._coordinates[i]) - Math.abs(this._coordinates[i - 1] || 0) - this.settings.margin;
338
+ this.$stage.children().eq(i).css(css);
339
+ }
340
+ } else {
341
+ this.$stage.children().css(css);
342
+ }
343
+ }
344
+ }, {
345
+ filter: [ 'width', 'items', 'settings' ],
346
+ run: function(cache) {
347
+ cache.current && this.reset(this.$stage.children().index(cache.current));
348
+ }
349
+ }, {
350
+ filter: [ 'position' ],
351
+ run: function() {
352
+ this.animate(this.coordinates(this._current));
353
+ }
354
+ }, {
355
+ filter: [ 'width', 'position', 'items', 'settings' ],
356
+ run: function() {
357
+ var rtl = this.settings.rtl ? 1 : -1,
358
+ padding = this.settings.stagePadding * 2,
359
+ begin = this.coordinates(this.current()) + padding,
360
+ end = begin + this.width() * rtl,
361
+ inner, outer, matches = [], i, n;
362
+
363
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
364
+ inner = this._coordinates[i - 1] || 0;
365
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
366
+
367
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
368
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
369
+ matches.push(i);
370
+ }
371
+ }
372
+
373
+ this.$stage.children('.' + this.settings.activeClass).removeClass(this.settings.activeClass);
374
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass(this.settings.activeClass);
375
+
376
+ if (this.settings.center) {
377
+ this.$stage.children('.' + this.settings.centerClass).removeClass(this.settings.centerClass);
378
+ this.$stage.children().eq(this.current()).addClass(this.settings.centerClass);
379
+ }
380
+ }
381
+ } ];
382
+
383
+ /**
384
+ * Initializes the carousel.
385
+ * @protected
386
+ */
387
+ Owl.prototype.initialize = function() {
388
+ this.trigger('initialize');
389
+
390
+ this.$element
391
+ .addClass(this.settings.baseClass)
392
+ .addClass(this.settings.themeClass)
393
+ .toggleClass('owl-rtl', this.settings.rtl);
394
+
395
+ // check support
396
+ this.browserSupport();
397
+
398
+ if (this.settings.autoWidth && this.state.imagesLoaded !== true) {
399
+ var imgs, nestedSelector, width;
400
+ imgs = this.$element.find('img');
401
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
402
+ width = this.$element.children(nestedSelector).width();
403
+
404
+ if (imgs.length && width <= 0) {
405
+ this.preloadAutoWidthImages(imgs);
406
+ return false;
407
+ }
408
+ }
409
+
410
+ this.$element.addClass('owl-loading');
411
+
412
+ // create stage
413
+ this.$stage = $('<' + this.settings.stageElement + ' class="owl-stage"/>')
414
+ .wrap('<div class="owl-stage-outer">');
415
+
416
+ // append stage
417
+ this.$element.append(this.$stage.parent());
418
+
419
+ // append content
420
+ this.replace(this.$element.children().not(this.$stage.parent()));
421
+
422
+ // set view width
423
+ this._width = this.$element.width();
424
+
425
+ // update view
426
+ this.refresh();
427
+
428
+ this.$element.removeClass('owl-loading').addClass('owl-loaded');
429
+
430
+ // attach generic events
431
+ this.eventsCall();
432
+
433
+ // attach generic events
434
+ this.internalEvents();
435
+
436
+ // attach custom control events
437
+ this.addTriggerableEvents();
438
+
439
+ this.trigger('initialized');
440
+ };
441
+
442
+ /**
443
+ * Setups the current settings.
444
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
445
+ * @todo Support for media queries by using `matchMedia` would be nice.
446
+ * @public
447
+ */
448
+ Owl.prototype.setup = function() {
449
+ var viewport = this.viewport(),
450
+ overwrites = this.options.responsive,
451
+ match = -1,
452
+ settings = null;
453
+
454
+ if (!overwrites) {
455
+ settings = $.extend({}, this.options);
456
+ } else {
457
+ $.each(overwrites, function(breakpoint) {
458
+ if (breakpoint <= viewport && breakpoint > match) {
459
+ match = Number(breakpoint);
460
+ }
461
+ });
462
+
463
+ settings = $.extend({}, this.options, overwrites[match]);
464
+ delete settings.responsive;
465
+
466
+ // responsive class
467
+ if (settings.responsiveClass) {
468
+ this.$element.attr('class', function(i, c) {
469
+ return c.replace(/\b owl-responsive-\S+/g, '');
470
+ }).addClass('owl-responsive-' + match);
471
+ }
472
+ }
473
+
474
+ if (this.settings === null || this._breakpoint !== match) {
475
+ this.trigger('change', { property: { name: 'settings', value: settings } });
476
+ this._breakpoint = match;
477
+ this.settings = settings;
478
+ this.invalidate('settings');
479
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
480
+ }
481
+ };
482
+
483
+ /**
484
+ * Updates option logic if necessery.
485
+ * @protected
486
+ */
487
+ Owl.prototype.optionsLogic = function() {
488
+ // Toggle Center class
489
+ this.$element.toggleClass('owl-center', this.settings.center);
490
+
491
+ // if items number is less than in body
492
+ if (this.settings.loop && this._items.length < this.settings.items) {
493
+ this.settings.loop = false;
494
+ }
495
+
496
+ if (this.settings.autoWidth) {
497
+ this.settings.stagePadding = false;
498
+ this.settings.merge = false;
499
+ }
500
+ };
501
+
502
+ /**
503
+ * Prepares an item before add.
504
+ * @todo Rename event parameter `content` to `item`.
505
+ * @protected
506
+ * @returns {jQuery|HTMLElement} - The item container.
507
+ */
508
+ Owl.prototype.prepare = function(item) {
509
+ var event = this.trigger('prepare', { content: item });
510
+
511
+ if (!event.data) {
512
+ event.data = $('<' + this.settings.itemElement + '/>')
513
+ .addClass(this.settings.itemClass).append(item)
514
+ }
515
+
516
+ this.trigger('prepared', { content: event.data });
517
+
518
+ return event.data;
519
+ };
520
+
521
+ /**
522
+ * Updates the view.
523
+ * @public
524
+ */
525
+ Owl.prototype.update = function() {
526
+ var i = 0,
527
+ n = this._pipe.length,
528
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
529
+ cache = {};
530
+
531
+ while (i < n) {
532
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
533
+ this._pipe[i].run(cache);
534
+ }
535
+ i++;
536
+ }
537
+
538
+ this._invalidated = {};
539
+ };
540
+
541
+ /**
542
+ * Gets the width of the view.
543
+ * @public
544
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
545
+ * @returns {Number} - The width of the view in pixel.
546
+ */
547
+ Owl.prototype.width = function(dimension) {
548
+ dimension = dimension || Owl.Width.Default;
549
+ switch (dimension) {
550
+ case Owl.Width.Inner:
551
+ case Owl.Width.Outer:
552
+ return this._width;
553
+ default:
554
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
555
+ }
556
+ };
557
+
558
+ /**
559
+ * Refreshes the carousel primarily for adaptive purposes.
560
+ * @public
561
+ */
562
+ Owl.prototype.refresh = function() {
563
+ if (this._items.length === 0) {
564
+ return false;
565
+ }
566
+
567
+ var start = new Date().getTime();
568
+
569
+ this.trigger('refresh');
570
+
571
+ this.setup();
572
+
573
+ this.optionsLogic();
574
+
575
+ // hide and show methods helps here to set a proper widths,
576
+ // this prevents scrollbar to be calculated in stage width
577
+ this.$stage.addClass('owl-refresh');
578
+
579
+ this.update();
580
+
581
+ this.$stage.removeClass('owl-refresh');
582
+
583
+ this.state.orientation = window.orientation;
584
+
585
+ this.watchVisibility();
586
+
587
+ this.trigger('refreshed');
588
+ };
589
+
590
+ /**
591
+ * Save internal event references and add event based functions.
592
+ * @protected
593
+ */
594
+ Owl.prototype.eventsCall = function() {
595
+ // Save events references
596
+ this.e._onDragStart = $.proxy(function(e) {
597
+ this.onDragStart(e);
598
+ }, this);
599
+ this.e._onDragMove = $.proxy(function(e) {
600
+ this.onDragMove(e);
601
+ }, this);
602
+ this.e._onDragEnd = $.proxy(function(e) {
603
+ this.onDragEnd(e);
604
+ }, this);
605
+ this.e._onResize = $.proxy(function(e) {
606
+ this.onResize(e);
607
+ }, this);
608
+ this.e._transitionEnd = $.proxy(function(e) {
609
+ this.transitionEnd(e);
610
+ }, this);
611
+ this.e._preventClick = $.proxy(function(e) {
612
+ this.preventClick(e);
613
+ }, this);
614
+ };
615
+
616
+ /**
617
+ * Checks window `resize` event.
618
+ * @protected
619
+ */
620
+ Owl.prototype.onThrottledResize = function() {
621
+ window.clearTimeout(this.resizeTimer);
622
+ this.resizeTimer = window.setTimeout(this.e._onResize, this.settings.responsiveRefreshRate);
623
+ };
624
+
625
+ /**
626
+ * Checks window `resize` event.
627
+ * @protected
628
+ */
629
+ Owl.prototype.onResize = function() {
630
+ if (!this._items.length) {
631
+ return false;
632
+ }
633
+
634
+ if (this._width === this.$element.width()) {
635
+ return false;
636
+ }
637
+
638
+ if (this.trigger('resize').isDefaultPrevented()) {
639
+ return false;
640
+ }
641
+
642
+ this._width = this.$element.width();
643
+
644
+ this.invalidate('width');
645
+
646
+ this.refresh();
647
+
648
+ this.trigger('resized');
649
+ };
650
+
651
+ /**
652
+ * Checks for touch/mouse drag event type and add run event handlers.
653
+ * @protected
654
+ */
655
+ Owl.prototype.eventsRouter = function(event) {
656
+ var type = event.type;
657
+
658
+ if (type === "mousedown" || type === "touchstart") {
659
+ this.onDragStart(event);
660
+ } else if (type === "mousemove" || type === "touchmove") {
661
+ this.onDragMove(event);
662
+ } else if (type === "mouseup" || type === "touchend") {
663
+ this.onDragEnd(event);
664
+ } else if (type === "touchcancel") {
665
+ this.onDragEnd(event);
666
+ }
667
+ };
668
+
669
+ /**
670
+ * Checks for touch/mouse drag options and add necessery event handlers.
671
+ * @protected
672
+ */
673
+ Owl.prototype.internalEvents = function() {
674
+ var isTouch = isTouchSupport(),
675
+ isTouchIE = isTouchSupportIE();
676
+
677
+ if (this.settings.mouseDrag){
678
+ this.$stage.on('mousedown', $.proxy(function(event) { this.eventsRouter(event) }, this));
679
+ this.$stage.on('dragstart', function() { return false });
680
+ this.$stage.get(0).onselectstart = function() { return false };
681
+ } else {
682
+ this.$element.addClass('owl-text-select-on');
683
+ }
684
+
685
+ if (this.settings.touchDrag && !isTouchIE){
686
+ this.$stage.on('touchstart touchcancel', $.proxy(function(event) { this.eventsRouter(event) }, this));
687
+ }
688
+
689
+ // catch transitionEnd event
690
+ if (this.transitionEndVendor) {
691
+ this.on(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd, false);
692
+ }
693
+
694
+ // responsive
695
+ if (this.settings.responsive !== false) {
696
+ this.on(window, 'resize', $.proxy(this.onThrottledResize, this));
697
+ }
698
+ };
699
+
700
+ /**
701
+ * Handles touchstart/mousedown event.
702
+ * @protected
703
+ * @param {Event} event - The event arguments.
704
+ */
705
+ Owl.prototype.onDragStart = function(event) {
706
+ var ev, isTouchEvent, pageX, pageY, animatedPos;
707
+
708
+ ev = event.originalEvent || event || window.event;
709
+
710
+ // prevent right click
711
+ if (ev.which === 3 || this.state.isTouch) {
712
+ return false;
713
+ }
714
+
715
+ if (ev.type === 'mousedown') {
716
+ this.$stage.addClass('owl-grab');
717
+ }
718
+
719
+ this.trigger('drag');
720
+ this.drag.startTime = new Date().getTime();
721
+ this.speed(0);
722
+ this.state.isTouch = true;
723
+ this.state.isScrolling = false;
724
+ this.state.isSwiping = false;
725
+ this.drag.distance = 0;
726
+
727
+ pageX = getTouches(ev).x;
728
+ pageY = getTouches(ev).y;
729
+
730
+ // get stage position left
731
+ this.drag.offsetX = this.$stage.position().left;
732
+ this.drag.offsetY = this.$stage.position().top;
733
+
734
+ if (this.settings.rtl) {
735
+ this.drag.offsetX = this.$stage.position().left + this.$stage.width() - this.width()
736
+ + this.settings.margin;
737
+ }
738
+
739
+ // catch position // ie to fix
740
+ if (this.state.inMotion && this.support3d) {
741
+ animatedPos = this.getTransformProperty();
742
+ this.drag.offsetX = animatedPos;
743
+ this.animate(animatedPos);
744
+ this.state.inMotion = true;
745
+ } else if (this.state.inMotion && !this.support3d) {
746
+ this.state.inMotion = false;
747
+ return false;
748
+ }
749
+
750
+ this.drag.startX = pageX - this.drag.offsetX;
751
+ this.drag.startY = pageY - this.drag.offsetY;
752
+
753
+ this.drag.start = pageX - this.drag.startX;
754
+ this.drag.targetEl = ev.target || ev.srcElement;
755
+ this.drag.updatedX = this.drag.start;
756
+
757
+ // to do/check
758
+ // prevent links and images dragging;
759
+ if (this.drag.targetEl.tagName === "IMG" || this.drag.targetEl.tagName === "A") {
760
+ this.drag.targetEl.draggable = false;
761
+ }
762
+
763
+ $(document).on('mousemove.owl.dragEvents mouseup.owl.dragEvents touchmove.owl.dragEvents touchend.owl.dragEvents', $.proxy(function(event) {this.eventsRouter(event)},this));
764
+ };
765
+
766
+ /**
767
+ * Handles the touchmove/mousemove events.
768
+ * @todo Simplify
769
+ * @protected
770
+ * @param {Event} event - The event arguments.
771
+ */
772
+ Owl.prototype.onDragMove = function(event) {
773
+ var ev, isTouchEvent, pageX, pageY, minValue, maxValue, pull;
774
+
775
+ if (!this.state.isTouch) {
776
+ return;
777
+ }
778
+
779
+ if (this.state.isScrolling) {
780
+ return;
781
+ }
782
+
783
+ ev = event.originalEvent || event || window.event;
784
+
785
+ pageX = getTouches(ev).x;
786
+ pageY = getTouches(ev).y;
787
+
788
+ // Drag Direction
789
+ this.drag.currentX = pageX - this.drag.startX;
790
+ this.drag.currentY = pageY - this.drag.startY;
791
+ this.drag.distance = this.drag.currentX - this.drag.offsetX;
792
+
793
+ // Check move direction
794
+ if (this.drag.distance < 0) {
795
+ this.state.direction = this.settings.rtl ? 'right' : 'left';
796
+ } else if (this.drag.distance > 0) {
797
+ this.state.direction = this.settings.rtl ? 'left' : 'right';
798
+ }
799
+ // Loop
800
+ if (this.settings.loop) {
801
+ if (this.op(this.drag.currentX, '>', this.coordinates(this.minimum())) && this.state.direction === 'right') {
802
+ this.drag.currentX -= (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length);
803
+ } else if (this.op(this.drag.currentX, '<', this.coordinates(this.maximum())) && this.state.direction === 'left') {
804
+ this.drag.currentX += (this.settings.center && this.coordinates(0)) - this.coordinates(this._items.length);
805
+ }
806
+ } else {
807
+ // pull
808
+ minValue = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
809
+ maxValue = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
810
+ pull = this.settings.pullDrag ? this.drag.distance / 5 : 0;
811
+ this.drag.currentX = Math.max(Math.min(this.drag.currentX, minValue + pull), maxValue + pull);
812
+ }
813
+
814
+ // Lock browser if swiping horizontal
815
+
816
+ if ((this.drag.distance > 8 || this.drag.distance < -8)) {
817
+ if (ev.preventDefault !== undefined) {
818
+ ev.preventDefault();
819
+ } else {
820
+ ev.returnValue = false;
821
+ }
822
+ this.state.isSwiping = true;
823
+ }
824
+
825
+ this.drag.updatedX = this.drag.currentX;
826
+
827
+ // Lock Owl if scrolling
828
+ if ((this.drag.currentY > 16 || this.drag.currentY < -16) && this.state.isSwiping === false) {
829
+ this.state.isScrolling = true;
830
+ this.drag.updatedX = this.drag.start;
831
+ }
832
+
833
+ this.animate(this.drag.updatedX);
834
+ };
835
+
836
+ /**
837
+ * Handles the touchend/mouseup events.
838
+ * @protected
839
+ */
840
+ Owl.prototype.onDragEnd = function(event) {
841
+ var compareTimes, distanceAbs, closest;
842
+
843
+ if (!this.state.isTouch) {
844
+ return;
845
+ }
846
+
847
+ if (event.type === 'mouseup') {
848
+ this.$stage.removeClass('owl-grab');
849
+ }
850
+
851
+ this.trigger('dragged');
852
+
853
+ // prevent links and images dragging;
854
+ this.drag.targetEl.removeAttribute("draggable");
855
+
856
+ // remove drag event listeners
857
+
858
+ this.state.isTouch = false;
859
+ this.state.isScrolling = false;
860
+ this.state.isSwiping = false;
861
+
862
+ // to check
863
+ if (this.drag.distance === 0 && this.state.inMotion !== true) {
864
+ this.state.inMotion = false;
865
+ return false;
866
+ }
867
+
868
+ // prevent clicks while scrolling
869
+
870
+ this.drag.endTime = new Date().getTime();
871
+ compareTimes = this.drag.endTime - this.drag.startTime;
872
+ distanceAbs = Math.abs(this.drag.distance);
873
+
874
+ // to test
875
+ if (distanceAbs > 3 || compareTimes > 300) {
876
+ this.removeClick(this.drag.targetEl);
877
+ }
878
+
879
+ closest = this.closest(this.drag.updatedX);
880
+
881
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
882
+ this.current(closest);
883
+ this.invalidate('position');
884
+ this.update();
885
+
886
+ // if pullDrag is off then fire transitionEnd event manually when stick
887
+ // to border
888
+ if (!this.settings.pullDrag && this.drag.updatedX === this.coordinates(closest)) {
889
+ this.transitionEnd();
890
+ }
891
+
892
+ this.drag.distance = 0;
893
+
894
+ $(document).off('.owl.dragEvents');
895
+ };
896
+
897
+ /**
898
+ * Attaches `preventClick` to disable link while swipping.
899
+ * @protected
900
+ * @param {HTMLElement} [target] - The target of the `click` event.
901
+ */
902
+ Owl.prototype.removeClick = function(target) {
903
+ this.drag.targetEl = target;
904
+ $(target).on('click.preventClick', this.e._preventClick);
905
+ // to make sure click is removed:
906
+ window.setTimeout(function() {
907
+ $(target).off('click.preventClick');
908
+ }, 300);
909
+ };
910
+
911
+ /**
912
+ * Suppresses click event.
913
+ * @protected
914
+ * @param {Event} ev - The event arguments.
915
+ */
916
+ Owl.prototype.preventClick = function(ev) {
917
+ if (ev.preventDefault) {
918
+ ev.preventDefault();
919
+ } else {
920
+ ev.returnValue = false;
921
+ }
922
+ if (ev.stopPropagation) {
923
+ ev.stopPropagation();
924
+ }
925
+ $(ev.target).off('click.preventClick');
926
+ };
927
+
928
+ /**
929
+ * Catches stage position while animate (only CSS3).
930
+ * @protected
931
+ * @returns
932
+ */
933
+ Owl.prototype.getTransformProperty = function() {
934
+ var transform, matrix3d;
935
+
936
+ transform = window.getComputedStyle(this.$stage.get(0), null).getPropertyValue(this.vendorName + 'transform');
937
+ // var transform = this.$stage.css(this.vendorName + 'transform')
938
+ transform = transform.replace(/matrix(3d)?\(|\)/g, '').split(',');
939
+ matrix3d = transform.length === 16;
940
+
941
+ return matrix3d !== true ? transform[4] : transform[12];
942
+ };
943
+
944
+ /**
945
+ * Gets absolute position of the closest item for a coordinate.
946
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
947
+ * @protected
948
+ * @param {Number} coordinate - The coordinate in pixel.
949
+ * @return {Number} - The absolute position of the closest item.
950
+ */
951
+ Owl.prototype.closest = function(coordinate) {
952
+ var position = -1, pull = 30, width = this.width(), coordinates = this.coordinates();
953
+
954
+ if (!this.settings.freeDrag) {
955
+ // check closest item
956
+ $.each(coordinates, $.proxy(function(index, value) {
957
+ if (coordinate > value - pull && coordinate < value + pull) {
958
+ position = index;
959
+ } else if (this.op(coordinate, '<', value)
960
+ && this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
961
+ position = this.state.direction === 'left' ? index + 1 : index;
962
+ }
963
+ return position === -1;
964
+ }, this));
965
+ }
966
+
967
+ if (!this.settings.loop) {
968
+ // non loop boundries
969
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
970
+ position = coordinate = this.minimum();
971
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
972
+ position = coordinate = this.maximum();
973
+ }
974
+ }
975
+
976
+ return position;
977
+ };
978
+
979
+ /**
980
+ * Animates the stage.
981
+ * @public
982
+ * @param {Number} coordinate - The coordinate in pixels.
983
+ */
984
+ Owl.prototype.animate = function(coordinate) {
985
+ this.trigger('translate');
986
+ this.state.inMotion = this.speed() > 0;
987
+
988
+ if (this.support3d) {
989
+ this.$stage.css({
990
+ transform: 'translate3d(' + coordinate + 'px' + ',0px, 0px)',
991
+ transition: (this.speed() / 1000) + 's'
992
+ });
993
+ } else if (this.state.isTouch) {
994
+ this.$stage.css({
995
+ left: coordinate + 'px'
996
+ });
997
+ } else {
998
+ this.$stage.animate({
999
+ left: coordinate
1000
+ }, this.speed() / 1000, this.settings.fallbackEasing, $.proxy(function() {
1001
+ if (this.state.inMotion) {
1002
+ this.transitionEnd();
1003
+ }
1004
+ }, this));
1005
+ }
1006
+ };
1007
+
1008
+ /**
1009
+ * Sets the absolute position of the current item.
1010
+ * @public
1011
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
1012
+ * @returns {Number} - The absolute position of the current item.
1013
+ */
1014
+ Owl.prototype.current = function(position) {
1015
+ if (position === undefined) {
1016
+ return this._current;
1017
+ }
1018
+
1019
+ if (this._items.length === 0) {
1020
+ return undefined;
1021
+ }
1022
+
1023
+ position = this.normalize(position);
1024
+
1025
+ if (this._current !== position) {
1026
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
1027
+
1028
+ if (event.data !== undefined) {
1029
+ position = this.normalize(event.data);
1030
+ }
1031
+
1032
+ this._current = position;
1033
+
1034
+ this.invalidate('position');
1035
+
1036
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
1037
+ }
1038
+
1039
+ return this._current;
1040
+ };
1041
+
1042
+ /**
1043
+ * Invalidates the given part of the update routine.
1044
+ * @param {String} part - The part to invalidate.
1045
+ */
1046
+ Owl.prototype.invalidate = function(part) {
1047
+ this._invalidated[part] = true;
1048
+ }
1049
+
1050
+ /**
1051
+ * Resets the absolute position of the current item.
1052
+ * @public
1053
+ * @param {Number} position - The absolute position of the new item.
1054
+ */
1055
+ Owl.prototype.reset = function(position) {
1056
+ position = this.normalize(position);
1057
+
1058
+ if (position === undefined) {
1059
+ return;
1060
+ }
1061
+
1062
+ this._speed = 0;
1063
+ this._current = position;
1064
+
1065
+ this.suppress([ 'translate', 'translated' ]);
1066
+
1067
+ this.animate(this.coordinates(position));
1068
+
1069
+ this.release([ 'translate', 'translated' ]);
1070
+ };
1071
+
1072
+ /**
1073
+ * Normalizes an absolute or a relative position for an item.
1074
+ * @public
1075
+ * @param {Number} position - The absolute or relative position to normalize.
1076
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
1077
+ * @returns {Number} - The normalized position.
1078
+ */
1079
+ Owl.prototype.normalize = function(position, relative) {
1080
+ var n = (relative ? this._items.length : this._items.length + this._clones.length);
1081
+
1082
+ if (!$.isNumeric(position) || n < 1) {
1083
+ return undefined;
1084
+ }
1085
+
1086
+ if (this._clones.length) {
1087
+ position = ((position % n) + n) % n;
1088
+ } else {
1089
+ position = Math.max(this.minimum(relative), Math.min(this.maximum(relative), position));
1090
+ }
1091
+
1092
+ return position;
1093
+ };
1094
+
1095
+ /**
1096
+ * Converts an absolute position for an item into a relative position.
1097
+ * @public
1098
+ * @param {Number} position - The absolute position to convert.
1099
+ * @returns {Number} - The converted position.
1100
+ */
1101
+ Owl.prototype.relative = function(position) {
1102
+ position = this.normalize(position);
1103
+ position = position - this._clones.length / 2;
1104
+ return this.normalize(position, true);
1105
+ };
1106
+
1107
+ /**
1108
+ * Gets the maximum position for an item.
1109
+ * @public
1110
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1111
+ * @returns {Number}
1112
+ */
1113
+ Owl.prototype.maximum = function(relative) {
1114
+ var maximum, width, i = 0, coordinate,
1115
+ settings = this.settings;
1116
+
1117
+ if (relative) {
1118
+ return this._items.length - 1;
1119
+ }
1120
+
1121
+ if (!settings.loop && settings.center) {
1122
+ maximum = this._items.length - 1;
1123
+ } else if (!settings.loop && !settings.center) {
1124
+ maximum = this._items.length - settings.items;
1125
+ } else if (settings.loop || settings.center) {
1126
+ maximum = this._items.length + settings.items;
1127
+ } else if (settings.autoWidth || settings.merge) {
1128
+ revert = settings.rtl ? 1 : -1;
1129
+ width = this.$stage.width() - this.$element.width();
1130
+ while (coordinate = this.coordinates(i)) {
1131
+ if (coordinate * revert >= width) {
1132
+ break;
1133
+ }
1134
+ maximum = ++i;
1135
+ }
1136
+ } else {
1137
+ throw 'Can not detect maximum absolute position.'
1138
+ }
1139
+
1140
+ return maximum;
1141
+ };
1142
+
1143
+ /**
1144
+ * Gets the minimum position for an item.
1145
+ * @public
1146
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1147
+ * @returns {Number}
1148
+ */
1149
+ Owl.prototype.minimum = function(relative) {
1150
+ if (relative) {
1151
+ return 0;
1152
+ }
1153
+
1154
+ return this._clones.length / 2;
1155
+ };
1156
+
1157
+ /**
1158
+ * Gets an item at the specified relative position.
1159
+ * @public
1160
+ * @param {Number} [position] - The relative position of the item.
1161
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1162
+ */
1163
+ Owl.prototype.items = function(position) {
1164
+ if (position === undefined) {
1165
+ return this._items.slice();
1166
+ }
1167
+
1168
+ position = this.normalize(position, true);
1169
+ return this._items[position];
1170
+ };
1171
+
1172
+ /**
1173
+ * Gets an item at the specified relative position.
1174
+ * @public
1175
+ * @param {Number} [position] - The relative position of the item.
1176
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1177
+ */
1178
+ Owl.prototype.mergers = function(position) {
1179
+ if (position === undefined) {
1180
+ return this._mergers.slice();
1181
+ }
1182
+
1183
+ position = this.normalize(position, true);
1184
+ return this._mergers[position];
1185
+ };
1186
+
1187
+ /**
1188
+ * Gets the absolute positions of clones for an item.
1189
+ * @public
1190
+ * @param {Number} [position] - The relative position of the item.
1191
+ * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
1192
+ */
1193
+ Owl.prototype.clones = function(position) {
1194
+ var odd = this._clones.length / 2,
1195
+ even = odd + this._items.length,
1196
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
1197
+
1198
+ if (position === undefined) {
1199
+ return $.map(this._clones, function(v, i) { return map(i) });
1200
+ }
1201
+
1202
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
1203
+ };
1204
+
1205
+ /**
1206
+ * Sets the current animation speed.
1207
+ * @public
1208
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
1209
+ * @returns {Number} - The current animation speed in milliseconds.
1210
+ */
1211
+ Owl.prototype.speed = function(speed) {
1212
+ if (speed !== undefined) {
1213
+ this._speed = speed;
1214
+ }
1215
+
1216
+ return this._speed;
1217
+ };
1218
+
1219
+ /**
1220
+ * Gets the coordinate of an item.
1221
+ * @todo The name of this method is missleanding.
1222
+ * @public
1223
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
1224
+ * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
1225
+ */
1226
+ Owl.prototype.coordinates = function(position) {
1227
+ var coordinate = null;
1228
+
1229
+ if (position === undefined) {
1230
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
1231
+ return this.coordinates(index);
1232
+ }, this));
1233
+ }
1234
+
1235
+ if (this.settings.center) {
1236
+ coordinate = this._coordinates[position];
1237
+ coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
1238
+ } else {
1239
+ coordinate = this._coordinates[position - 1] || 0;
1240
+ }
1241
+
1242
+ return coordinate;
1243
+ };
1244
+
1245
+ /**
1246
+ * Calculates the speed for a translation.
1247
+ * @protected
1248
+ * @param {Number} from - The absolute position of the start item.
1249
+ * @param {Number} to - The absolute position of the target item.
1250
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
1251
+ * @returns {Number} - The time in milliseconds for the translation.
1252
+ */
1253
+ Owl.prototype.duration = function(from, to, factor) {
1254
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
1255
+ };
1256
+
1257
+ /**
1258
+ * Slides to the specified item.
1259
+ * @public
1260
+ * @param {Number} position - The position of the item.
1261
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1262
+ */
1263
+ Owl.prototype.to = function(position, speed) {
1264
+ if (this.settings.loop) {
1265
+ var distance = position - this.relative(this.current()),
1266
+ revert = this.current(),
1267
+ before = this.current(),
1268
+ after = this.current() + distance,
1269
+ direction = before - after < 0 ? true : false,
1270
+ items = this._clones.length + this._items.length;
1271
+
1272
+ if (after < this.settings.items && direction === false) {
1273
+ revert = before + this._items.length;
1274
+ this.reset(revert);
1275
+ } else if (after >= items - this.settings.items && direction === true) {
1276
+ revert = before - this._items.length;
1277
+ this.reset(revert);
1278
+ }
1279
+ window.clearTimeout(this.e._goToLoop);
1280
+ this.e._goToLoop = window.setTimeout($.proxy(function() {
1281
+ this.speed(this.duration(this.current(), revert + distance, speed));
1282
+ this.current(revert + distance);
1283
+ this.update();
1284
+ }, this), 30);
1285
+ } else {
1286
+ this.speed(this.duration(this.current(), position, speed));
1287
+ this.current(position);
1288
+ this.update();
1289
+ }
1290
+ };
1291
+
1292
+ /**
1293
+ * Slides to the next item.
1294
+ * @public
1295
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1296
+ */
1297
+ Owl.prototype.next = function(speed) {
1298
+ speed = speed || false;
1299
+ this.to(this.relative(this.current()) + 1, speed);
1300
+ };
1301
+
1302
+ /**
1303
+ * Slides to the previous item.
1304
+ * @public
1305
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1306
+ */
1307
+ Owl.prototype.prev = function(speed) {
1308
+ speed = speed || false;
1309
+ this.to(this.relative(this.current()) - 1, speed);
1310
+ };
1311
+
1312
+ /**
1313
+ * Handles the end of an animation.
1314
+ * @protected
1315
+ * @param {Event} event - The event arguments.
1316
+ */
1317
+ Owl.prototype.transitionEnd = function(event) {
1318
+
1319
+ // if css2 animation then event object is undefined
1320
+ if (event !== undefined) {
1321
+ event.stopPropagation();
1322
+
1323
+ // Catch only owl-stage transitionEnd event
1324
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
1325
+ return false;
1326
+ }
1327
+ }
1328
+
1329
+ this.state.inMotion = false;
1330
+ this.trigger('translated');
1331
+ };
1332
+
1333
+ /**
1334
+ * Gets viewport width.
1335
+ * @protected
1336
+ * @return {Number} - The width in pixel.
1337
+ */
1338
+ Owl.prototype.viewport = function() {
1339
+ var width;
1340
+ if (this.options.responsiveBaseElement !== window) {
1341
+ width = $(this.options.responsiveBaseElement).width();
1342
+ } else if (window.innerWidth) {
1343
+ width = window.innerWidth;
1344
+ } else if (document.documentElement && document.documentElement.clientWidth) {
1345
+ width = document.documentElement.clientWidth;
1346
+ } else {
1347
+ throw 'Can not detect viewport width.';
1348
+ }
1349
+ return width;
1350
+ };
1351
+
1352
+ /**
1353
+ * Replaces the current content.
1354
+ * @public
1355
+ * @param {HTMLElement|jQuery|String} content - The new content.
1356
+ */
1357
+ Owl.prototype.replace = function(content) {
1358
+ this.$stage.empty();
1359
+ this._items = [];
1360
+
1361
+ if (content) {
1362
+ content = (content instanceof jQuery) ? content : $(content);
1363
+ }
1364
+
1365
+ if (this.settings.nestedItemSelector) {
1366
+ content = content.find('.' + this.settings.nestedItemSelector);
1367
+ }
1368
+
1369
+ content.filter(function() {
1370
+ return this.nodeType === 1;
1371
+ }).each($.proxy(function(index, item) {
1372
+ item = this.prepare(item);
1373
+ this.$stage.append(item);
1374
+ this._items.push(item);
1375
+ this._mergers.push(item.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
1376
+ }, this));
1377
+
1378
+ this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
1379
+
1380
+ this.invalidate('items');
1381
+ };
1382
+
1383
+ /**
1384
+ * Adds an item.
1385
+ * @todo Use `item` instead of `content` for the event arguments.
1386
+ * @public
1387
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
1388
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
1389
+ */
1390
+ Owl.prototype.add = function(content, position) {
1391
+ position = position === undefined ? this._items.length : this.normalize(position, true);
1392
+
1393
+ this.trigger('add', { content: content, position: position });
1394
+
1395
+ if (this._items.length === 0 || position === this._items.length) {
1396
+ this.$stage.append(content);
1397
+ this._items.push(content);
1398
+ this._mergers.push(content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
1399
+ } else {
1400
+ this._items[position].before(content);
1401
+ this._items.splice(position, 0, content);
1402
+ this._mergers.splice(position, 0, content.find('[data-merge]').andSelf('[data-merge]').attr('data-merge') * 1 || 1);
1403
+ }
1404
+
1405
+ this.invalidate('items');
1406
+
1407
+ this.trigger('added', { content: content, position: position });
1408
+ };
1409
+
1410
+ /**
1411
+ * Removes an item by its position.
1412
+ * @todo Use `item` instead of `content` for the event arguments.
1413
+ * @public
1414
+ * @param {Number} position - The relative position of the item to remove.
1415
+ */
1416
+ Owl.prototype.remove = function(position) {
1417
+ position = this.normalize(position, true);
1418
+
1419
+ if (position === undefined) {
1420
+ return;
1421
+ }
1422
+
1423
+ this.trigger('remove', { content: this._items[position], position: position });
1424
+
1425
+ this._items[position].remove();
1426
+ this._items.splice(position, 1);
1427
+ this._mergers.splice(position, 1);
1428
+
1429
+ this.invalidate('items');
1430
+
1431
+ this.trigger('removed', { content: null, position: position });
1432
+ };
1433
+
1434
+ /**
1435
+ * Adds triggerable events.
1436
+ * @protected
1437
+ */
1438
+ Owl.prototype.addTriggerableEvents = function() {
1439
+ var handler = $.proxy(function(callback, event) {
1440
+ return $.proxy(function(e) {
1441
+ if (e.relatedTarget !== this) {
1442
+ this.suppress([ event ]);
1443
+ callback.apply(this, [].slice.call(arguments, 1));
1444
+ this.release([ event ]);
1445
+ }
1446
+ }, this);
1447
+ }, this);
1448
+
1449
+ $.each({
1450
+ 'next': this.next,
1451
+ 'prev': this.prev,
1452
+ 'to': this.to,
1453
+ 'destroy': this.destroy,
1454
+ 'refresh': this.refresh,
1455
+ 'replace': this.replace,
1456
+ 'add': this.add,
1457
+ 'remove': this.remove
1458
+ }, $.proxy(function(event, callback) {
1459
+ this.$element.on(event + '.owl.carousel', handler(callback, event + '.owl.carousel'));
1460
+ }, this));
1461
+
1462
+ };
1463
+
1464
+ /**
1465
+ * Watches the visibility of the carousel element.
1466
+ * @protected
1467
+ */
1468
+ Owl.prototype.watchVisibility = function() {
1469
+
1470
+ // test on zepto
1471
+ if (!isElVisible(this.$element.get(0))) {
1472
+ this.$element.addClass('owl-hidden');
1473
+ window.clearInterval(this.e._checkVisibile);
1474
+ this.e._checkVisibile = window.setInterval($.proxy(checkVisible, this), 500);
1475
+ }
1476
+
1477
+ function isElVisible(el) {
1478
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
1479
+ }
1480
+
1481
+ function checkVisible() {
1482
+ if (isElVisible(this.$element.get(0))) {
1483
+ this.$element.removeClass('owl-hidden');
1484
+ this.refresh();
1485
+ window.clearInterval(this.e._checkVisibile);
1486
+ }
1487
+ }
1488
+ };
1489
+
1490
+ /**
1491
+ * Preloads images with auto width.
1492
+ * @protected
1493
+ * @todo Still to test
1494
+ */
1495
+ Owl.prototype.preloadAutoWidthImages = function(imgs) {
1496
+ var loaded, that, $el, img;
1497
+
1498
+ loaded = 0;
1499
+ that = this;
1500
+ imgs.each(function(i, el) {
1501
+ $el = $(el);
1502
+ img = new Image();
1503
+
1504
+ img.onload = function() {
1505
+ loaded++;
1506
+ $el.attr('src', img.src);
1507
+ $el.css('opacity', 1);
1508
+ if (loaded >= imgs.length) {
1509
+ that.state.imagesLoaded = true;
1510
+ that.initialize();
1511
+ }
1512
+ };
1513
+
1514
+ img.src = $el.attr('src') || $el.attr('data-src') || $el.attr('data-src-retina');
1515
+ });
1516
+ };
1517
+
1518
+ /**
1519
+ * Destroys the carousel.
1520
+ * @public
1521
+ */
1522
+ Owl.prototype.destroy = function() {
1523
+
1524
+ if (this.$element.hasClass(this.settings.themeClass)) {
1525
+ this.$element.removeClass(this.settings.themeClass);
1526
+ }
1527
+
1528
+ if (this.settings.responsive !== false) {
1529
+ $(window).off('resize.owl.carousel');
1530
+ }
1531
+
1532
+ if (this.transitionEndVendor) {
1533
+ this.off(this.$stage.get(0), this.transitionEndVendor, this.e._transitionEnd);
1534
+ }
1535
+
1536
+ for ( var i in this._plugins) {
1537
+ this._plugins[i].destroy();
1538
+ }
1539
+
1540
+ if (this.settings.mouseDrag || this.settings.touchDrag) {
1541
+ this.$stage.off('mousedown touchstart touchcancel');
1542
+ $(document).off('.owl.dragEvents');
1543
+ this.$stage.get(0).onselectstart = function() {};
1544
+ this.$stage.off('dragstart', function() { return false });
1545
+ }
1546
+
1547
+ // remove event handlers in the ".owl.carousel" namespace
1548
+ this.$element.off('.owl');
1549
+
1550
+ this.$stage.children('.cloned').remove();
1551
+ this.e = null;
1552
+ this.$element.removeData('owlCarousel');
1553
+
1554
+ this.$stage.children().contents().unwrap();
1555
+ this.$stage.children().unwrap();
1556
+ this.$stage.unwrap();
1557
+ };
1558
+
1559
+ /**
1560
+ * Operators to calculate right-to-left and left-to-right.
1561
+ * @protected
1562
+ * @param {Number} [a] - The left side operand.
1563
+ * @param {String} [o] - The operator.
1564
+ * @param {Number} [b] - The right side operand.
1565
+ */
1566
+ Owl.prototype.op = function(a, o, b) {
1567
+ var rtl = this.settings.rtl;
1568
+ switch (o) {
1569
+ case '<':
1570
+ return rtl ? a > b : a < b;
1571
+ case '>':
1572
+ return rtl ? a < b : a > b;
1573
+ case '>=':
1574
+ return rtl ? a <= b : a >= b;
1575
+ case '<=':
1576
+ return rtl ? a >= b : a <= b;
1577
+ default:
1578
+ break;
1579
+ }
1580
+ };
1581
+
1582
+ /**
1583
+ * Attaches to an internal event.
1584
+ * @protected
1585
+ * @param {HTMLElement} element - The event source.
1586
+ * @param {String} event - The event name.
1587
+ * @param {Function} listener - The event handler to attach.
1588
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
1589
+ */
1590
+ Owl.prototype.on = function(element, event, listener, capture) {
1591
+ if (element.addEventListener) {
1592
+ element.addEventListener(event, listener, capture);
1593
+ } else if (element.attachEvent) {
1594
+ element.attachEvent('on' + event, listener);
1595
+ }
1596
+ };
1597
+
1598
+ /**
1599
+ * Detaches from an internal event.
1600
+ * @protected
1601
+ * @param {HTMLElement} element - The event source.
1602
+ * @param {String} event - The event name.
1603
+ * @param {Function} listener - The attached event handler to detach.
1604
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
1605
+ */
1606
+ Owl.prototype.off = function(element, event, listener, capture) {
1607
+ if (element.removeEventListener) {
1608
+ element.removeEventListener(event, listener, capture);
1609
+ } else if (element.detachEvent) {
1610
+ element.detachEvent('on' + event, listener);
1611
+ }
1612
+ };
1613
+
1614
+ /**
1615
+ * Triggers an public event.
1616
+ * @protected
1617
+ * @param {String} name - The event name.
1618
+ * @param {*} [data=null] - The event data.
1619
+ * @param {String} [namespace=.owl.carousel] - The event namespace.
1620
+ * @returns {Event} - The event arguments.
1621
+ */
1622
+ Owl.prototype.trigger = function(name, data, namespace) {
1623
+ var status = {
1624
+ item: { count: this._items.length, index: this.current() }
1625
+ }, handler = $.camelCase(
1626
+ $.grep([ 'on', name, namespace ], function(v) { return v })
1627
+ .join('-').toLowerCase()
1628
+ ), event = $.Event(
1629
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
1630
+ $.extend({ relatedTarget: this }, status, data)
1631
+ );
1632
+
1633
+ if (!this._supress[name]) {
1634
+ $.each(this._plugins, function(name, plugin) {
1635
+ if (plugin.onTrigger) {
1636
+ plugin.onTrigger(event);
1637
+ }
1638
+ });
1639
+
1640
+ this.$element.trigger(event);
1641
+
1642
+ if (this.settings && typeof this.settings[handler] === 'function') {
1643
+ this.settings[handler].apply(this, event);
1644
+ }
1645
+ }
1646
+
1647
+ return event;
1648
+ };
1649
+
1650
+ /**
1651
+ * Suppresses events.
1652
+ * @protected
1653
+ * @param {Array.<String>} events - The events to suppress.
1654
+ */
1655
+ Owl.prototype.suppress = function(events) {
1656
+ $.each(events, $.proxy(function(index, event) {
1657
+ this._supress[event] = true;
1658
+ }, this));
1659
+ }
1660
+
1661
+ /**
1662
+ * Releases suppressed events.
1663
+ * @protected
1664
+ * @param {Array.<String>} events - The events to release.
1665
+ */
1666
+ Owl.prototype.release = function(events) {
1667
+ $.each(events, $.proxy(function(index, event) {
1668
+ delete this._supress[event];
1669
+ }, this));
1670
+ }
1671
+
1672
+ /**
1673
+ * Checks the availability of some browser features.
1674
+ * @protected
1675
+ */
1676
+ Owl.prototype.browserSupport = function() {
1677
+ this.support3d = isPerspective();
1678
+
1679
+ if (this.support3d) {
1680
+ this.transformVendor = isTransform();
1681
+
1682
+ // take transitionend event name by detecting transition
1683
+ var endVendors = [ 'transitionend', 'webkitTransitionEnd', 'transitionend', 'oTransitionEnd' ];
1684
+ this.transitionEndVendor = endVendors[isTransition()];
1685
+
1686
+ // take vendor name from transform name
1687
+ this.vendorName = this.transformVendor.replace(/Transform/i, '');
1688
+ this.vendorName = this.vendorName !== '' ? '-' + this.vendorName.toLowerCase() + '-' : '';
1689
+ }
1690
+
1691
+ this.state.orientation = window.orientation;
1692
+ };
1693
+
1694
+ /**
1695
+ * Get touch/drag coordinats.
1696
+ * @private
1697
+ * @param {event} - mousedown/touchstart event
1698
+ * @returns {object} - Contains X and Y of current mouse/touch position
1699
+ */
1700
+
1701
+ function getTouches(event) {
1702
+ if (event.touches !== undefined) {
1703
+ return {
1704
+ x: event.touches[0].pageX,
1705
+ y: event.touches[0].pageY
1706
+ };
1707
+ }
1708
+
1709
+ if (event.touches === undefined) {
1710
+ if (event.pageX !== undefined) {
1711
+ return {
1712
+ x: event.pageX,
1713
+ y: event.pageY
1714
+ };
1715
+ }
1716
+
1717
+ if (event.pageX === undefined) {
1718
+ return {
1719
+ x: event.clientX,
1720
+ y: event.clientY
1721
+ };
1722
+ }
1723
+ }
1724
+ }
1725
+
1726
+ /**
1727
+ * Checks for CSS support.
1728
+ * @private
1729
+ * @param {Array} array - The CSS properties to check for.
1730
+ * @returns {Array} - Contains the supported CSS property name and its index or `false`.
1731
+ */
1732
+ function isStyleSupported(array) {
1733
+ var p, s, fake = document.createElement('div'), list = array;
1734
+ for (p in list) {
1735
+ s = list[p];
1736
+ if (typeof fake.style[s] !== 'undefined') {
1737
+ fake = null;
1738
+ return [ s, p ];
1739
+ }
1740
+ }
1741
+ return [ false ];
1742
+ }
1743
+
1744
+ /**
1745
+ * Checks for CSS transition support.
1746
+ * @private
1747
+ * @todo Realy bad design
1748
+ * @returns {Number}
1749
+ */
1750
+ function isTransition() {
1751
+ return isStyleSupported([ 'transition', 'WebkitTransition', 'MozTransition', 'OTransition' ])[1];
1752
+ }
1753
+
1754
+ /**
1755
+ * Checks for CSS transform support.
1756
+ * @private
1757
+ * @returns {String} The supported property name or false.
1758
+ */
1759
+ function isTransform() {
1760
+ return isStyleSupported([ 'transform', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ])[0];
1761
+ }
1762
+
1763
+ /**
1764
+ * Checks for CSS perspective support.
1765
+ * @private
1766
+ * @returns {String} The supported property name or false.
1767
+ */
1768
+ function isPerspective() {
1769
+ return isStyleSupported([ 'perspective', 'webkitPerspective', 'MozPerspective', 'OPerspective', 'MsPerspective' ])[0];
1770
+ }
1771
+
1772
+ /**
1773
+ * Checks wether touch is supported or not.
1774
+ * @private
1775
+ * @returns {Boolean}
1776
+ */
1777
+ function isTouchSupport() {
1778
+ return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);
1779
+ }
1780
+
1781
+ /**
1782
+ * Checks wether touch is supported or not for IE.
1783
+ * @private
1784
+ * @returns {Boolean}
1785
+ */
1786
+ function isTouchSupportIE() {
1787
+ return window.navigator.msPointerEnabled;
1788
+ }
1789
+
1790
+ /**
1791
+ * The jQuery Plugin for the Owl Carousel
1792
+ * @public
1793
+ */
1794
+ $.fn.owlCarousel = function(options) {
1795
+ return this.each(function() {
1796
+ if (!$(this).data('owlCarousel')) {
1797
+ $(this).data('owlCarousel', new Owl(this, options));
1798
+ }
1799
+ });
1800
+ };
1801
+
1802
+ /**
1803
+ * The constructor for the jQuery Plugin
1804
+ * @public
1805
+ */
1806
+ $.fn.owlCarousel.Constructor = Owl;
1807
+
1808
+ })(window.Zepto || window.jQuery, window, document);
1809
+
1810
+ /**
1811
+ * Lazy Plugin
1812
+ * @version 2.0.0
1813
+ * @author Bartosz Wojciechowski
1814
+ * @license The MIT License (MIT)
1815
+ */
1816
+ ;(function($, window, document, undefined) {
1817
+
1818
+ /**
1819
+ * Creates the lazy plugin.
1820
+ * @class The Lazy Plugin
1821
+ * @param {Owl} carousel - The Owl Carousel
1822
+ */
1823
+ var Lazy = function(carousel) {
1824
+
1825
+ /**
1826
+ * Reference to the core.
1827
+ * @protected
1828
+ * @type {Owl}
1829
+ */
1830
+ this._core = carousel;
1831
+
1832
+ /**
1833
+ * Already loaded items.
1834
+ * @protected
1835
+ * @type {Array.<jQuery>}
1836
+ */
1837
+ this._loaded = [];
1838
+
1839
+ /**
1840
+ * Event handlers.
1841
+ * @protected
1842
+ * @type {Object}
1843
+ */
1844
+ this._handlers = {
1845
+ 'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
1846
+ if (!e.namespace) {
1847
+ return;
1848
+ }
1849
+
1850
+ if (!this._core.settings || !this._core.settings.lazyLoad) {
1851
+ return;
1852
+ }
1853
+
1854
+ if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
1855
+ var settings = this._core.settings,
1856
+ n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
1857
+ i = ((settings.center && n * -1) || 0),
1858
+ position = ((e.property && e.property.value) || this._core.current()) + i,
1859
+ clones = this._core.clones().length,
1860
+ load = $.proxy(function(i, v) { this.load(v) }, this);
1861
+
1862
+ while (i++ < n) {
1863
+ this.load(clones / 2 + this._core.relative(position));
1864
+ clones && $.each(this._core.clones(this._core.relative(position++)), load);
1865
+ }
1866
+ }
1867
+ }, this)
1868
+ };
1869
+
1870
+ // set the default options
1871
+ this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
1872
+
1873
+ // register event handler
1874
+ this._core.$element.on(this._handlers);
1875
+ }
1876
+
1877
+ /**
1878
+ * Default options.
1879
+ * @public
1880
+ */
1881
+ Lazy.Defaults = {
1882
+ lazyLoad: false
1883
+ }
1884
+
1885
+ /**
1886
+ * Loads all resources of an item at the specified position.
1887
+ * @param {Number} position - The absolute position of the item.
1888
+ * @protected
1889
+ */
1890
+ Lazy.prototype.load = function(position) {
1891
+ var $item = this._core.$stage.children().eq(position),
1892
+ $elements = $item && $item.find('.owl-lazy');
1893
+
1894
+ if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
1895
+ return;
1896
+ }
1897
+
1898
+ $elements.each($.proxy(function(index, element) {
1899
+ var $element = $(element), image,
1900
+ url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
1901
+
1902
+ this._core.trigger('load', { element: $element, url: url }, 'lazy');
1903
+
1904
+ if ($element.is('img')) {
1905
+ $element.one('load.owl.lazy', $.proxy(function() {
1906
+ $element.css('opacity', 1);
1907
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
1908
+ }, this)).attr('src', url);
1909
+ } else {
1910
+ image = new Image();
1911
+ image.onload = $.proxy(function() {
1912
+ $element.css({
1913
+ 'background-image': 'url(' + url + ')',
1914
+ 'opacity': '1'
1915
+ });
1916
+ this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
1917
+ }, this);
1918
+ image.src = url;
1919
+ }
1920
+ }, this));
1921
+
1922
+ this._loaded.push($item.get(0));
1923
+ }
1924
+
1925
+ /**
1926
+ * Destroys the plugin.
1927
+ * @public
1928
+ */
1929
+ Lazy.prototype.destroy = function() {
1930
+ var handler, property;
1931
+
1932
+ for (handler in this.handlers) {
1933
+ this._core.$element.off(handler, this.handlers[handler]);
1934
+ }
1935
+ for (property in Object.getOwnPropertyNames(this)) {
1936
+ typeof this[property] != 'function' && (this[property] = null);
1937
+ }
1938
+ }
1939
+
1940
+ $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
1941
+
1942
+ })(window.Zepto || window.jQuery, window, document);
1943
+
1944
+ /**
1945
+ * AutoHeight Plugin
1946
+ * @version 2.0.0
1947
+ * @author Bartosz Wojciechowski
1948
+ * @license The MIT License (MIT)
1949
+ */
1950
+ ;(function($, window, document, undefined) {
1951
+
1952
+ /**
1953
+ * Creates the auto height plugin.
1954
+ * @class The Auto Height Plugin
1955
+ * @param {Owl} carousel - The Owl Carousel
1956
+ */
1957
+ var AutoHeight = function(carousel) {
1958
+ /**
1959
+ * Reference to the core.
1960
+ * @protected
1961
+ * @type {Owl}
1962
+ */
1963
+ this._core = carousel;
1964
+
1965
+ /**
1966
+ * All event handlers.
1967
+ * @protected
1968
+ * @type {Object}
1969
+ */
1970
+ this._handlers = {
1971
+ 'initialized.owl.carousel': $.proxy(function() {
1972
+ if (this._core.settings.autoHeight) {
1973
+ this.update();
1974
+ }
1975
+ }, this),
1976
+ 'changed.owl.carousel': $.proxy(function(e) {
1977
+ if (this._core.settings.autoHeight && e.property.name == 'position'){
1978
+ this.update();
1979
+ }
1980
+ }, this),
1981
+ 'loaded.owl.lazy': $.proxy(function(e) {
1982
+ if (this._core.settings.autoHeight && e.element.closest('.' + this._core.settings.itemClass)
1983
+ === this._core.$stage.children().eq(this._core.current())) {
1984
+ this.update();
1985
+ }
1986
+ }, this)
1987
+ };
1988
+
1989
+ // set default options
1990
+ this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
1991
+
1992
+ // register event handlers
1993
+ this._core.$element.on(this._handlers);
1994
+ };
1995
+
1996
+ /**
1997
+ * Default options.
1998
+ * @public
1999
+ */
2000
+ AutoHeight.Defaults = {
2001
+ autoHeight: false,
2002
+ autoHeightClass: 'owl-height'
2003
+ };
2004
+
2005
+ /**
2006
+ * Updates the view.
2007
+ */
2008
+ AutoHeight.prototype.update = function() {
2009
+ this._core.$stage.parent()
2010
+ .height(this._core.$stage.children().eq(this._core.current()).height())
2011
+ .addClass(this._core.settings.autoHeightClass);
2012
+ };
2013
+
2014
+ AutoHeight.prototype.destroy = function() {
2015
+ var handler, property;
2016
+
2017
+ for (handler in this._handlers) {
2018
+ this._core.$element.off(handler, this._handlers[handler]);
2019
+ }
2020
+ for (property in Object.getOwnPropertyNames(this)) {
2021
+ typeof this[property] != 'function' && (this[property] = null);
2022
+ }
2023
+ };
2024
+
2025
+ $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
2026
+
2027
+ })(window.Zepto || window.jQuery, window, document);
2028
+
2029
+ /**
2030
+ * Video Plugin
2031
+ * @version 2.0.0
2032
+ * @author Bartosz Wojciechowski
2033
+ * @license The MIT License (MIT)
2034
+ */
2035
+ ;(function($, window, document, undefined) {
2036
+
2037
+ /**
2038
+ * Creates the video plugin.
2039
+ * @class The Video Plugin
2040
+ * @param {Owl} carousel - The Owl Carousel
2041
+ */
2042
+ var Video = function(carousel) {
2043
+ /**
2044
+ * Reference to the core.
2045
+ * @protected
2046
+ * @type {Owl}
2047
+ */
2048
+ this._core = carousel;
2049
+
2050
+ /**
2051
+ * Cache all video URLs.
2052
+ * @protected
2053
+ * @type {Object}
2054
+ */
2055
+ this._videos = {};
2056
+
2057
+ /**
2058
+ * Current playing item.
2059
+ * @protected
2060
+ * @type {jQuery}
2061
+ */
2062
+ this._playing = null;
2063
+
2064
+ /**
2065
+ * Whether this is in fullscreen or not.
2066
+ * @protected
2067
+ * @type {Boolean}
2068
+ */
2069
+ this._fullscreen = false;
2070
+
2071
+ /**
2072
+ * All event handlers.
2073
+ * @protected
2074
+ * @type {Object}
2075
+ */
2076
+ this._handlers = {
2077
+ 'resize.owl.carousel': $.proxy(function(e) {
2078
+ if (this._core.settings.video && !this.isInFullScreen()) {
2079
+ e.preventDefault();
2080
+ }
2081
+ }, this),
2082
+ 'refresh.owl.carousel changed.owl.carousel': $.proxy(function(e) {
2083
+ if (this._playing) {
2084
+ this.stop();
2085
+ }
2086
+ }, this),
2087
+ 'prepared.owl.carousel': $.proxy(function(e) {
2088
+ var $element = $(e.content).find('.owl-video');
2089
+ if ($element.length) {
2090
+ $element.css('display', 'none');
2091
+ this.fetch($element, $(e.content));
2092
+ }
2093
+ }, this)
2094
+ };
2095
+
2096
+ // set default options
2097
+ this._core.options = $.extend({}, Video.Defaults, this._core.options);
2098
+
2099
+ // register event handlers
2100
+ this._core.$element.on(this._handlers);
2101
+
2102
+ this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
2103
+ this.play(e);
2104
+ }, this));
2105
+ };
2106
+
2107
+ /**
2108
+ * Default options.
2109
+ * @public
2110
+ */
2111
+ Video.Defaults = {
2112
+ video: false,
2113
+ videoHeight: false,
2114
+ videoWidth: false
2115
+ };
2116
+
2117
+ /**
2118
+ * Gets the video ID and the type (YouTube/Vimeo only).
2119
+ * @protected
2120
+ * @param {jQuery} target - The target containing the video data.
2121
+ * @param {jQuery} item - The item containing the video.
2122
+ */
2123
+ Video.prototype.fetch = function(target, item) {
2124
+
2125
+ var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
2126
+ id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
2127
+ width = target.attr('data-width') || this._core.settings.videoWidth,
2128
+ height = target.attr('data-height') || this._core.settings.videoHeight,
2129
+ url = target.attr('href');
2130
+
2131
+ if (url) {
2132
+ id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
2133
+
2134
+ if (id[3].indexOf('youtu') > -1) {
2135
+ type = 'youtube';
2136
+ } else if (id[3].indexOf('vimeo') > -1) {
2137
+ type = 'vimeo';
2138
+ } else {
2139
+ throw new Error('Video URL not supported.');
2140
+ }
2141
+ id = id[6];
2142
+ } else {
2143
+ throw new Error('Missing video URL.');
2144
+ }
2145
+
2146
+ this._videos[url] = {
2147
+ type: type,
2148
+ id: id,
2149
+ width: width,
2150
+ height: height
2151
+ };
2152
+
2153
+ item.attr('data-video', url);
2154
+
2155
+ this.thumbnail(target, this._videos[url]);
2156
+ };
2157
+
2158
+ /**
2159
+ * Creates video thumbnail.
2160
+ * @protected
2161
+ * @param {jQuery} target - The target containing the video data.
2162
+ * @param {Object} info - The video info object.
2163
+ * @see `fetch`
2164
+ */
2165
+ Video.prototype.thumbnail = function(target, video) {
2166
+
2167
+ var tnLink,
2168
+ icon,
2169
+ path,
2170
+ dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
2171
+ customTn = target.find('img'),
2172
+ srcType = 'src',
2173
+ lazyClass = '',
2174
+ settings = this._core.settings,
2175
+ create = function(path) {
2176
+ icon = '<div class="owl-video-play-icon"></div>';
2177
+
2178
+ if (settings.lazyLoad) {
2179
+ tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
2180
+ } else {
2181
+ tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
2182
+ }
2183
+ target.after(tnLink);
2184
+ target.after(icon);
2185
+ };
2186
+
2187
+ // wrap video content into owl-video-wrapper div
2188
+ target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
2189
+
2190
+ if (this._core.settings.lazyLoad) {
2191
+ srcType = 'data-src';
2192
+ lazyClass = 'owl-lazy';
2193
+ }
2194
+
2195
+ // custom thumbnail
2196
+ if (customTn.length) {
2197
+ create(customTn.attr(srcType));
2198
+ customTn.remove();
2199
+ return false;
2200
+ }
2201
+
2202
+ if (video.type === 'youtube') {
2203
+ path = "http://img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
2204
+ create(path);
2205
+ } else if (video.type === 'vimeo') {
2206
+ $.ajax({
2207
+ type: 'GET',
2208
+ url: 'http://vimeo.com/api/v2/video/' + video.id + '.json',
2209
+ jsonp: 'callback',
2210
+ dataType: 'jsonp',
2211
+ success: function(data) {
2212
+ path = data[0].thumbnail_large;
2213
+ create(path);
2214
+ }
2215
+ });
2216
+ }
2217
+ };
2218
+
2219
+ /**
2220
+ * Stops the current video.
2221
+ * @public
2222
+ */
2223
+ Video.prototype.stop = function() {
2224
+ this._core.trigger('stop', null, 'video');
2225
+ this._playing.find('.owl-video-frame').remove();
2226
+ this._playing.removeClass('owl-video-playing');
2227
+ this._playing = null;
2228
+ };
2229
+
2230
+ /**
2231
+ * Starts the current video.
2232
+ * @public
2233
+ * @param {Event} ev - The event arguments.
2234
+ */
2235
+ Video.prototype.play = function(ev) {
2236
+ this._core.trigger('play', null, 'video');
2237
+
2238
+ if (this._playing) {
2239
+ this.stop();
2240
+ }
2241
+
2242
+ var target = $(ev.target || ev.srcElement),
2243
+ item = target.closest('.' + this._core.settings.itemClass),
2244
+ video = this._videos[item.attr('data-video')],
2245
+ width = video.width || '100%',
2246
+ height = video.height || this._core.$stage.height(),
2247
+ html, wrap;
2248
+
2249
+ if (video.type === 'youtube') {
2250
+ html = '<iframe width="' + width + '" height="' + height + '" src="http://www.youtube.com/embed/'
2251
+ + video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
2252
+ } else if (video.type === 'vimeo') {
2253
+ html = '<iframe src="http://player.vimeo.com/video/' + video.id + '?autoplay=1" width="' + width
2254
+ + '" height="' + height
2255
+ + '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
2256
+ }
2257
+
2258
+ item.addClass('owl-video-playing');
2259
+ this._playing = item;
2260
+
2261
+ wrap = $('<div style="height:' + height + 'px; width:' + width + 'px" class="owl-video-frame">'
2262
+ + html + '</div>');
2263
+ target.after(wrap);
2264
+ };
2265
+
2266
+ /**
2267
+ * Checks whether an video is currently in full screen mode or not.
2268
+ * @todo Bad style because looks like a readonly method but changes members.
2269
+ * @protected
2270
+ * @returns {Boolean}
2271
+ */
2272
+ Video.prototype.isInFullScreen = function() {
2273
+
2274
+ // if Vimeo Fullscreen mode
2275
+ var element = document.fullscreenElement || document.mozFullScreenElement
2276
+ || document.webkitFullscreenElement;
2277
+
2278
+ if (element && $(element).parent().hasClass('owl-video-frame')) {
2279
+ this._core.speed(0);
2280
+ this._fullscreen = true;
2281
+ }
2282
+
2283
+ if (element && this._fullscreen && this._playing) {
2284
+ return false;
2285
+ }
2286
+
2287
+ // comming back from fullscreen
2288
+ if (this._fullscreen) {
2289
+ this._fullscreen = false;
2290
+ return false;
2291
+ }
2292
+
2293
+ // check full screen mode and window orientation
2294
+ if (this._playing) {
2295
+ if (this._core.state.orientation !== window.orientation) {
2296
+ this._core.state.orientation = window.orientation;
2297
+ return false;
2298
+ }
2299
+ }
2300
+
2301
+ return true;
2302
+ };
2303
+
2304
+ /**
2305
+ * Destroys the plugin.
2306
+ */
2307
+ Video.prototype.destroy = function() {
2308
+ var handler, property;
2309
+
2310
+ this._core.$element.off('click.owl.video');
2311
+
2312
+ for (handler in this._handlers) {
2313
+ this._core.$element.off(handler, this._handlers[handler]);
2314
+ }
2315
+ for (property in Object.getOwnPropertyNames(this)) {
2316
+ typeof this[property] != 'function' && (this[property] = null);
2317
+ }
2318
+ };
2319
+
2320
+ $.fn.owlCarousel.Constructor.Plugins.Video = Video;
2321
+
2322
+ })(window.Zepto || window.jQuery, window, document);
2323
+
2324
+ /**
2325
+ * Animate Plugin
2326
+ * @version 2.0.0
2327
+ * @author Bartosz Wojciechowski
2328
+ * @license The MIT License (MIT)
2329
+ */
2330
+ ;(function($, window, document, undefined) {
2331
+
2332
+ /**
2333
+ * Creates the animate plugin.
2334
+ * @class The Navigation Plugin
2335
+ * @param {Owl} scope - The Owl Carousel
2336
+ */
2337
+ var Animate = function(scope) {
2338
+ this.core = scope;
2339
+ this.core.options = $.extend({}, Animate.Defaults, this.core.options);
2340
+ this.swapping = true;
2341
+ this.previous = undefined;
2342
+ this.next = undefined;
2343
+
2344
+ this.handlers = {
2345
+ 'change.owl.carousel': $.proxy(function(e) {
2346
+ if (e.property.name == 'position') {
2347
+ this.previous = this.core.current();
2348
+ this.next = e.property.value;
2349
+ }
2350
+ }, this),
2351
+ 'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
2352
+ this.swapping = e.type == 'translated';
2353
+ }, this),
2354
+ 'translate.owl.carousel': $.proxy(function(e) {
2355
+ if (this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
2356
+ this.swap();
2357
+ }
2358
+ }, this)
2359
+ };
2360
+
2361
+ this.core.$element.on(this.handlers);
2362
+ };
2363
+
2364
+ /**
2365
+ * Default options.
2366
+ * @public
2367
+ */
2368
+ Animate.Defaults = {
2369
+ animateOut: false,
2370
+ animateIn: false
2371
+ };
2372
+
2373
+ /**
2374
+ * Toggles the animation classes whenever an translations starts.
2375
+ * @protected
2376
+ * @returns {Boolean|undefined}
2377
+ */
2378
+ Animate.prototype.swap = function() {
2379
+
2380
+ if (this.core.settings.items !== 1 || !this.core.support3d) {
2381
+ return;
2382
+ }
2383
+
2384
+ this.core.speed(0);
2385
+
2386
+ var left,
2387
+ clear = $.proxy(this.clear, this),
2388
+ previous = this.core.$stage.children().eq(this.previous),
2389
+ next = this.core.$stage.children().eq(this.next),
2390
+ incoming = this.core.settings.animateIn,
2391
+ outgoing = this.core.settings.animateOut;
2392
+
2393
+ if (this.core.current() === this.previous) {
2394
+ return;
2395
+ }
2396
+
2397
+ if (outgoing) {
2398
+ left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
2399
+ previous.css( { 'left': left + 'px' } )
2400
+ .addClass('animated owl-animated-out')
2401
+ .addClass(outgoing)
2402
+ .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear);
2403
+ }
2404
+
2405
+ if (incoming) {
2406
+ next.addClass('animated owl-animated-in')
2407
+ .addClass(incoming)
2408
+ .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', clear);
2409
+ }
2410
+ };
2411
+
2412
+ Animate.prototype.clear = function(e) {
2413
+ $(e.target).css( { 'left': '' } )
2414
+ .removeClass('animated owl-animated-out owl-animated-in')
2415
+ .removeClass(this.core.settings.animateIn)
2416
+ .removeClass(this.core.settings.animateOut);
2417
+ this.core.transitionEnd();
2418
+ }
2419
+
2420
+ /**
2421
+ * Destroys the plugin.
2422
+ * @public
2423
+ */
2424
+ Animate.prototype.destroy = function() {
2425
+ var handler, property;
2426
+
2427
+ for (handler in this.handlers) {
2428
+ this.core.$element.off(handler, this.handlers[handler]);
2429
+ }
2430
+ for (property in Object.getOwnPropertyNames(this)) {
2431
+ typeof this[property] != 'function' && (this[property] = null);
2432
+ }
2433
+ };
2434
+
2435
+ $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
2436
+
2437
+ })(window.Zepto || window.jQuery, window, document);
2438
+
2439
+ /**
2440
+ * Autoplay Plugin
2441
+ * @version 2.0.0
2442
+ * @author Bartosz Wojciechowski
2443
+ * @license The MIT License (MIT)
2444
+ */
2445
+ ;(function($, window, document, undefined) {
2446
+
2447
+ /**
2448
+ * Creates the autoplay plugin.
2449
+ * @class The Autoplay Plugin
2450
+ * @param {Owl} scope - The Owl Carousel
2451
+ */
2452
+ var Autoplay = function(scope) {
2453
+ this.core = scope;
2454
+ this.core.options = $.extend({}, Autoplay.Defaults, this.core.options);
2455
+
2456
+ this.handlers = {
2457
+ 'translated.owl.carousel refreshed.owl.carousel': $.proxy(function() {
2458
+ this.autoplay();
2459
+ }, this),
2460
+ 'play.owl.autoplay': $.proxy(function(e, t, s) {
2461
+ this.play(t, s);
2462
+ }, this),
2463
+ 'stop.owl.autoplay': $.proxy(function() {
2464
+ this.stop();
2465
+ }, this),
2466
+ 'mouseover.owl.autoplay': $.proxy(function() {
2467
+ if (this.core.settings.autoplayHoverPause) {
2468
+ this.pause();
2469
+ }
2470
+ }, this),
2471
+ 'mouseleave.owl.autoplay': $.proxy(function() {
2472
+ if (this.core.settings.autoplayHoverPause) {
2473
+ this.autoplay();
2474
+ }
2475
+ }, this)
2476
+ };
2477
+
2478
+ this.core.$element.on(this.handlers);
2479
+ };
2480
+
2481
+ /**
2482
+ * Default options.
2483
+ * @public
2484
+ */
2485
+ Autoplay.Defaults = {
2486
+ autoplay: false,
2487
+ autoplayTimeout: 5000,
2488
+ autoplayHoverPause: false,
2489
+ autoplaySpeed: false
2490
+ };
2491
+
2492
+ /**
2493
+ * @protected
2494
+ * @todo Must be documented.
2495
+ */
2496
+ Autoplay.prototype.autoplay = function() {
2497
+ if (this.core.settings.autoplay && !this.core.state.videoPlay) {
2498
+ window.clearInterval(this.interval);
2499
+
2500
+ this.interval = window.setInterval($.proxy(function() {
2501
+ this.play();
2502
+ }, this), this.core.settings.autoplayTimeout);
2503
+ } else {
2504
+ window.clearInterval(this.interval);
2505
+ }
2506
+ };
2507
+
2508
+ /**
2509
+ * Starts the autoplay.
2510
+ * @public
2511
+ * @param {Number} [timeout] - ...
2512
+ * @param {Number} [speed] - ...
2513
+ * @returns {Boolean|undefined} - ...
2514
+ * @todo Must be documented.
2515
+ */
2516
+ Autoplay.prototype.play = function(timeout, speed) {
2517
+ // if tab is inactive - doesnt work in <IE10
2518
+ if (document.hidden === true) {
2519
+ return;
2520
+ }
2521
+
2522
+ if (this.core.state.isTouch || this.core.state.isScrolling
2523
+ || this.core.state.isSwiping || this.core.state.inMotion) {
2524
+ return;
2525
+ }
2526
+
2527
+ if (this.core.settings.autoplay === false) {
2528
+ window.clearInterval(this.interval);
2529
+ return;
2530
+ }
2531
+
2532
+ this.core.next(this.core.settings.autoplaySpeed);
2533
+ };
2534
+
2535
+ /**
2536
+ * Stops the autoplay.
2537
+ * @public
2538
+ */
2539
+ Autoplay.prototype.stop = function() {
2540
+ window.clearInterval(this.interval);
2541
+ };
2542
+
2543
+ /**
2544
+ * Pauses the autoplay.
2545
+ * @public
2546
+ */
2547
+ Autoplay.prototype.pause = function() {
2548
+ window.clearInterval(this.interval);
2549
+ };
2550
+
2551
+ /**
2552
+ * Destroys the plugin.
2553
+ */
2554
+ Autoplay.prototype.destroy = function() {
2555
+ var handler, property;
2556
+
2557
+ window.clearInterval(this.interval);
2558
+
2559
+ for (handler in this.handlers) {
2560
+ this.core.$element.off(handler, this.handlers[handler]);
2561
+ }
2562
+ for (property in Object.getOwnPropertyNames(this)) {
2563
+ typeof this[property] != 'function' && (this[property] = null);
2564
+ }
2565
+ };
2566
+
2567
+ $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
2568
+
2569
+ })(window.Zepto || window.jQuery, window, document);
2570
+
2571
+ /**
2572
+ * Navigation Plugin
2573
+ * @version 2.0.0
2574
+ * @author Artus Kolanowski
2575
+ * @license The MIT License (MIT)
2576
+ */
2577
+ ;(function($, window, document, undefined) {
2578
+ 'use strict';
2579
+
2580
+ /**
2581
+ * Creates the navigation plugin.
2582
+ * @class The Navigation Plugin
2583
+ * @param {Owl} carousel - The Owl Carousel.
2584
+ */
2585
+ var Navigation = function(carousel) {
2586
+ /**
2587
+ * Reference to the core.
2588
+ * @protected
2589
+ * @type {Owl}
2590
+ */
2591
+ this._core = carousel;
2592
+
2593
+ /**
2594
+ * Indicates whether the plugin is initialized or not.
2595
+ * @protected
2596
+ * @type {Boolean}
2597
+ */
2598
+ this._initialized = false;
2599
+
2600
+ /**
2601
+ * The current paging indexes.
2602
+ * @protected
2603
+ * @type {Array}
2604
+ */
2605
+ this._pages = [];
2606
+
2607
+ /**
2608
+ * All DOM elements of the user interface.
2609
+ * @protected
2610
+ * @type {Object}
2611
+ */
2612
+ this._controls = {};
2613
+
2614
+ /**
2615
+ * Markup for an indicator.
2616
+ * @protected
2617
+ * @type {Array.<String>}
2618
+ */
2619
+ this._templates = [];
2620
+
2621
+ /**
2622
+ * The carousel element.
2623
+ * @type {jQuery}
2624
+ */
2625
+ this.$element = this._core.$element;
2626
+
2627
+ /**
2628
+ * Overridden methods of the carousel.
2629
+ * @protected
2630
+ * @type {Object}
2631
+ */
2632
+ this._overrides = {
2633
+ next: this._core.next,
2634
+ prev: this._core.prev,
2635
+ to: this._core.to
2636
+ };
2637
+
2638
+ /**
2639
+ * All event handlers.
2640
+ * @protected
2641
+ * @type {Object}
2642
+ */
2643
+ this._handlers = {
2644
+ 'prepared.owl.carousel': $.proxy(function(e) {
2645
+ if (this._core.settings.dotsData) {
2646
+ this._templates.push($(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot'));
2647
+ }
2648
+ }, this),
2649
+ 'add.owl.carousel': $.proxy(function(e) {
2650
+ if (this._core.settings.dotsData) {
2651
+ this._templates.splice(e.position, 0, $(e.content).find('[data-dot]').andSelf('[data-dot]').attr('data-dot'));
2652
+ }
2653
+ }, this),
2654
+ 'remove.owl.carousel prepared.owl.carousel': $.proxy(function(e) {
2655
+ if (this._core.settings.dotsData) {
2656
+ this._templates.splice(e.position, 1);
2657
+ }
2658
+ }, this),
2659
+ 'change.owl.carousel': $.proxy(function(e) {
2660
+ if (e.property.name == 'position') {
2661
+ if (!this._core.state.revert && !this._core.settings.loop && this._core.settings.navRewind) {
2662
+ var current = this._core.current(),
2663
+ maximum = this._core.maximum(),
2664
+ minimum = this._core.minimum();
2665
+ e.data = e.property.value > maximum
2666
+ ? current >= maximum ? minimum : maximum
2667
+ : e.property.value < minimum ? maximum : e.property.value;
2668
+ }
2669
+ }
2670
+ }, this),
2671
+ 'changed.owl.carousel': $.proxy(function(e) {
2672
+ if (e.property.name == 'position') {
2673
+ this.draw();
2674
+ }
2675
+ }, this),
2676
+ 'refreshed.owl.carousel': $.proxy(function() {
2677
+ if (!this._initialized) {
2678
+ this.initialize();
2679
+ this._initialized = true;
2680
+ }
2681
+ this._core.trigger('refresh', null, 'navigation');
2682
+ this.update();
2683
+ this.draw();
2684
+ this._core.trigger('refreshed', null, 'navigation');
2685
+ }, this)
2686
+ };
2687
+
2688
+ // set default options
2689
+ this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
2690
+
2691
+ // register event handlers
2692
+ this.$element.on(this._handlers);
2693
+ }
2694
+
2695
+ /**
2696
+ * Default options.
2697
+ * @public
2698
+ * @todo Rename `slideBy` to `navBy`
2699
+ */
2700
+ Navigation.Defaults = {
2701
+ nav: false,
2702
+ navRewind: true,
2703
+ navText: [ 'prev', 'next' ],
2704
+ navSpeed: false,
2705
+ navElement: 'div',
2706
+ navContainer: false,
2707
+ navContainerClass: 'owl-nav',
2708
+ navClass: [ 'owl-prev', 'owl-next' ],
2709
+ slideBy: 1,
2710
+ dotClass: 'owl-dot',
2711
+ dotsClass: 'owl-dots',
2712
+ dots: true,
2713
+ dotsEach: false,
2714
+ dotData: false,
2715
+ dotsSpeed: false,
2716
+ dotsContainer: false,
2717
+ controlsClass: 'owl-controls'
2718
+ }
2719
+
2720
+ /**
2721
+ * Initializes the layout of the plugin and extends the carousel.
2722
+ * @protected
2723
+ */
2724
+ Navigation.prototype.initialize = function() {
2725
+ var $container, override,
2726
+ options = this._core.settings;
2727
+
2728
+ // create the indicator template
2729
+ if (!options.dotsData) {
2730
+ this._templates = [ $('<div>')
2731
+ .addClass(options.dotClass)
2732
+ .append($('<span>'))
2733
+ .prop('outerHTML') ];
2734
+ }
2735
+
2736
+ // create controls container if needed
2737
+ if (!options.navContainer || !options.dotsContainer) {
2738
+ this._controls.$container = $('<div>')
2739
+ .addClass(options.controlsClass)
2740
+ .appendTo(this.$element);
2741
+ }
2742
+
2743
+ // create DOM structure for absolute navigation
2744
+ this._controls.$indicators = options.dotsContainer ? $(options.dotsContainer)
2745
+ : $('<div>').hide().addClass(options.dotsClass).appendTo(this._controls.$container);
2746
+
2747
+ this._controls.$indicators.on('click', 'div', $.proxy(function(e) {
2748
+ var index = $(e.target).parent().is(this._controls.$indicators)
2749
+ ? $(e.target).index() : $(e.target).parent().index();
2750
+
2751
+ e.preventDefault();
2752
+
2753
+ this.to(index, options.dotsSpeed);
2754
+ }, this));
2755
+
2756
+ // create DOM structure for relative navigation
2757
+ $container = options.navContainer ? $(options.navContainer)
2758
+ : $('<div>').addClass(options.navContainerClass).prependTo(this._controls.$container);
2759
+
2760
+ this._controls.$next = $('<' + options.navElement + '>');
2761
+ this._controls.$previous = this._controls.$next.clone();
2762
+
2763
+ this._controls.$previous
2764
+ .addClass(options.navClass[0])
2765
+ .html(options.navText[0])
2766
+ .hide()
2767
+ .prependTo($container)
2768
+ .on('click', $.proxy(function(e) {
2769
+ this.prev(options.navSpeed);
2770
+ }, this));
2771
+ this._controls.$next
2772
+ .addClass(options.navClass[1])
2773
+ .html(options.navText[1])
2774
+ .hide()
2775
+ .appendTo($container)
2776
+ .on('click', $.proxy(function(e) {
2777
+ this.next(options.navSpeed);
2778
+ }, this));
2779
+
2780
+ // override public methods of the carousel
2781
+ for (override in this._overrides) {
2782
+ this._core[override] = $.proxy(this[override], this);
2783
+ }
2784
+ }
2785
+
2786
+ /**
2787
+ * Destroys the plugin.
2788
+ * @protected
2789
+ */
2790
+ Navigation.prototype.destroy = function() {
2791
+ var handler, control, property, override;
2792
+
2793
+ for (handler in this._handlers) {
2794
+ this.$element.off(handler, this._handlers[handler]);
2795
+ }
2796
+ for (control in this._controls) {
2797
+ this._controls[control].remove();
2798
+ }
2799
+ for (override in this.overides) {
2800
+ this._core[override] = this._overrides[override];
2801
+ }
2802
+ for (property in Object.getOwnPropertyNames(this)) {
2803
+ typeof this[property] != 'function' && (this[property] = null);
2804
+ }
2805
+ }
2806
+
2807
+ /**
2808
+ * Updates the internal state.
2809
+ * @protected
2810
+ */
2811
+ Navigation.prototype.update = function() {
2812
+ var i, j, k,
2813
+ options = this._core.settings,
2814
+ lower = this._core.clones().length / 2,
2815
+ upper = lower + this._core.items().length,
2816
+ size = options.center || options.autoWidth || options.dotData
2817
+ ? 1 : options.dotsEach || options.items;
2818
+
2819
+ if (options.slideBy !== 'page') {
2820
+ options.slideBy = Math.min(options.slideBy, options.items);
2821
+ }
2822
+
2823
+ if (options.dots || options.slideBy == 'page') {
2824
+ this._pages = [];
2825
+
2826
+ for (i = lower, j = 0, k = 0; i < upper; i++) {
2827
+ if (j >= size || j === 0) {
2828
+ this._pages.push({
2829
+ start: i - lower,
2830
+ end: i - lower + size - 1
2831
+ });
2832
+ j = 0, ++k;
2833
+ }
2834
+ j += this._core.mergers(this._core.relative(i));
2835
+ }
2836
+ }
2837
+ }
2838
+
2839
+ /**
2840
+ * Draws the user interface.
2841
+ * @todo The option `dotData` wont work.
2842
+ * @protected
2843
+ */
2844
+ Navigation.prototype.draw = function() {
2845
+ var difference, i, html = '',
2846
+ options = this._core.settings,
2847
+ $items = this._core.$stage.children(),
2848
+ index = this._core.relative(this._core.current());
2849
+
2850
+ if (options.nav && !options.loop && !options.navRewind) {
2851
+ this._controls.$previous.toggleClass('disabled', index <= 0);
2852
+ this._controls.$next.toggleClass('disabled', index >= this._core.maximum());
2853
+ }
2854
+
2855
+ this._controls.$previous.toggle(options.nav);
2856
+ this._controls.$next.toggle(options.nav);
2857
+
2858
+ if (options.dots) {
2859
+ difference = this._pages.length - this._controls.$indicators.children().length;
2860
+
2861
+ if (options.dotData && difference !== 0) {
2862
+ for (i = 0; i < this._controls.$indicators.children().length; i++) {
2863
+ html += this._templates[this._core.relative(i)];
2864
+ }
2865
+ this._controls.$indicators.html(html);
2866
+ } else if (difference > 0) {
2867
+ html = new Array(difference + 1).join(this._templates[0]);
2868
+ this._controls.$indicators.append(html);
2869
+ } else if (difference < 0) {
2870
+ this._controls.$indicators.children().slice(difference).remove();
2871
+ }
2872
+
2873
+ this._controls.$indicators.find('.active').removeClass('active');
2874
+ this._controls.$indicators.children().eq($.inArray(this.current(), this._pages)).addClass('active');
2875
+ }
2876
+
2877
+ this._controls.$indicators.toggle(options.dots);
2878
+ }
2879
+
2880
+ /**
2881
+ * Extends event data.
2882
+ * @protected
2883
+ * @param {Event} event - The event object which gets thrown.
2884
+ */
2885
+ Navigation.prototype.onTrigger = function(event) {
2886
+ var settings = this._core.settings;
2887
+
2888
+ event.page = {
2889
+ index: $.inArray(this.current(), this._pages),
2890
+ count: this._pages.length,
2891
+ size: settings && (settings.center || settings.autoWidth || settings.dotData
2892
+ ? 1 : settings.dotsEach || settings.items)
2893
+ };
2894
+ }
2895
+
2896
+ /**
2897
+ * Gets the current page position of the carousel.
2898
+ * @protected
2899
+ * @returns {Number}
2900
+ */
2901
+ Navigation.prototype.current = function() {
2902
+ var index = this._core.relative(this._core.current());
2903
+ return $.grep(this._pages, function(o) {
2904
+ return o.start <= index && o.end >= index;
2905
+ }).pop();
2906
+ }
2907
+
2908
+ /**
2909
+ * Gets the current succesor/predecessor position.
2910
+ * @protected
2911
+ * @returns {Number}
2912
+ */
2913
+ Navigation.prototype.getPosition = function(successor) {
2914
+ var position, length,
2915
+ options = this._core.settings;
2916
+
2917
+ if (options.slideBy == 'page') {
2918
+ position = $.inArray(this.current(), this._pages);
2919
+ length = this._pages.length;
2920
+ successor ? ++position : --position;
2921
+ position = this._pages[((position % length) + length) % length].start;
2922
+ } else {
2923
+ position = this._core.relative(this._core.current());
2924
+ length = this._core.items().length;
2925
+ successor ? position += options.slideBy : position -= options.slideBy;
2926
+ }
2927
+ return position;
2928
+ }
2929
+
2930
+ /**
2931
+ * Slides to the next item or page.
2932
+ * @public
2933
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
2934
+ */
2935
+ Navigation.prototype.next = function(speed) {
2936
+ $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
2937
+ }
2938
+
2939
+ /**
2940
+ * Slides to the previous item or page.
2941
+ * @public
2942
+ * @param {Number} [speed=false] - The time in milliseconds for the transition.
2943
+ */
2944
+ Navigation.prototype.prev = function(speed) {
2945
+ $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
2946
+ }
2947
+
2948
+ /**
2949
+ * Slides to the specified item or page.
2950
+ * @public
2951
+ * @param {Number} position - The position of the item or page.
2952
+ * @param {Number} [speed] - The time in milliseconds for the transition.
2953
+ * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
2954
+ */
2955
+ Navigation.prototype.to = function(position, speed, standard) {
2956
+ var length;
2957
+
2958
+ if (!standard) {
2959
+ length = this._pages.length;
2960
+ $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
2961
+ } else {
2962
+ $.proxy(this._overrides.to, this._core)(position, speed);
2963
+ }
2964
+ }
2965
+
2966
+ $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
2967
+
2968
+ })(window.Zepto || window.jQuery, window, document);
2969
+
2970
+ /**
2971
+ * Hash Plugin
2972
+ * @version 2.0.0
2973
+ * @author Artus Kolanowski
2974
+ * @license The MIT License (MIT)
2975
+ */
2976
+ ;(function($, window, document, undefined) {
2977
+ 'use strict';
2978
+
2979
+ /**
2980
+ * Creates the hash plugin.
2981
+ * @class The Hash Plugin
2982
+ * @param {Owl} carousel - The Owl Carousel
2983
+ */
2984
+ var Hash = function(carousel) {
2985
+ /**
2986
+ * Reference to the core.
2987
+ * @protected
2988
+ * @type {Owl}
2989
+ */
2990
+ this._core = carousel;
2991
+
2992
+ /**
2993
+ * Hash table for the hashes.
2994
+ * @protected
2995
+ * @type {Object}
2996
+ */
2997
+ this._hashes = {};
2998
+
2999
+ /**
3000
+ * The carousel element.
3001
+ * @type {jQuery}
3002
+ */
3003
+ this.$element = this._core.$element;
3004
+
3005
+ /**
3006
+ * All event handlers.
3007
+ * @protected
3008
+ * @type {Object}
3009
+ */
3010
+ this._handlers = {
3011
+ 'initialized.owl.carousel': $.proxy(function() {
3012
+ if (this._core.settings.startPosition == 'URLHash') {
3013
+ $(window).trigger('hashchange.owl.navigation');
3014
+ }
3015
+ }, this),
3016
+ 'prepared.owl.carousel': $.proxy(function(e) {
3017
+ var hash = $(e.content).find('[data-hash]').andSelf('[data-hash]').attr('data-hash');
3018
+ this._hashes[hash] = e.content;
3019
+ }, this)
3020
+ };
3021
+
3022
+ // set default options
3023
+ this._core.options = $.extend({}, Hash.Defaults, this._core.options);
3024
+
3025
+ // register the event handlers
3026
+ this.$element.on(this._handlers);
3027
+
3028
+ // register event listener for hash navigation
3029
+ $(window).on('hashchange.owl.navigation', $.proxy(function() {
3030
+ var hash = window.location.hash.substring(1),
3031
+ items = this._core.$stage.children(),
3032
+ position = this._hashes[hash] && items.index(this._hashes[hash]) || 0;
3033
+
3034
+ if (!hash) {
3035
+ return false;
3036
+ }
3037
+
3038
+ this._core.to(position, false, true);
3039
+ }, this));
3040
+ }
3041
+
3042
+ /**
3043
+ * Default options.
3044
+ * @public
3045
+ */
3046
+ Hash.Defaults = {
3047
+ URLhashListener: false
3048
+ }
3049
+
3050
+ /**
3051
+ * Destroys the plugin.
3052
+ * @public
3053
+ */
3054
+ Hash.prototype.destroy = function() {
3055
+ var handler, property;
3056
+
3057
+ $(window).off('hashchange.owl.navigation');
3058
+
3059
+ for (handler in this._handlers) {
3060
+ this._core.$element.off(handler, this._handlers[handler]);
3061
+ }
3062
+ for (property in Object.getOwnPropertyNames(this)) {
3063
+ typeof this[property] != 'function' && (this[property] = null);
3064
+ }
3065
+ }
3066
+
3067
+ $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
3068
+
3069
+ })(window.Zepto || window.jQuery, window, document);