WP VR – 360 Panorama and virtual tour creator for WordPress - Version 3.1.0

Version Description

  • Custom scene gallery.
  • Border radius tag added.
  • Modified preview window.

=

Download this release

Release Info

Developer rextheme
Plugin Icon 128x128 WP VR – 360 Panorama and virtual tour creator for WordPress
Version 3.1.0
Comparing to
See all releases

Code changes from version 3.0.0 to 3.1.0

README.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://rextheme.com/wp-vr-360-panorama-and-virtual-tour-creator-fo
4
  Tags: virtual tour, real estate tour, panorama, panorama viewer, virtual tour, 360 panorama, interactive tour
5
  Requires at least: 4.0
6
  Tested up to: 5.2
7
- Stable tag: 3.0.0
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -90,6 +90,7 @@ For more control over creating a virtual tour, learn about the [Premium version]
90
  * Scene fade animation
91
  * Full width tour tag
92
  * 360 Video embed support
 
93
  * Support from support forum
94
 
95
 
@@ -106,12 +107,12 @@ For more control over creating a virtual tour, learn about the [Premium version]
106
  * Add scene title and description tag
107
  * File export and import (for WPVR only)
108
  * Duplicate tour on one click
 
109
  * Personalized support (e-mail or forum)
110
 
111
  [Instructions to upgrade to pro](https://rextheme.com/docs/wp-vr/how-to-upgrade-to-pro/)
112
 
113
  **Upcoming Features**
114
- - Gallery of scenes
115
  - Ground map
116
  - Connect multiple tours
117
  - Background music
@@ -234,5 +235,10 @@ You will find the gyroscope icon at the top left side.
234
  * Fullwidth tag added.
235
  * Placeholder color changed.
236
 
 
 
 
 
 
237
  == Upgrade Notice ==
238
  Please do update the WP VR to the latest version. Each update makes it sure your plugin is supporting all tour features.  
4
  Tags: virtual tour, real estate tour, panorama, panorama viewer, virtual tour, 360 panorama, interactive tour
5
  Requires at least: 4.0
6
  Tested up to: 5.2
7
+ Stable tag: 3.1.0
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
90
  * Scene fade animation
91
  * Full width tour tag
92
  * 360 Video embed support
93
+ * Radius tag for VR border radius
94
  * Support from support forum
95
 
96
 
107
  * Add scene title and description tag
108
  * File export and import (for WPVR only)
109
  * Duplicate tour on one click
110
+ * Custom scene gallery
111
  * Personalized support (e-mail or forum)
112
 
113
  [Instructions to upgrade to pro](https://rextheme.com/docs/wp-vr/how-to-upgrade-to-pro/)
114
 
115
  **Upcoming Features**
 
116
  - Ground map
117
  - Connect multiple tours
118
  - Background music
235
  * Fullwidth tag added.
236
  * Placeholder color changed.
237
 
238
+ = 3.1.0 =
239
+ * Custom scene gallery.
240
+ * Border radius tag added.
241
+ * Modified preview window.
242
+
243
  == Upgrade Notice ==
244
  Please do update the WP VR to the latest version. Each update makes it sure your plugin is supporting all tour features.  
admin/class-wpvr-admin.php CHANGED
@@ -95,6 +95,7 @@ class Wpvr_Admin {
95
  if ($screen->id=="wpvr_item") {
96
  wp_enqueue_style( 'icon-picker-css', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.min.css', array(), $this->version, 'all' );
97
  wp_enqueue_style( 'icon-picker-css-theme', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.grey.min.css', array(), $this->version, 'all' );
 
98
  }
99
 
100
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-admin.css', array(), $this->version, 'all' );
@@ -137,6 +138,7 @@ class Wpvr_Admin {
137
  wp_enqueue_script( 'jquery-repeater', plugin_dir_url( __FILE__ ) .'js/jquery.repeater.min.js', array('jquery'), true);
138
  if ($adscreen->id=="wpvr_item") {
139
  wp_enqueue_script('icon-picker', plugin_dir_url( __FILE__ ) . 'lib/jquery.fonticonpicker.min.js', array(), true);
 
140
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-admin.js', array( 'jquery' ), $this->version, false );
141
  }
142
 
95
  if ($screen->id=="wpvr_item") {
96
  wp_enqueue_style( 'icon-picker-css', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.min.css', array(), $this->version, 'all' );
97
  wp_enqueue_style( 'icon-picker-css-theme', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.grey.min.css', array(), $this->version, 'all' );
98
+ wp_enqueue_style( 'owl-css', plugin_dir_url( __FILE__ ) . 'css/owl.carousel.css', array(), $this->version, 'all' );
99
  }
100
 
101
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-admin.css', array(), $this->version, 'all' );
138
  wp_enqueue_script( 'jquery-repeater', plugin_dir_url( __FILE__ ) .'js/jquery.repeater.min.js', array('jquery'), true);
139
  if ($adscreen->id=="wpvr_item") {
140
  wp_enqueue_script('icon-picker', plugin_dir_url( __FILE__ ) . 'lib/jquery.fonticonpicker.min.js', array(), true);
141
+ wp_enqueue_script( 'owl', plugin_dir_url( __FILE__ ) . 'js/owl.carousel.js', array( 'jquery' ), false );
142
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-admin.js', array( 'jquery' ), $this->version, false );
143
  }
144
 
admin/class-wpvr-ajax.php CHANGED
@@ -629,6 +629,14 @@ class Wpvr_Ajax {
629
  $control = false;
630
  }
631
 
 
 
 
 
 
 
 
 
632
  $gyro = sanitize_text_field($_POST['gyro']);
633
 
634
  if ($gyro == 'on') {
@@ -932,7 +940,7 @@ class Wpvr_Ajax {
932
  }
933
 
934
  $pano_array = array();
935
- $pano_array = array(__( "panoid" )=>$panoid,__( "autoLoad" )=>$autoload,__( "showControls" )=>$control,__( "gyro" )=>$gyro,__( "compass" )=>$compass,__( "autoRotate" )=>$autorotation,__( "autoRotateInactivityDelay" )=>$autorotationinactivedelay,__( "autoRotateStopDelay" )=>$autorotationstopdelay,__( "preview" )=>$preview,__( "defaultscene" )=>$default_scene,__( "scenefadeduration" )=>$scene_fade_duration,__( "panodata" )=>$panodata);
936
 
937
  if ($rotation == 'off') {
938
  unset($pano_array['autoRotate']);
629
  $control = false;
630
  }
631
 
632
+ $vrgallery = sanitize_text_field($_POST['vrgallery']);
633
+ if ($vrgallery == 'on') {
634
+ $vrgallery = true;
635
+ }
636
+ else {
637
+ $vrgallery = false;
638
+ }
639
+
640
  $gyro = sanitize_text_field($_POST['gyro']);
641
 
642
  if ($gyro == 'on') {
940
  }
941
 
942
  $pano_array = array();
943
+ $pano_array = array(__( "panoid" )=>$panoid,__( "autoLoad" )=>$autoload,__( "showControls" )=>$control,__( "vrgallery" )=>$vrgallery,__( "gyro" )=>$gyro,__( "compass" )=>$compass,__( "autoRotate" )=>$autorotation,__( "autoRotateInactivityDelay" )=>$autorotationinactivedelay,__( "autoRotateStopDelay" )=>$autorotationstopdelay,__( "preview" )=>$preview,__( "defaultscene" )=>$default_scene,__( "scenefadeduration" )=>$scene_fade_duration,__( "panodata" )=>$panodata);
944
 
945
  if ($rotation == 'off') {
946
  unset($pano_array['autoRotate']);
admin/css/owl.carousel.css ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Owl Carousel v2.3.4
3
+ * Copyright 2013-2018 David Deutsch
4
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
5
+ */
6
+ /*
7
+ * Owl Carousel - Core
8
+ */
9
+ .owl-carousel {
10
+ display: none;
11
+ width: 100%;
12
+ -webkit-tap-highlight-color: transparent;
13
+ /* position relative and z-index fix webkit rendering fonts issue */
14
+ position: relative;
15
+ z-index: 1; }
16
+ .owl-carousel .owl-stage {
17
+ position: relative;
18
+ -ms-touch-action: pan-Y;
19
+ touch-action: manipulation;
20
+ -moz-backface-visibility: hidden;
21
+ /* fix firefox animation glitch */ }
22
+ .owl-carousel .owl-stage:after {
23
+ content: ".";
24
+ display: block;
25
+ clear: both;
26
+ visibility: hidden;
27
+ line-height: 0;
28
+ height: 0; }
29
+ .owl-carousel .owl-stage-outer {
30
+ position: relative;
31
+ overflow: hidden;
32
+ /* fix for flashing background */
33
+ -webkit-transform: translate3d(0px, 0px, 0px); }
34
+ .owl-carousel .owl-wrapper,
35
+ .owl-carousel .owl-item {
36
+ -webkit-backface-visibility: hidden;
37
+ -moz-backface-visibility: hidden;
38
+ -ms-backface-visibility: hidden;
39
+ -webkit-transform: translate3d(0, 0, 0);
40
+ -moz-transform: translate3d(0, 0, 0);
41
+ -ms-transform: translate3d(0, 0, 0); }
42
+ .owl-carousel .owl-item {
43
+ position: relative;
44
+ min-height: 1px;
45
+ float: left;
46
+ -webkit-backface-visibility: hidden;
47
+ -webkit-tap-highlight-color: transparent;
48
+ -webkit-touch-callout: none; }
49
+ .owl-carousel .owl-item img {
50
+ display: block;
51
+ width: 100%; }
52
+ .owl-carousel .owl-nav.disabled,
53
+ .owl-carousel .owl-dots.disabled {
54
+ display: none; }
55
+ .owl-carousel .owl-nav .owl-prev,
56
+ .owl-carousel .owl-nav .owl-next,
57
+ .owl-carousel .owl-dot {
58
+ cursor: pointer;
59
+ -webkit-user-select: none;
60
+ -khtml-user-select: none;
61
+ -moz-user-select: none;
62
+ -ms-user-select: none;
63
+ user-select: none; }
64
+ .owl-carousel .owl-nav button.owl-prev,
65
+ .owl-carousel .owl-nav button.owl-next,
66
+ .owl-carousel button.owl-dot {
67
+ background: none;
68
+ color: inherit;
69
+ border: none;
70
+ padding: 0 !important;
71
+ font: inherit; }
72
+ .owl-carousel.owl-loaded {
73
+ display: block; }
74
+ .owl-carousel.owl-loading {
75
+ opacity: 0;
76
+ display: block; }
77
+ .owl-carousel.owl-hidden {
78
+ opacity: 0; }
79
+ .owl-carousel.owl-refresh .owl-item {
80
+ visibility: hidden; }
81
+ .owl-carousel.owl-drag .owl-item {
82
+ -ms-touch-action: pan-y;
83
+ touch-action: pan-y;
84
+ -webkit-user-select: none;
85
+ -moz-user-select: none;
86
+ -ms-user-select: none;
87
+ user-select: none; }
88
+ .owl-carousel.owl-grab {
89
+ cursor: move;
90
+ cursor: grab; }
91
+ .owl-carousel.owl-rtl {
92
+ direction: rtl; }
93
+ .owl-carousel.owl-rtl .owl-item {
94
+ float: right; }
95
+
96
+ /* No Js */
97
+ .no-js .owl-carousel {
98
+ display: block; }
99
+
100
+ /*
101
+ * Owl Carousel - Animate Plugin
102
+ */
103
+ .owl-carousel .animated {
104
+ animation-duration: 1000ms;
105
+ animation-fill-mode: both; }
106
+
107
+ .owl-carousel .owl-animated-in {
108
+ z-index: 0; }
109
+
110
+ .owl-carousel .owl-animated-out {
111
+ z-index: 1; }
112
+
113
+ .owl-carousel .fadeOut {
114
+ animation-name: fadeOut; }
115
+
116
+ @keyframes fadeOut {
117
+ 0% {
118
+ opacity: 1; }
119
+ 100% {
120
+ opacity: 0; } }
121
+
122
+ /*
123
+ * Owl Carousel - Auto Height Plugin
124
+ */
125
+ .owl-height {
126
+ transition: height 500ms ease-in-out; }
127
+
128
+ /*
129
+ * Owl Carousel - Lazy Load Plugin
130
+ */
131
+ .owl-carousel .owl-item {
132
+ /**
133
+ This is introduced due to a bug in IE11 where lazy loading combined with autoheight plugin causes a wrong
134
+ calculation of the height of the owl-item that breaks page layouts
135
+ */ }
136
+ .owl-carousel .owl-item .owl-lazy {
137
+ opacity: 0;
138
+ transition: opacity 400ms ease; }
139
+ .owl-carousel .owl-item .owl-lazy[src^=""], .owl-carousel .owl-item .owl-lazy:not([src]) {
140
+ max-height: 0; }
141
+ .owl-carousel .owl-item img.owl-lazy {
142
+ transform-style: preserve-3d; }
143
+
144
+ /*
145
+ * Owl Carousel - Video Plugin
146
+ */
147
+ .owl-carousel .owl-video-wrapper {
148
+ position: relative;
149
+ height: 100%;
150
+ background: #000; }
151
+
152
+ .owl-carousel .owl-video-play-icon {
153
+ position: absolute;
154
+ height: 80px;
155
+ width: 80px;
156
+ left: 50%;
157
+ top: 50%;
158
+ margin-left: -40px;
159
+ margin-top: -40px;
160
+ background: url("owl.video.play.png") no-repeat;
161
+ cursor: pointer;
162
+ z-index: 1;
163
+ -webkit-backface-visibility: hidden;
164
+ transition: transform 100ms ease; }
165
+
166
+ .owl-carousel .owl-video-play-icon:hover {
167
+ -ms-transform: scale(1.3, 1.3);
168
+ transform: scale(1.3, 1.3); }
169
+
170
+ .owl-carousel .owl-video-playing .owl-video-tn,
171
+ .owl-carousel .owl-video-playing .owl-video-play-icon {
172
+ display: none; }
173
+
174
+ .owl-carousel .owl-video-tn {
175
+ opacity: 0;
176
+ height: 100%;
177
+ background-position: center center;
178
+ background-repeat: no-repeat;
179
+ background-size: contain;
180
+ transition: opacity 400ms ease; }
181
+
182
+ .owl-carousel .owl-video-frame {
183
+ position: relative;
184
+ z-index: 1;
185
+ height: 100%;
186
+ width: 100%; }
admin/css/owl.theme.default.css ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Owl Carousel v2.3.4
3
+ * Copyright 2013-2018 David Deutsch
4
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
5
+ */
6
+ /*
7
+ * Default theme - Owl Carousel CSS File
8
+ */
9
+ .owl-theme .owl-nav {
10
+ margin-top: 10px;
11
+ text-align: center;
12
+ -webkit-tap-highlight-color: transparent; }
13
+ .owl-theme .owl-nav [class*='owl-'] {
14
+ color: #FFF;
15
+ font-size: 14px;
16
+ margin: 5px;
17
+ padding: 4px 7px;
18
+ background: #D6D6D6;
19
+ display: inline-block;
20
+ cursor: pointer;
21
+ border-radius: 3px; }
22
+ .owl-theme .owl-nav [class*='owl-']:hover {
23
+ background: #869791;
24
+ color: #FFF;
25
+ text-decoration: none; }
26
+ .owl-theme .owl-nav .disabled {
27
+ opacity: 0.5;
28
+ cursor: default; }
29
+
30
+ .owl-theme .owl-nav.disabled + .owl-dots {
31
+ margin-top: 10px; }
32
+
33
+ .owl-theme .owl-dots {
34
+ text-align: center;
35
+ -webkit-tap-highlight-color: transparent; }
36
+ .owl-theme .owl-dots .owl-dot {
37
+ display: inline-block;
38
+ zoom: 1;
39
+ *display: inline; }
40
+ .owl-theme .owl-dots .owl-dot span {
41
+ width: 10px;
42
+ height: 10px;
43
+ margin: 5px 7px;
44
+ background: #D6D6D6;
45
+ display: block;
46
+ -webkit-backface-visibility: visible;
47
+ transition: opacity 200ms ease;
48
+ border-radius: 30px; }
49
+ .owl-theme .owl-dots .owl-dot.active span, .owl-theme .owl-dots .owl-dot:hover span {
50
+ background: #869791; }
admin/css/wpvr-admin.css CHANGED
@@ -3,13 +3,34 @@
3
  * included in this file.
4
  */
5
 
6
- /*@import url('https://fonts.googleapis.com/css?family=Roboto:300,300i,400,500,700,900');*/
7
  .icon-wpvrtourmake_icon:before {
8
  content: '';
9
  height: 30px;
10
  width: 30px;
11
  background: url('../images/icon.png') no-repeat center center / 100% 100%;
12
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  .vr-export {
14
  color: #fff!important;
15
  background-color: #2196F3!important;
3
  * included in this file.
4
  */
5
 
 
6
  .icon-wpvrtourmake_icon:before {
7
  content: '';
8
  height: 30px;
9
  width: 30px;
10
  background: url('../images/icon.png') no-repeat center center / 100% 100%;
11
  }
12
+ .scene-gallery {
13
+ border-radius: 10px;
14
+ max-width: 600px;
15
+ margin: 0 auto;
16
+ color: #32373c;
17
+ background-color: #eceef1;
18
+ }
19
+ .scene-gallery ul {
20
+ display: inline-grid;
21
+ }
22
+
23
+ .scctrl {
24
+ border-radius: 5px;
25
+ width: 100px;
26
+ height: 100px;
27
+ display: inline-block;
28
+ cursor: pointer;
29
+ margin: 5px;
30
+ }
31
+ .scctrl:hover {
32
+ background: rgba(200, 200, 200, 1);
33
+ }
34
  .vr-export {
35
  color: #fff!important;
36
  background-color: #2196F3!important;
admin/js/owl.carousel.js ADDED
@@ -0,0 +1,1756 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Owl carousel
3
+ * @version 2.3.4
4
+ * @author Bartosz Wojciechowski
5
+ * @author David Deutsch
6
+ * @license The MIT License (MIT)
7
+ * @todo Lazy Load Icon
8
+ * @todo prevent animationend bubling
9
+ * @todo itemsScaleUp
10
+ * @todo Test Zepto
11
+ * @todo stagePadding calculate wrong active classes
12
+ */
13
+ ;(function($, window, document, undefined) {
14
+
15
+ /**
16
+ * Creates a carousel.
17
+ * @class The Owl Carousel.
18
+ * @public
19
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
20
+ * @param {Object} [options] - The options
21
+ */
22
+ function Owl(element, options) {
23
+
24
+ /**
25
+ * Current settings for the carousel.
26
+ * @public
27
+ */
28
+ this.settings = null;
29
+
30
+ /**
31
+ * Current options set by the caller including defaults.
32
+ * @public
33
+ */
34
+ this.options = $.extend({}, Owl.Defaults, options);
35
+
36
+ /**
37
+ * Plugin element.
38
+ * @public
39
+ */
40
+ this.$element = $(element);
41
+
42
+ /**
43
+ * Proxied event handlers.
44
+ * @protected
45
+ */
46
+ this._handlers = {};
47
+
48
+ /**
49
+ * References to the running plugins of this carousel.
50
+ * @protected
51
+ */
52
+ this._plugins = {};
53
+
54
+ /**
55
+ * Currently suppressed events to prevent them from being retriggered.
56
+ * @protected
57
+ */
58
+ this._supress = {};
59
+
60
+ /**
61
+ * Absolute current position.
62
+ * @protected
63
+ */
64
+ this._current = null;
65
+
66
+ /**
67
+ * Animation speed in milliseconds.
68
+ * @protected
69
+ */
70
+ this._speed = null;
71
+
72
+ /**
73
+ * Coordinates of all items in pixel.
74
+ * @todo The name of this member is missleading.
75
+ * @protected
76
+ */
77
+ this._coordinates = [];
78
+
79
+ /**
80
+ * Current breakpoint.
81
+ * @todo Real media queries would be nice.
82
+ * @protected
83
+ */
84
+ this._breakpoint = null;
85
+
86
+ /**
87
+ * Current width of the plugin element.
88
+ */
89
+ this._width = null;
90
+
91
+ /**
92
+ * All real items.
93
+ * @protected
94
+ */
95
+ this._items = [];
96
+
97
+ /**
98
+ * All cloned items.
99
+ * @protected
100
+ */
101
+ this._clones = [];
102
+
103
+ /**
104
+ * Merge values of all items.
105
+ * @todo Maybe this could be part of a plugin.
106
+ * @protected
107
+ */
108
+ this._mergers = [];
109
+
110
+ /**
111
+ * Widths of all items.
112
+ */
113
+ this._widths = [];
114
+
115
+ /**
116
+ * Invalidated parts within the update process.
117
+ * @protected
118
+ */
119
+ this._invalidated = {};
120
+
121
+ /**
122
+ * Ordered list of workers for the update process.
123
+ * @protected
124
+ */
125
+ this._pipe = [];
126
+
127
+ /**
128
+ * Current state information for the drag operation.
129
+ * @todo #261
130
+ * @protected
131
+ */
132
+ this._drag = {
133
+ time: null,
134
+ target: null,
135
+ pointer: null,
136
+ stage: {
137
+ start: null,
138
+ current: null
139
+ },
140
+ direction: null
141
+ };
142
+
143
+ /**
144
+ * Current state information and their tags.
145
+ * @type {Object}
146
+ * @protected
147
+ */
148
+ this._states = {
149
+ current: {},
150
+ tags: {
151
+ 'initializing': [ 'busy' ],
152
+ 'animating': [ 'busy' ],
153
+ 'dragging': [ 'interacting' ]
154
+ }
155
+ };
156
+
157
+ $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
158
+ this._handlers[handler] = $.proxy(this[handler], this);
159
+ }, this));
160
+
161
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
162
+ this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
163
+ = new plugin(this);
164
+ }, this));
165
+
166
+ $.each(Owl.Workers, $.proxy(function(priority, worker) {
167
+ this._pipe.push({
168
+ 'filter': worker.filter,
169
+ 'run': $.proxy(worker.run, this)
170
+ });
171
+ }, this));
172
+
173
+ this.setup();
174
+ this.initialize();
175
+ }
176
+
177
+ /**
178
+ * Default options for the carousel.
179
+ * @public
180
+ */
181
+ Owl.Defaults = {
182
+ items: 3,
183
+ loop: false,
184
+ center: false,
185
+ rewind: false,
186
+ checkVisibility: true,
187
+
188
+ mouseDrag: true,
189
+ touchDrag: true,
190
+ pullDrag: true,
191
+ freeDrag: false,
192
+
193
+ margin: 0,
194
+ stagePadding: 0,
195
+
196
+ merge: false,
197
+ mergeFit: true,
198
+ autoWidth: false,
199
+
200
+ startPosition: 0,
201
+ rtl: false,
202
+
203
+ smartSpeed: 250,
204
+ fluidSpeed: false,
205
+ dragEndSpeed: false,
206
+
207
+ responsive: {},
208
+ responsiveRefreshRate: 200,
209
+ responsiveBaseElement: window,
210
+
211
+ fallbackEasing: 'swing',
212
+ slideTransition: '',
213
+
214
+ info: false,
215
+
216
+ nestedItemSelector: false,
217
+ itemElement: 'div',
218
+ stageElement: 'div',
219
+
220
+ refreshClass: 'owl-refresh',
221
+ loadedClass: 'owl-loaded',
222
+ loadingClass: 'owl-loading',
223
+ rtlClass: 'owl-rtl',
224
+ responsiveClass: 'owl-responsive',
225
+ dragClass: 'owl-drag',
226
+ itemClass: 'owl-item',
227
+ stageClass: 'owl-stage',
228
+ stageOuterClass: 'owl-stage-outer',
229
+ grabClass: 'owl-grab'
230
+ };
231
+
232
+ /**
233
+ * Enumeration for width.
234
+ * @public
235
+ * @readonly
236
+ * @enum {String}
237
+ */
238
+ Owl.Width = {
239
+ Default: 'default',
240
+ Inner: 'inner',
241
+ Outer: 'outer'
242
+ };
243
+
244
+ /**
245
+ * Enumeration for types.
246
+ * @public
247
+ * @readonly
248
+ * @enum {String}
249
+ */
250
+ Owl.Type = {
251
+ Event: 'event',
252
+ State: 'state'
253
+ };
254
+
255
+ /**
256
+ * Contains all registered plugins.
257
+ * @public
258
+ */
259
+ Owl.Plugins = {};
260
+
261
+ /**
262
+ * List of workers involved in the update process.
263
+ */
264
+ Owl.Workers = [ {
265
+ filter: [ 'width', 'settings' ],
266
+ run: function() {
267
+ this._width = this.$element.width();
268
+ }
269
+ }, {
270
+ filter: [ 'width', 'items', 'settings' ],
271
+ run: function(cache) {
272
+ cache.current = this._items && this._items[this.relative(this._current)];
273
+ }
274
+ }, {
275
+ filter: [ 'items', 'settings' ],
276
+ run: function() {
277
+ this.$stage.children('.cloned').remove();
278
+ }
279
+ }, {
280
+ filter: [ 'width', 'items', 'settings' ],
281
+ run: function(cache) {
282
+ var margin = this.settings.margin || '',
283
+ grid = !this.settings.autoWidth,
284
+ rtl = this.settings.rtl,
285
+ css = {
286
+ 'width': 'auto',
287
+ 'margin-left': rtl ? margin : '',
288
+ 'margin-right': rtl ? '' : margin
289
+ };
290
+
291
+ !grid && this.$stage.children().css(css);
292
+
293
+ cache.css = css;
294
+ }
295
+ }, {
296
+ filter: [ 'width', 'items', 'settings' ],
297
+ run: function(cache) {
298
+ var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
299
+ merge = null,
300
+ iterator = this._items.length,
301
+ grid = !this.settings.autoWidth,
302
+ widths = [];
303
+
304
+ cache.items = {
305
+ merge: false,
306
+ width: width
307
+ };
308
+
309
+ while (iterator--) {
310
+ merge = this._mergers[iterator];
311
+ merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
312
+
313
+ cache.items.merge = merge > 1 || cache.items.merge;
314
+
315
+ widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
316
+ }
317
+
318
+ this._widths = widths;
319
+ }
320
+ }, {
321
+ filter: [ 'items', 'settings' ],
322
+ run: function() {
323
+ var clones = [],
324
+ items = this._items,
325
+ settings = this.settings,
326
+ // TODO: Should be computed from number of min width items in stage
327
+ view = Math.max(settings.items * 2, 4),
328
+ size = Math.ceil(items.length / 2) * 2,
329
+ repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
330
+ append = '',
331
+ prepend = '';
332
+
333
+ repeat /= 2;
334
+
335
+ while (repeat > 0) {
336
+ // Switch to only using appended clones
337
+ clones.push(this.normalize(clones.length / 2, true));
338
+ $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').appendTo(this.$stage);
339
+ clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
340
+ $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').prependTo(this.$stage);
341
+ repeat -= 1;
342
+ }
343
+ this._clones = clones;
344
+ }
345
+ }, {
346
+ filter: [ 'width', 'items', 'settings' ],
347
+ run: function() {
348
+ var rtl = this.settings.rtl ? 1 : -1,
349
+ size = this._clones.length + this._items.length,
350
+ iterator = -1,
351
+ previous = 0,
352
+ current = 0,
353
+ coordinates = [];
354
+
355
+ while (++iterator < size) {
356
+ previous = coordinates[iterator - 1] || 0;
357
+ current = this._widths[this.relative(iterator)] + this.settings.margin;
358
+ coordinates.push(previous + current * rtl);
359
+ }
360
+
361
+ this._coordinates = coordinates;
362
+ }
363
+ }, {
364
+ filter: [ 'width', 'items', 'settings' ],
365
+ run: function() {
366
+ var padding = this.settings.stagePadding,
367
+ coordinates = this._coordinates,
368
+ css = {
369
+ 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
370
+ 'padding-left': padding || '',
371
+ 'padding-right': padding || ''
372
+ };
373
+
374
+ this.$stage.css(css);
375
+ }
376
+ }, {
377
+ filter: [ 'width', 'items', 'settings' ],
378
+ run: function(cache) {
379
+ var iterator = this._coordinates.length,
380
+ grid = !this.settings.autoWidth,
381
+ items = this.$stage.children();
382
+
383
+ if (grid && cache.items.merge) {
384
+ while (iterator--) {
385
+ cache.css.width = this._widths[this.relative(iterator)];
386
+ items.eq(iterator).css(cache.css);
387
+ }
388
+ } else if (grid) {
389
+ cache.css.width = cache.items.width;
390
+ items.css(cache.css);
391
+ }
392
+ }
393
+ }, {
394
+ filter: [ 'items' ],
395
+ run: function() {
396
+ this._coordinates.length < 1 && this.$stage.removeAttr('style');
397
+ }
398
+ }, {
399
+ filter: [ 'width', 'items', 'settings' ],
400
+ run: function(cache) {
401
+ cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
402
+ cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
403
+ this.reset(cache.current);
404
+ }
405
+ }, {
406
+ filter: [ 'position' ],
407
+ run: function() {
408
+ this.animate(this.coordinates(this._current));
409
+ }
410
+ }, {
411
+ filter: [ 'width', 'position', 'items', 'settings' ],
412
+ run: function() {
413
+ var rtl = this.settings.rtl ? 1 : -1,
414
+ padding = this.settings.stagePadding * 2,
415
+ begin = this.coordinates(this.current()) + padding,
416
+ end = begin + this.width() * rtl,
417
+ inner, outer, matches = [], i, n;
418
+
419
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
420
+ inner = this._coordinates[i - 1] || 0;
421
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
422
+
423
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
424
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
425
+ matches.push(i);
426
+ }
427
+ }
428
+
429
+ this.$stage.children('.active').removeClass('active');
430
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
431
+
432
+ this.$stage.children('.center').removeClass('center');
433
+ if (this.settings.center) {
434
+ this.$stage.children().eq(this.current()).addClass('center');
435
+ }
436
+ }
437
+ } ];
438
+
439
+ /**
440
+ * Create the stage DOM element
441
+ */
442
+ Owl.prototype.initializeStage = function() {
443
+ this.$stage = this.$element.find('.' + this.settings.stageClass);
444
+
445
+ // if the stage is already in the DOM, grab it and skip stage initialization
446
+ if (this.$stage.length) {
447
+ return;
448
+ }
449
+
450
+ this.$element.addClass(this.options.loadingClass);
451
+
452
+ // create stage
453
+ this.$stage = $('<' + this.settings.stageElement + '>', {
454
+ "class": this.settings.stageClass
455
+ }).wrap( $( '<div/>', {
456
+ "class": this.settings.stageOuterClass
457
+ }));
458
+
459
+ // append stage
460
+ this.$element.append(this.$stage.parent());
461
+ };
462
+
463
+ /**
464
+ * Create item DOM elements
465
+ */
466
+ Owl.prototype.initializeItems = function() {
467
+ var $items = this.$element.find('.owl-item');
468
+
469
+ // if the items are already in the DOM, grab them and skip item initialization
470
+ if ($items.length) {
471
+ this._items = $items.get().map(function(item) {
472
+ return $(item);
473
+ });
474
+
475
+ this._mergers = this._items.map(function() {
476
+ return 1;
477
+ });
478
+
479
+ this.refresh();
480
+
481
+ return;
482
+ }
483
+
484
+ // append content
485
+ this.replace(this.$element.children().not(this.$stage.parent()));
486
+
487
+ // check visibility
488
+ if (this.isVisible()) {
489
+ // update view
490
+ this.refresh();
491
+ } else {
492
+ // invalidate width
493
+ this.invalidate('width');
494
+ }
495
+
496
+ this.$element
497
+ .removeClass(this.options.loadingClass)
498
+ .addClass(this.options.loadedClass);
499
+ };
500
+
501
+ /**
502
+ * Initializes the carousel.
503
+ * @protected
504
+ */
505
+ Owl.prototype.initialize = function() {
506
+ this.enter('initializing');
507
+ this.trigger('initialize');
508
+
509
+ this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
510
+
511
+ if (this.settings.autoWidth && !this.is('pre-loading')) {
512
+ var imgs, nestedSelector, width;
513
+ imgs = this.$element.find('img');
514
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
515
+ width = this.$element.children(nestedSelector).width();
516
+
517
+ if (imgs.length && width <= 0) {
518
+ this.preloadAutoWidthImages(imgs);
519
+ }
520
+ }
521
+
522
+ this.initializeStage();
523
+ this.initializeItems();
524
+
525
+ // register event handlers
526
+ this.registerEventHandlers();
527
+
528
+ this.leave('initializing');
529
+ this.trigger('initialized');
530
+ };
531
+
532
+ /**
533
+ * @returns {Boolean} visibility of $element
534
+ * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
535
+ * prevent the expensive browser layout forced reflow the $element.is(':visible') does
536
+ */
537
+ Owl.prototype.isVisible = function() {
538
+ return this.settings.checkVisibility
539
+ ? this.$element.is(':visible')
540
+ : true;
541
+ };
542
+
543
+ /**
544
+ * Setups the current settings.
545
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
546
+ * @todo Support for media queries by using `matchMedia` would be nice.
547
+ * @public
548
+ */
549
+ Owl.prototype.setup = function() {
550
+ var viewport = this.viewport(),
551
+ overwrites = this.options.responsive,
552
+ match = -1,
553
+ settings = null;
554
+
555
+ if (!overwrites) {
556
+ settings = $.extend({}, this.options);
557
+ } else {
558
+ $.each(overwrites, function(breakpoint) {
559
+ if (breakpoint <= viewport && breakpoint > match) {
560
+ match = Number(breakpoint);
561
+ }
562
+ });
563
+
564
+ settings = $.extend({}, this.options, overwrites[match]);
565
+ if (typeof settings.stagePadding === 'function') {
566
+ settings.stagePadding = settings.stagePadding();
567
+ }
568
+ delete settings.responsive;
569
+
570
+ // responsive class
571
+ if (settings.responsiveClass) {
572
+ this.$element.attr('class',
573
+ this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
574
+ );
575
+ }
576
+ }
577
+
578
+ this.trigger('change', { property: { name: 'settings', value: settings } });
579
+ this._breakpoint = match;
580
+ this.settings = settings;
581
+ this.invalidate('settings');
582
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
583
+ };
584
+
585
+ /**
586
+ * Updates option logic if necessery.
587
+ * @protected
588
+ */
589
+ Owl.prototype.optionsLogic = function() {
590
+ if (this.settings.autoWidth) {
591
+ this.settings.stagePadding = false;
592
+ this.settings.merge = false;
593
+ }
594
+ };
595
+
596
+ /**
597
+ * Prepares an item before add.
598
+ * @todo Rename event parameter `content` to `item`.
599
+ * @protected
600
+ * @returns {jQuery|HTMLElement} - The item container.
601
+ */
602
+ Owl.prototype.prepare = function(item) {
603
+ var event = this.trigger('prepare', { content: item });
604
+
605
+ if (!event.data) {
606
+ event.data = $('<' + this.settings.itemElement + '/>')
607
+ .addClass(this.options.itemClass).append(item)
608
+ }
609
+
610
+ this.trigger('prepared', { content: event.data });
611
+
612
+ return event.data;
613
+ };
614
+
615
+ /**
616
+ * Updates the view.
617
+ * @public
618
+ */
619
+ Owl.prototype.update = function() {
620
+ var i = 0,
621
+ n = this._pipe.length,
622
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
623
+ cache = {};
624
+
625
+ while (i < n) {
626
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
627
+ this._pipe[i].run(cache);
628
+ }
629
+ i++;
630
+ }
631
+
632
+ this._invalidated = {};
633
+
634
+ !this.is('valid') && this.enter('valid');
635
+ };
636
+
637
+ /**
638
+ * Gets the width of the view.
639
+ * @public
640
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
641
+ * @returns {Number} - The width of the view in pixel.
642
+ */
643
+ Owl.prototype.width = function(dimension) {
644
+ dimension = dimension || Owl.Width.Default;
645
+ switch (dimension) {
646
+ case Owl.Width.Inner:
647
+ case Owl.Width.Outer:
648
+ return this._width;
649
+ default:
650
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
651
+ }
652
+ };
653
+
654
+ /**
655
+ * Refreshes the carousel primarily for adaptive purposes.
656
+ * @public
657
+ */
658
+ Owl.prototype.refresh = function(resizing) {
659
+ resizing = resizing || false;
660
+
661
+ this.enter('refreshing');
662
+ this.trigger('refresh');
663
+
664
+ this.setup();
665
+
666
+ this.optionsLogic();
667
+
668
+ this.$element.addClass(this.options.refreshClass);
669
+
670
+ this.update();
671
+
672
+ if (!resizing) {
673
+ this.onResize();
674
+ }
675
+
676
+ this.$element.removeClass(this.options.refreshClass);
677
+
678
+ this.leave('refreshing');
679
+ this.trigger('refreshed');
680
+ };
681
+
682
+ /**
683
+ * Checks window `resize` event.
684
+ * @protected
685
+ */
686
+ Owl.prototype.onThrottledResize = function() {
687
+ window.clearTimeout(this.resizeTimer);
688
+ this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
689
+ };
690
+
691
+ /**
692
+ * Checks window `resize` event.
693
+ * @protected
694
+ */
695
+ Owl.prototype.onResize = function() {
696
+ var resizing = true;
697
+
698
+ if (!this._items.length) {
699
+ return false;
700
+ }
701
+
702
+ if (this._width === this.$element.width()) {
703
+ return false;
704
+ }
705
+
706
+ if (!this.isVisible()) {
707
+ return false;
708
+ }
709
+
710
+ this.enter('resizing');
711
+
712
+ if (this.trigger('resize').isDefaultPrevented()) {
713
+ this.leave('resizing');
714
+ return false;
715
+ }
716
+
717
+ this.invalidate('width');
718
+
719
+ this.refresh(resizing);
720
+
721
+ this.leave('resizing');
722
+ this.trigger('resized');
723
+ };
724
+
725
+ /**
726
+ * Registers event handlers.
727
+ * @todo Check `msPointerEnabled`
728
+ * @todo #261
729
+ * @protected
730
+ */
731
+ Owl.prototype.registerEventHandlers = function() {
732
+ if ($.support.transition) {
733
+ this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
734
+ }
735
+
736
+ if (this.settings.responsive !== false) {
737
+ this.on(window, 'resize', this._handlers.onThrottledResize);
738
+ }
739
+
740
+ if (this.settings.mouseDrag) {
741
+ this.$element.addClass(this.options.dragClass);
742
+ this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
743
+ this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
744
+ }
745
+
746
+ if (this.settings.touchDrag){
747
+ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
748
+ this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
749
+ }
750
+ };
751
+
752
+ /**
753
+ * Handles `touchstart` and `mousedown` events.
754
+ * @todo Horizontal swipe threshold as option
755
+ * @todo #261
756
+ * @protected
757
+ * @param {Event} event - The event arguments.
758
+ */
759
+ Owl.prototype.onDragStart = function(event) {
760
+ var stage = null;
761
+
762
+ if (event.which === 3) {
763
+ return;
764
+ }
765
+
766
+ if ($.support.transform) {
767
+ stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
768
+ stage = {
769
+ x: stage[stage.length === 16 ? 12 : 4],
770
+ y: stage[stage.length === 16 ? 13 : 5]
771
+ };
772
+ } else {
773
+ stage = this.$stage.position();
774
+ stage = {
775
+ x: this.settings.rtl ?
776
+ stage.left + this.$stage.width() - this.width() + this.settings.margin :
777
+ stage.left,
778
+ y: stage.top
779
+ };
780
+ }
781
+
782
+ if (this.is('animating')) {
783
+ $.support.transform ? this.animate(stage.x) : this.$stage.stop()
784
+ this.invalidate('position');
785
+ }
786
+
787
+ this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
788
+
789
+ this.speed(0);
790
+
791
+ this._drag.time = new Date().getTime();
792
+ this._drag.target = $(event.target);
793
+ this._drag.stage.start = stage;
794
+ this._drag.stage.current = stage;
795
+ this._drag.pointer = this.pointer(event);
796
+
797
+ $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
798
+
799
+ $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
800
+ var delta = this.difference(this._drag.pointer, this.pointer(event));
801
+
802
+ $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
803
+
804
+ if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
805
+ return;
806
+ }
807
+
808
+ event.preventDefault();
809
+
810
+ this.enter('dragging');
811
+ this.trigger('drag');
812
+ }, this));
813
+ };
814
+
815
+ /**
816
+ * Handles the `touchmove` and `mousemove` events.
817
+ * @todo #261
818
+ * @protected
819
+ * @param {Event} event - The event arguments.
820
+ */
821
+ Owl.prototype.onDragMove = function(event) {
822
+ var minimum = null,
823
+ maximum = null,
824
+ pull = null,
825
+ delta = this.difference(this._drag.pointer, this.pointer(event)),
826
+ stage = this.difference(this._drag.stage.start, delta);
827
+
828
+ if (!this.is('dragging')) {
829
+ return;
830
+ }
831
+
832
+ event.preventDefault();
833
+
834
+ if (this.settings.loop) {
835
+ minimum = this.coordinates(this.minimum());
836
+ maximum = this.coordinates(this.maximum() + 1) - minimum;
837
+ stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
838
+ } else {
839
+ minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
840
+ maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
841
+ pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
842
+ stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
843
+ }
844
+
845
+ this._drag.stage.current = stage;
846
+
847
+ this.animate(stage.x);
848
+ };
849
+
850
+ /**
851
+ * Handles the `touchend` and `mouseup` events.
852
+ * @todo #261
853
+ * @todo Threshold for click event
854
+ * @protected
855
+ * @param {Event} event - The event arguments.
856
+ */
857
+ Owl.prototype.onDragEnd = function(event) {
858
+ var delta = this.difference(this._drag.pointer, this.pointer(event)),
859
+ stage = this._drag.stage.current,
860
+ direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
861
+
862
+ $(document).off('.owl.core');
863
+
864
+ this.$element.removeClass(this.options.grabClass);
865
+
866
+ if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
867
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
868
+ this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
869
+ this.invalidate('position');
870
+ this.update();
871
+
872
+ this._drag.direction = direction;
873
+
874
+ if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
875
+ this._drag.target.one('click.owl.core', function() { return false; });
876
+ }
877
+ }
878
+
879
+ if (!this.is('dragging')) {
880
+ return;
881
+ }
882
+
883
+ this.leave('dragging');
884
+ this.trigger('dragged');
885
+ };
886
+
887
+ /**
888
+ * Gets absolute position of the closest item for a coordinate.
889
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
890
+ * @protected
891
+ * @param {Number} coordinate - The coordinate in pixel.
892
+ * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
893
+ * @return {Number} - The absolute position of the closest item.
894
+ */
895
+ Owl.prototype.closest = function(coordinate, direction) {
896
+ var position = -1,
897
+ pull = 30,
898
+ width = this.width(), // visible carousel width
899
+ count = this.settings.items,
900
+ itemWidth = Math.round(width / count),
901
+ coordinates = this.coordinates();
902
+
903
+ if (!this.settings.freeDrag) {
904
+ // check closest item
905
+ $.each(coordinates, $.proxy(function(index, value) {
906
+ // on a left pull, check on current index
907
+ if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
908
+ position = index;
909
+ // on a right pull, check on previous index
910
+ // to do so, subtract width from value and set position = index + 1
911
+ } else if (direction === 'right' && coordinate > value - itemWidth - pull && coordinate < value - itemWidth + pull) {
912
+ position = index + 1;
913
+ } else if (this.op(coordinate, '<', value)
914
+ && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
915
+ position = direction === 'left' ? index + 1 : index;
916
+ }
917
+ return position === -1;
918
+ }, this));
919
+ }
920
+
921
+ if (!this.settings.loop) {
922
+ // non loop boundries
923
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
924
+ position = coordinate = this.minimum();
925
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
926
+ position = coordinate = this.maximum();
927
+ }
928
+ }
929
+
930
+ return position;
931
+ };
932
+
933
+ /**
934
+ * Animates the stage.
935
+ * @todo #270
936
+ * @public
937
+ * @param {Number} coordinate - The coordinate in pixels.
938
+ */
939
+ Owl.prototype.animate = function(coordinate) {
940
+ var animate = this.speed() > 0;
941
+
942
+ this.is('animating') && this.onTransitionEnd();
943
+
944
+ if (animate) {
945
+ this.enter('animating');
946
+ this.trigger('translate');
947
+ }
948
+
949
+ if ($.support.transform3d && $.support.transition) {
950
+ this.$stage.css({
951
+ transform: 'translate3d(' + coordinate + 'px,0px,0px)',
952
+ transition: (this.speed() / 1000) + 's' + (
953
+ this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
954
+ )
955
+ });
956
+ } else if (animate) {
957
+ this.$stage.animate({
958
+ left: coordinate + 'px'
959
+ }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
960
+ } else {
961
+ this.$stage.css({
962
+ left: coordinate + 'px'
963
+ });
964
+ }
965
+ };
966
+
967
+ /**
968
+ * Checks whether the carousel is in a specific state or not.
969
+ * @param {String} state - The state to check.
970
+ * @returns {Boolean} - The flag which indicates if the carousel is busy.
971
+ */
972
+ Owl.prototype.is = function(state) {
973
+ return this._states.current[state] && this._states.current[state] > 0;
974
+ };
975
+
976
+ /**
977
+ * Sets the absolute position of the current item.
978
+ * @public
979
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
980
+ * @returns {Number} - The absolute position of the current item.
981
+ */
982
+ Owl.prototype.current = function(position) {
983
+ if (position === undefined) {
984
+ return this._current;
985
+ }
986
+
987
+ if (this._items.length === 0) {
988
+ return undefined;
989
+ }
990
+
991
+ position = this.normalize(position);
992
+
993
+ if (this._current !== position) {
994
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
995
+
996
+ if (event.data !== undefined) {
997
+ position = this.normalize(event.data);
998
+ }
999
+
1000
+ this._current = position;
1001
+
1002
+ this.invalidate('position');
1003
+
1004
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
1005
+ }
1006
+
1007
+ return this._current;
1008
+ };
1009
+
1010
+ /**
1011
+ * Invalidates the given part of the update routine.
1012
+ * @param {String} [part] - The part to invalidate.
1013
+ * @returns {Array.<String>} - The invalidated parts.
1014
+ */
1015
+ Owl.prototype.invalidate = function(part) {
1016
+ if ($.type(part) === 'string') {
1017
+ this._invalidated[part] = true;
1018
+ this.is('valid') && this.leave('valid');
1019
+ }
1020
+ return $.map(this._invalidated, function(v, i) { return i });
1021
+ };
1022
+
1023
+ /**
1024
+ * Resets the absolute position of the current item.
1025
+ * @public
1026
+ * @param {Number} position - The absolute position of the new item.
1027
+ */
1028
+ Owl.prototype.reset = function(position) {
1029
+ position = this.normalize(position);
1030
+
1031
+ if (position === undefined) {
1032
+ return;
1033
+ }
1034
+
1035
+ this._speed = 0;
1036
+ this._current = position;
1037
+
1038
+ this.suppress([ 'translate', 'translated' ]);
1039
+
1040
+ this.animate(this.coordinates(position));
1041
+
1042
+ this.release([ 'translate', 'translated' ]);
1043
+ };
1044
+
1045
+ /**
1046
+ * Normalizes an absolute or a relative position of an item.
1047
+ * @public
1048
+ * @param {Number} position - The absolute or relative position to normalize.
1049
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
1050
+ * @returns {Number} - The normalized position.
1051
+ */
1052
+ Owl.prototype.normalize = function(position, relative) {
1053
+ var n = this._items.length,
1054
+ m = relative ? 0 : this._clones.length;
1055
+
1056
+ if (!this.isNumeric(position) || n < 1) {
1057
+ position = undefined;
1058
+ } else if (position < 0 || position >= n + m) {
1059
+ position = ((position - m / 2) % n + n) % n + m / 2;
1060
+ }
1061
+
1062
+ return position;
1063
+ };
1064
+
1065
+ /**
1066
+ * Converts an absolute position of an item into a relative one.
1067
+ * @public
1068
+ * @param {Number} position - The absolute position to convert.
1069
+ * @returns {Number} - The converted position.
1070
+ */
1071
+ Owl.prototype.relative = function(position) {
1072
+ position -= this._clones.length / 2;
1073
+ return this.normalize(position, true);
1074
+ };
1075
+
1076
+ /**
1077
+ * Gets the maximum position for the current item.
1078
+ * @public
1079
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1080
+ * @returns {Number}
1081
+ */
1082
+ Owl.prototype.maximum = function(relative) {
1083
+ var settings = this.settings,
1084
+ maximum = this._coordinates.length,
1085
+ iterator,
1086
+ reciprocalItemsWidth,
1087
+ elementWidth;
1088
+
1089
+ if (settings.loop) {
1090
+ maximum = this._clones.length / 2 + this._items.length - 1;
1091
+ } else if (settings.autoWidth || settings.merge) {
1092
+ iterator = this._items.length;
1093
+ if (iterator) {
1094
+ reciprocalItemsWidth = this._items[--iterator].width();
1095
+ elementWidth = this.$element.width();
1096
+ while (iterator--) {
1097
+ reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
1098
+ if (reciprocalItemsWidth > elementWidth) {
1099
+ break;
1100
+ }
1101
+ }
1102
+ }
1103
+ maximum = iterator + 1;
1104
+ } else if (settings.center) {
1105
+ maximum = this._items.length - 1;
1106
+ } else {
1107
+ maximum = this._items.length - settings.items;
1108
+ }
1109
+
1110
+ if (relative) {
1111
+ maximum -= this._clones.length / 2;
1112
+ }
1113
+
1114
+ return Math.max(maximum, 0);
1115
+ };
1116
+
1117
+ /**
1118
+ * Gets the minimum position for the current item.
1119
+ * @public
1120
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1121
+ * @returns {Number}
1122
+ */
1123
+ Owl.prototype.minimum = function(relative) {
1124
+ return relative ? 0 : this._clones.length / 2;
1125
+ };
1126
+
1127
+ /**
1128
+ * Gets an item at the specified relative position.
1129
+ * @public
1130
+ * @param {Number} [position] - The relative position of the item.
1131
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1132
+ */
1133
+ Owl.prototype.items = function(position) {
1134
+ if (position === undefined) {
1135
+ return this._items.slice();
1136
+ }
1137
+
1138
+ position = this.normalize(position, true);
1139
+ return this._items[position];
1140
+ };
1141
+
1142
+ /**
1143
+ * Gets an item at the specified relative position.
1144
+ * @public
1145
+ * @param {Number} [position] - The relative position of the item.
1146
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1147
+ */
1148
+ Owl.prototype.mergers = function(position) {
1149
+ if (position === undefined) {
1150
+ return this._mergers.slice();
1151
+ }
1152
+
1153
+ position = this.normalize(position, true);
1154
+ return this._mergers[position];
1155
+ };
1156
+
1157
+ /**
1158
+ * Gets the absolute positions of clones for an item.
1159
+ * @public
1160
+ * @param {Number} [position] - The relative position of the item.
1161
+ * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
1162
+ */
1163
+ Owl.prototype.clones = function(position) {
1164
+ var odd = this._clones.length / 2,
1165
+ even = odd + this._items.length,
1166
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
1167
+
1168
+ if (position === undefined) {
1169
+ return $.map(this._clones, function(v, i) { return map(i) });
1170
+ }
1171
+
1172
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
1173
+ };
1174
+
1175
+ /**
1176
+ * Sets the current animation speed.
1177
+ * @public
1178
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
1179
+ * @returns {Number} - The current animation speed in milliseconds.
1180
+ */
1181
+ Owl.prototype.speed = function(speed) {
1182
+ if (speed !== undefined) {
1183
+ this._speed = speed;
1184
+ }
1185
+
1186
+ return this._speed;
1187
+ };
1188
+
1189
+ /**
1190
+ * Gets the coordinate of an item.
1191
+ * @todo The name of this method is missleanding.
1192
+ * @public
1193
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
1194
+ * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
1195
+ */
1196
+ Owl.prototype.coordinates = function(position) {
1197
+ var multiplier = 1,
1198
+ newPosition = position - 1,
1199
+ coordinate;
1200
+
1201
+ if (position === undefined) {
1202
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
1203
+ return this.coordinates(index);
1204
+ }, this));
1205
+ }
1206
+
1207
+ if (this.settings.center) {
1208
+ if (this.settings.rtl) {
1209
+ multiplier = -1;
1210
+ newPosition = position + 1;
1211
+ }
1212
+
1213
+ coordinate = this._coordinates[position];
1214
+ coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
1215
+ } else {
1216
+ coordinate = this._coordinates[newPosition] || 0;
1217
+ }
1218
+
1219
+ coordinate = Math.ceil(coordinate);
1220
+
1221
+ return coordinate;
1222
+ };
1223
+
1224
+ /**
1225
+ * Calculates the speed for a translation.
1226
+ * @protected
1227
+ * @param {Number} from - The absolute position of the start item.
1228
+ * @param {Number} to - The absolute position of the target item.
1229
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
1230
+ * @returns {Number} - The time in milliseconds for the translation.
1231
+ */
1232
+ Owl.prototype.duration = function(from, to, factor) {
1233
+ if (factor === 0) {
1234
+ return 0;
1235
+ }
1236
+
1237
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
1238
+ };
1239
+
1240
+ /**
1241
+ * Slides to the specified item.
1242
+ * @public
1243
+ * @param {Number} position - The position of the item.
1244
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1245
+ */
1246
+ Owl.prototype.to = function(position, speed) {
1247
+ var current = this.current(),
1248
+ revert = null,
1249
+ distance = position - this.relative(current),
1250
+ direction = (distance > 0) - (distance < 0),
1251
+ items = this._items.length,
1252
+ minimum = this.minimum(),
1253
+ maximum = this.maximum();
1254
+
1255
+ if (this.settings.loop) {
1256
+ if (!this.settings.rewind && Math.abs(distance) > items / 2) {
1257
+ distance += direction * -1 * items;
1258
+ }
1259
+
1260
+ position = current + distance;
1261
+ revert = ((position - minimum) % items + items) % items + minimum;
1262
+
1263
+ if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
1264
+ current = revert - distance;
1265
+ position = revert;
1266
+ this.reset(current);
1267
+ }
1268
+ } else if (this.settings.rewind) {
1269
+ maximum += 1;
1270
+ position = (position % maximum + maximum) % maximum;
1271
+ } else {
1272
+ position = Math.max(minimum, Math.min(maximum, position));
1273
+ }
1274
+
1275
+ this.speed(this.duration(current, position, speed));
1276
+ this.current(position);
1277
+
1278
+ if (this.isVisible()) {
1279
+ this.update();
1280
+ }
1281
+ };
1282
+
1283
+ /**
1284
+ * Slides to the next item.
1285
+ * @public
1286
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1287
+ */
1288
+ Owl.prototype.next = function(speed) {
1289
+ speed = speed || false;
1290
+ this.to(this.relative(this.current()) + 1, speed);
1291
+ };
1292
+
1293
+ /**
1294
+ * Slides to the previous item.
1295
+ * @public
1296
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1297
+ */
1298
+ Owl.prototype.prev = function(speed) {
1299
+ speed = speed || false;
1300
+ this.to(this.relative(this.current()) - 1, speed);
1301
+ };
1302
+
1303
+ /**
1304
+ * Handles the end of an animation.
1305
+ * @protected
1306
+ * @param {Event} event - The event arguments.
1307
+ */
1308
+ Owl.prototype.onTransitionEnd = function(event) {
1309
+
1310
+ // if css2 animation then event object is undefined
1311
+ if (event !== undefined) {
1312
+ event.stopPropagation();
1313
+
1314
+ // Catch only owl-stage transitionEnd event
1315
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
1316
+ return false;
1317
+ }
1318
+ }
1319
+
1320
+ this.leave('animating');
1321
+ this.trigger('translated');
1322
+ };
1323
+
1324
+ /**
1325
+ * Gets viewport width.
1326
+ * @protected
1327
+ * @return {Number} - The width in pixel.
1328
+ */
1329
+ Owl.prototype.viewport = function() {
1330
+ var width;
1331
+ if (this.options.responsiveBaseElement !== window) {
1332
+ width = $(this.options.responsiveBaseElement).width();
1333
+ } else if (window.innerWidth) {
1334
+ width = window.innerWidth;
1335
+ } else if (document.documentElement && document.documentElement.clientWidth) {
1336
+ width = document.documentElement.clientWidth;
1337
+ } else {
1338
+ console.warn('Can not detect viewport width.');
1339
+ }
1340
+ return width;
1341
+ };
1342
+
1343
+ /**
1344
+ * Replaces the current content.
1345
+ * @public
1346
+ * @param {HTMLElement|jQuery|String} content - The new content.
1347
+ */
1348
+ Owl.prototype.replace = function(content) {
1349
+ this.$stage.empty();
1350
+ this._items = [];
1351
+
1352
+ if (content) {
1353
+ content = (content instanceof jQuery) ? content : $(content);
1354
+ }
1355
+
1356
+ if (this.settings.nestedItemSelector) {
1357
+ content = content.find('.' + this.settings.nestedItemSelector);
1358
+ }
1359
+
1360
+ content.filter(function() {
1361
+ return this.nodeType === 1;
1362
+ }).each($.proxy(function(index, item) {
1363
+ item = this.prepare(item);
1364
+ this.$stage.append(item);
1365
+ this._items.push(item);
1366
+ this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1367
+ }, this));
1368
+
1369
+ this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
1370
+
1371
+ this.invalidate('items');
1372
+ };
1373
+
1374
+ /**
1375
+ * Adds an item.
1376
+ * @todo Use `item` instead of `content` for the event arguments.
1377
+ * @public
1378
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
1379
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
1380
+ */
1381
+ Owl.prototype.add = function(content, position) {
1382
+ var current = this.relative(this._current);
1383
+
1384
+ position = position === undefined ? this._items.length : this.normalize(position, true);
1385
+ content = content instanceof jQuery ? content : $(content);
1386
+
1387
+ this.trigger('add', { content: content, position: position });
1388
+
1389
+ content = this.prepare(content);
1390
+
1391
+ if (this._items.length === 0 || position === this._items.length) {
1392
+ this._items.length === 0 && this.$stage.append(content);
1393
+ this._items.length !== 0 && this._items[position - 1].after(content);
1394
+ this._items.push(content);
1395
+ this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1396
+ } else {
1397
+ this._items[position].before(content);
1398
+ this._items.splice(position, 0, content);
1399
+ this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1400
+ }
1401
+
1402
+ this._items[current] && this.reset(this._items[current].index());
1403
+
1404
+ this.invalidate('items');
1405
+
1406
+ this.trigger('added', { content: content, position: position });
1407
+ };
1408
+
1409
+ /**
1410
+ * Removes an item by its position.
1411
+ * @todo Use `item` instead of `content` for the event arguments.
1412
+ * @public
1413
+ * @param {Number} position - The relative position of the item to remove.
1414
+ */
1415
+ Owl.prototype.remove = function(position) {
1416
+ position = this.normalize(position, true);
1417
+
1418
+ if (position === undefined) {
1419
+ return;
1420
+ }
1421
+
1422
+ this.trigger('remove', { content: this._items[position], position: position });
1423
+
1424
+ this._items[position].remove();
1425
+ this._items.splice(position, 1);
1426
+ this._mergers.splice(position, 1);
1427
+
1428
+ this.invalidate('items');
1429
+
1430
+ this.trigger('removed', { content: null, position: position });
1431
+ };
1432
+
1433
+ /**
1434
+ * Preloads images with auto width.
1435
+ * @todo Replace by a more generic approach
1436
+ * @protected
1437
+ */
1438
+ Owl.prototype.preloadAutoWidthImages = function(images) {
1439
+ images.each($.proxy(function(i, element) {
1440
+ this.enter('pre-loading');
1441
+ element = $(element);
1442
+ $(new Image()).one('load', $.proxy(function(e) {
1443
+ element.attr('src', e.target.src);
1444
+ element.css('opacity', 1);
1445
+ this.leave('pre-loading');
1446
+ !this.is('pre-loading') && !this.is('initializing') && this.refresh();
1447
+ }, this)).attr('src', (window.devicePixelRatio > 1) ? element.attr('data-src-retina') : element.attr('data-src') || element.attr('src'));
1448
+ }, this));
1449
+ };
1450
+
1451
+ /**
1452
+ * Destroys the carousel.
1453
+ * @public
1454
+ */
1455
+ Owl.prototype.destroy = function() {
1456
+
1457
+ this.$element.off('.owl.core');
1458
+ this.$stage.off('.owl.core');
1459
+ $(document).off('.owl.core');
1460
+
1461
+ if (this.settings.responsive !== false) {
1462
+ window.clearTimeout(this.resizeTimer);
1463
+ this.off(window, 'resize', this._handlers.onThrottledResize);
1464
+ }
1465
+
1466
+ for (var i in this._plugins) {
1467
+ this._plugins[i].destroy();
1468
+ }
1469
+
1470
+ this.$stage.children('.cloned').remove();
1471
+
1472
+ this.$stage.unwrap();
1473
+ this.$stage.children().contents().unwrap();
1474
+ this.$stage.children().unwrap();
1475
+ this.$stage.remove();
1476
+ this.$element
1477
+ .removeClass(this.options.refreshClass)
1478
+ .removeClass(this.options.loadingClass)
1479
+ .removeClass(this.options.loadedClass)
1480
+ .removeClass(this.options.rtlClass)
1481
+ .removeClass(this.options.dragClass)
1482
+ .removeClass(this.options.grabClass)
1483
+ .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
1484
+ .removeData('owl.carousel');
1485
+ };
1486
+
1487
+ /**
1488
+ * Operators to calculate right-to-left and left-to-right.
1489
+ * @protected
1490
+ * @param {Number} [a] - The left side operand.
1491
+ * @param {String} [o] - The operator.
1492
+ * @param {Number} [b] - The right side operand.
1493
+ */
1494
+ Owl.prototype.op = function(a, o, b) {
1495
+ var rtl = this.settings.rtl;
1496
+ switch (o) {
1497
+ case '<':
1498
+ return rtl ? a > b : a < b;
1499
+ case '>':
1500
+ return rtl ? a < b : a > b;
1501
+ case '>=':
1502
+ return rtl ? a <= b : a >= b;
1503
+ case '<=':
1504
+ return rtl ? a >= b : a <= b;
1505
+ default:
1506
+ break;
1507
+ }
1508
+ };
1509
+
1510
+ /**
1511
+ * Attaches to an internal event.
1512
+ * @protected
1513
+ * @param {HTMLElement} element - The event source.
1514
+ * @param {String} event - The event name.
1515
+ * @param {Function} listener - The event handler to attach.
1516
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
1517
+ */
1518
+ Owl.prototype.on = function(element, event, listener, capture) {
1519
+ if (element.addEventListener) {
1520
+ element.addEventListener(event, listener, capture);
1521
+ } else if (element.attachEvent) {
1522
+ element.attachEvent('on' + event, listener);
1523
+ }
1524
+ };
1525
+
1526
+ /**
1527
+ * Detaches from an internal event.
1528
+ * @protected
1529
+ * @param {HTMLElement} element - The event source.
1530
+ * @param {String} event - The event name.
1531
+ * @param {Function} listener - The attached event handler to detach.
1532
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
1533
+ */
1534
+ Owl.prototype.off = function(element, event, listener, capture) {
1535
+ if (element.removeEventListener) {
1536
+ element.removeEventListener(event, listener, capture);
1537
+ } else if (element.detachEvent) {
1538
+ element.detachEvent('on' + event, listener);
1539
+ }
1540
+ };
1541
+
1542
+ /**
1543
+ * Triggers a public event.
1544
+ * @todo Remove `status`, `relatedTarget` should be used instead.
1545
+ * @protected
1546
+ * @param {String} name - The event name.
1547
+ * @param {*} [data=null] - The event data.
1548
+ * @param {String} [namespace=carousel] - The event namespace.
1549
+ * @param {String} [state] - The state which is associated with the event.
1550
+ * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
1551
+ * @returns {Event} - The event arguments.
1552
+ */
1553
+ Owl.prototype.trigger = function(name, data, namespace, state, enter) {
1554
+ var status = {
1555
+ item: { count: this._items.length, index: this.current() }
1556
+ }, handler = $.camelCase(
1557
+ $.grep([ 'on', name, namespace ], function(v) { return v })
1558
+ .join('-').toLowerCase()
1559
+ ), event = $.Event(
1560
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
1561
+ $.extend({ relatedTarget: this }, status, data)
1562
+ );
1563
+
1564
+ if (!this._supress[name]) {
1565
+ $.each(this._plugins, function(name, plugin) {
1566
+ if (plugin.onTrigger) {
1567
+ plugin.onTrigger(event);
1568
+ }
1569
+ });
1570
+
1571
+ this.register({ type: Owl.Type.Event, name: name });
1572
+ this.$element.trigger(event);
1573
+
1574
+ if (this.settings && typeof this.settings[handler] === 'function') {
1575
+ this.settings[handler].call(this, event);
1576
+ }
1577
+ }
1578
+
1579
+ return event;
1580
+ };
1581
+
1582
+ /**
1583
+ * Enters a state.
1584
+ * @param name - The state name.
1585
+ */
1586
+ Owl.prototype.enter = function(name) {
1587
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1588
+ if (this._states.current[name] === undefined) {
1589
+ this._states.current[name] = 0;
1590
+ }
1591
+
1592
+ this._states.current[name]++;
1593
+ }, this));
1594
+ };
1595
+
1596
+ /**
1597
+ * Leaves a state.
1598
+ * @param name - The state name.
1599
+ */
1600
+ Owl.prototype.leave = function(name) {
1601
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1602
+ this._states.current[name]--;
1603
+ }, this));
1604
+ };
1605
+
1606
+ /**
1607
+ * Registers an event or state.
1608
+ * @public
1609
+ * @param {Object} object - The event or state to register.
1610
+ */
1611
+ Owl.prototype.register = function(object) {
1612
+ if (object.type === Owl.Type.Event) {
1613
+ if (!$.event.special[object.name]) {
1614
+ $.event.special[object.name] = {};
1615
+ }
1616
+
1617
+ if (!$.event.special[object.name].owl) {
1618
+ var _default = $.event.special[object.name]._default;
1619
+ $.event.special[object.name]._default = function(e) {
1620
+ if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
1621
+ return _default.apply(this, arguments);
1622
+ }
1623
+ return e.namespace && e.namespace.indexOf('owl') > -1;
1624
+ };
1625
+ $.event.special[object.name].owl = true;
1626
+ }
1627
+ } else if (object.type === Owl.Type.State) {
1628
+ if (!this._states.tags[object.name]) {
1629
+ this._states.tags[object.name] = object.tags;
1630
+ } else {
1631
+ this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
1632
+ }
1633
+
1634
+ this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
1635
+ return $.inArray(tag, this._states.tags[object.name]) === i;
1636
+ }, this));
1637
+ }
1638
+ };
1639
+
1640
+ /**
1641
+ * Suppresses events.
1642
+ * @protected
1643
+ * @param {Array.<String>} events - The events to suppress.
1644
+ */
1645
+ Owl.prototype.suppress = function(events) {
1646
+ $.each(events, $.proxy(function(index, event) {
1647
+ this._supress[event] = true;
1648
+ }, this));
1649
+ };
1650
+
1651
+ /**
1652
+ * Releases suppressed events.
1653
+ * @protected
1654
+ * @param {Array.<String>} events - The events to release.
1655
+ */
1656
+ Owl.prototype.release = function(events) {
1657
+ $.each(events, $.proxy(function(index, event) {
1658
+ delete this._supress[event];
1659
+ }, this));
1660
+ };
1661
+
1662
+ /**
1663
+ * Gets unified pointer coordinates from event.
1664
+ * @todo #261
1665
+ * @protected
1666
+ * @param {Event} - The `mousedown` or `touchstart` event.
1667
+ * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
1668
+ */
1669
+ Owl.prototype.pointer = function(event) {
1670
+ var result = { x: null, y: null };
1671
+
1672
+ event = event.originalEvent || event || window.event;
1673
+
1674
+ event = event.touches && event.touches.length ?
1675
+ event.touches[0] : event.changedTouches && event.changedTouches.length ?
1676
+ event.changedTouches[0] : event;
1677
+
1678
+ if (event.pageX) {
1679
+ result.x = event.pageX;
1680
+ result.y = event.pageY;
1681
+ } else {
1682
+ result.x = event.clientX;
1683
+ result.y = event.clientY;
1684
+ }
1685
+
1686
+ return result;
1687
+ };
1688
+
1689
+ /**
1690
+ * Determines if the input is a Number or something that can be coerced to a Number
1691
+ * @protected
1692
+ * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
1693
+ * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
1694
+ */
1695
+ Owl.prototype.isNumeric = function(number) {
1696
+ return !isNaN(parseFloat(number));
1697
+ };
1698
+
1699
+ /**
1700
+ * Gets the difference of two vectors.
1701
+ * @todo #261
1702
+ * @protected
1703
+ * @param {Object} - The first vector.
1704
+ * @param {Object} - The second vector.
1705
+ * @returns {Object} - The difference.
1706
+ */
1707
+ Owl.prototype.difference = function(first, second) {
1708
+ return {
1709
+ x: first.x - second.x,
1710
+ y: first.y - second.y
1711
+ };
1712
+ };
1713
+
1714
+ /**
1715
+ * The jQuery Plugin for the Owl Carousel
1716
+ * @todo Navigation plugin `next` and `prev`
1717
+ * @public
1718
+ */
1719
+ $.fn.owlCarousel = function(option) {
1720
+ var args = Array.prototype.slice.call(arguments, 1);
1721
+
1722
+ return this.each(function() {
1723
+ var $this = $(this),
1724
+ data = $this.data('owl.carousel');
1725
+
1726
+ if (!data) {
1727
+ data = new Owl(this, typeof option == 'object' && option);
1728
+ $this.data('owl.carousel', data);
1729
+
1730
+ $.each([
1731
+ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
1732
+ ], function(i, event) {
1733
+ data.register({ type: Owl.Type.Event, name: event });
1734
+ data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
1735
+ if (e.namespace && e.relatedTarget !== this) {
1736
+ this.suppress([ event ]);
1737
+ data[event].apply(this, [].slice.call(arguments, 1));
1738
+ this.release([ event ]);
1739
+ }
1740
+ }, data));
1741
+ });
1742
+ }
1743
+
1744
+ if (typeof option == 'string' && option.charAt(0) !== '_') {
1745
+ data[option].apply(data, args);
1746
+ }
1747
+ });
1748
+ };
1749
+
1750
+ /**
1751
+ * The constructor for the jQuery Plugin
1752
+ * @public
1753
+ */
1754
+ $.fn.owlCarousel.Constructor = Owl;
1755
+
1756
+ })(window.Zepto || window.jQuery, window, document);
admin/js/wpvr-admin.js CHANGED
@@ -31,6 +31,13 @@
31
  * practising this, we should strive to set a better example in our own work.
32
  */
33
 
 
 
 
 
 
 
 
34
  jQuery(document).ready(function($){
35
 
36
 
@@ -91,7 +98,25 @@
91
  });
92
  });
93
  }
 
 
 
 
 
 
 
 
 
 
 
94
  var panoshow = pannellum.viewer(response.data[0]["panoid"], scenes);
 
 
 
 
 
 
 
95
  }
96
  else {
97
  $('#error_occured').show();
31
  * practising this, we should strive to set a better example in our own work.
32
  */
33
 
34
+ $(document).ready(function(){
35
+ $(".owl-carousel").owlCarousel({
36
+ margin:10,
37
+ autoWidth:true,
38
+ });
39
+ });
40
+
41
  jQuery(document).ready(function($){
42
 
43
 
98
  });
99
  });
100
  }
101
+ if (scenes) {
102
+ $('.scene-gallery').trigger('destroy.owl.carousel');
103
+ $('.scene-gallery').empty();
104
+ $(".owl-carousel").owlCarousel({
105
+ margin:10,
106
+ autoWidth:true,
107
+ });
108
+ $.each(scenes.scenes, function (key, val) {
109
+ $('.owl-stage').append('<div class="owl-item" style="width: auto; margin-right: 10px;" ><ul style="width:150px;" ><li>'+key+'</li><li><img class="scctrl" id="'+key+'_gallery" src="'+val.panorama+'"></li></ul></div>');
110
+ });
111
+ }
112
  var panoshow = pannellum.viewer(response.data[0]["panoid"], scenes);
113
+ if (scenes) {
114
+ $.each(scenes.scenes, function (key, val) {
115
+ document.getElementById(''+key+'_gallery').addEventListener('dblclick', function(e) {
116
+ panoshow.loadScene(key);
117
+ });
118
+ });
119
+ }
120
  }
121
  else {
122
  $('#error_occured').show();
admin/partials/wpvr-meta-box-builder-display.php CHANGED
@@ -342,13 +342,18 @@ if (isset($postdata['panodata'])) {
342
  <i class="fa fa-arrow-down toppitch"></i>
343
  </li>
344
  </ul>
 
 
 
 
345
  </div>
346
 
347
 
348
- <script>
349
 
 
350
  var response = <?php echo $response; ?>;
351
  var scenes = response[1];
 
352
  if (scenes) {
353
  $.each(scenes.scenes, function (i) {
354
  $.each(scenes.scenes[i]['hotSpots'], function (key, val) {
@@ -361,9 +366,22 @@ if (isset($postdata['panodata'])) {
361
  });
362
  });
363
  }
 
 
 
 
 
 
364
 
365
  if (response[1]['scenes'] != "") {
366
  var panoshow = pannellum.viewer(response[0]["panoid"], scenes);
 
 
 
 
 
 
 
367
  }
368
 
369
  function wpvrhotspot(hotSpotDiv, args) {
@@ -393,6 +411,9 @@ if (isset($postdata['panodata'])) {
393
  $('iframe').attr('src', $('iframe').attr('src'));
394
  });
395
  });
 
 
 
396
  </script>
397
  <?php
398
  }
342
  <i class="fa fa-arrow-down toppitch"></i>
343
  </li>
344
  </ul>
345
+
346
+ <div class="scene-gallery owl-carousel">
347
+
348
+ </div>
349
  </div>
350
 
351
 
 
352
 
353
+ <script>
354
  var response = <?php echo $response; ?>;
355
  var scenes = response[1];
356
+
357
  if (scenes) {
358
  $.each(scenes.scenes, function (i) {
359
  $.each(scenes.scenes[i]['hotSpots'], function (key, val) {
366
  });
367
  });
368
  }
369
+ if (scenes) {
370
+ $('.scene-gallery').empty();
371
+ $.each(scenes.scenes, function (key, val) {
372
+ $('.scene-gallery').append('<ul style="width:150px;"><li>'+key+'</li><li><img class="scctrl" id="'+key+'_gallery" src="'+val.panorama+'"></li></ul>');
373
+ });
374
+ }
375
 
376
  if (response[1]['scenes'] != "") {
377
  var panoshow = pannellum.viewer(response[0]["panoid"], scenes);
378
+ if (scenes) {
379
+ $.each(scenes.scenes, function (key, val) {
380
+ document.getElementById(''+key+'_gallery').addEventListener('dblclick', function(e) {
381
+ panoshow.loadScene(key);
382
+ });
383
+ });
384
+ }
385
  }
386
 
387
  function wpvrhotspot(hotSpotDiv, args) {
411
  $('iframe').attr('src', $('iframe').attr('src'));
412
  });
413
  });
414
+
415
+
416
+
417
  </script>
418
  <?php
419
  }
admin/partials/wpvr_documentation.php CHANGED
@@ -160,6 +160,7 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
160
  <div class="item"><?php _e('Gyroscope support','wpvr'); ?></div>
161
  <div class="item"><?php _e('Duplicate tour support','wpvr'); ?></div>
162
  <div class="item"><?php _e('File import & export system','wpvr'); ?></div>
 
163
  <div class="item"><?php _e('Personalized support on both support forum and our support e-mail.','wpvr'); ?></div>
164
  </div>
165
  <a href="https://rextheme.com/wpvr/" target="_blank" class="waves-effect waves-light btn wpvr-btn"><?php _e('Get Premium Version','wpvr'); ?></a>
160
  <div class="item"><?php _e('Gyroscope support','wpvr'); ?></div>
161
  <div class="item"><?php _e('Duplicate tour support','wpvr'); ?></div>
162
  <div class="item"><?php _e('File import & export system','wpvr'); ?></div>
163
+ <div class="item"><?php _e('Custom scene gallery','wpvr'); ?></div>
164
  <div class="item"><?php _e('Personalized support on both support forum and our support e-mail.','wpvr'); ?></div>
165
  </div>
166
  <a href="https://rextheme.com/wpvr/" target="_blank" class="waves-effect waves-light btn wpvr-btn"><?php _e('Get Premium Version','wpvr'); ?></a>
build/index.build.js CHANGED
@@ -93,7 +93,7 @@
93
  /*! no static exports found */
94
  /***/ (function(module, exports) {
95
 
96
- eval("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nvar __ = wp.i18n.__; // Import __() from wp.i18n\n\nvar Component = wp.element.Component;\nvar el = wp.element.createElement,\n registerBlockType = wp.blocks.registerBlockType,\n TextControl = wp.components.TextControl,\n SelectControl = wp.components.SelectControl,\n InspectorControls = wp.editor.InspectorControls,\n blockStyle = {\n fontFamily: 'Roboto',\n backgroundColor: '#900',\n color: '#fff',\n padding: '20px'\n};\nvar iconEl = el('svg', {\n width: 20,\n height: 20\n}, el('path', {\n d: \"M16.1,16.6h-2.5c-1,0-1.9-0.6-2.4-1.5L11,14.5c-0.2-0.4-0.5-0.6-0.9-0.6c-0.4,0-0.8,0.2-0.9,0.6l-0.3,0.6 c-0.4,0.9-1.3,1.5-2.4,1.5H3.9c-2.2,0-3.9-1.8-3.9-3.9V7.3c0-2.2,1.8-3.9,3.9-3.9h12.2c2.2,0,3.9,1.8,3.9,3.9v1.5 c0,0.4-0.3,0.8-0.8,0.8c-0.4,0-0.8-0.3-0.8-0.8V7.3c0-1.3-1.1-2.3-2.3-2.3H3.9C2.6,4.9,1.6,6,1.6,7.3v5.4c0,1.3,1.1,2.3,2.3,2.3 h2.6c0.4,0,0.8-0.2,0.9-0.6l0.3-0.6c0.4-0.9,1.3-1.5,2.4-1.5c1,0,1.9,0.6,2.4,1.5l0.3,0.6c0.2,0.4,0.5,0.6,0.9,0.6h2.5 c1.3,0,2.3-1.1,2.3-2.3c0-0.4,0.3-0.8,0.8-0.8c0.4,0,0.8,0.3,0.8,0.8C20,14.9,18.2,16.6,16.1,16.6L16.1,16.6z M16.7,9.4 c0-1.3-1.1-2.3-2.3-2.3C13,7.1,12,8.1,12,9.4s1.1,2.3,2.3,2.3C15.6,11.7,16.7,10.7,16.7,9.4L16.7,9.4z M15.1,9.4 c0,0.4-0.4,0.8-0.8,0.8c-0.4,0-0.8-0.4-0.8-0.8s0.4-0.8,0.8-0.8C14.8,8.6,15.1,9,15.1,9.4L15.1,9.4z M8,9.4C8,8.1,7,7.1,5.7,7.1 S3.3,8.1,3.3,9.4s1.1,2.3,2.3,2.3S8,10.7,8,9.4L8,9.4z M6.4,9.4c0,0.4-0.4,0.8-0.8,0.8c-0.4,0-0.8-0.4-0.8-0.8s0.4-0.8,0.8-0.8 C6.1,8.6,6.4,9,6.4,9.4L6.4,9.4z M6.4,9.4\"\n}));\n\nvar wpvredit =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(wpvredit, _Component);\n\n function wpvredit() {\n var _this;\n\n _classCallCheck(this, wpvredit);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(wpvredit).apply(this, arguments));\n _this.state = {\n data: [{\n value: \"0\",\n label: \"None\"\n }]\n };\n return _this;\n }\n\n _createClass(wpvredit, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n wp.apiFetch({\n path: 'wpvr/v1/panodata'\n }).then(function (data) {\n _this2.setState(_defineProperty({\n data: data\n }, \"data\", data));\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this3 = this;\n\n return [el(InspectorControls, {}, el(SelectControl, {\n label: 'Id',\n value: this.props.attributes.id,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n id: value\n });\n },\n options: this.state.data\n })), el(InspectorControls, {}, el(TextControl, {\n label: 'Width',\n value: this.props.attributes.width,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n width: value\n });\n }\n })), el(InspectorControls, {}, el(TextControl, {\n label: 'Height',\n value: this.props.attributes.height,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n height: value\n });\n }\n })), React.createElement(\"p\", {\n className: \"wpvr-block-content\"\n }, \"WPVR id=\", this.props.attributes.id, \", Width=\", this.props.attributes.width, \"px, Height=\", this.props.attributes.height, \"px\")];\n }\n }]);\n\n return wpvredit;\n}(Component);\n\nregisterBlockType('wpvr/wpvr-block', {\n title: 'WPVR',\n icon: iconEl,\n category: 'common',\n edit: wpvredit,\n save: function save(props) {\n return null;\n }\n});\n\n//# sourceURL=webpack:///./src/index.js?");
97
 
98
  /***/ })
99
 
93
  /*! no static exports found */
94
  /***/ (function(module, exports) {
95
 
96
+ eval("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nvar __ = wp.i18n.__; // Import __() from wp.i18n\n\nvar Component = wp.element.Component;\nvar el = wp.element.createElement,\n registerBlockType = wp.blocks.registerBlockType,\n TextControl = wp.components.TextControl,\n SelectControl = wp.components.SelectControl,\n InspectorControls = wp.editor.InspectorControls,\n blockStyle = {\n fontFamily: 'Roboto',\n backgroundColor: '#900',\n color: '#fff',\n padding: '20px'\n};\nvar iconEl = el('svg', {\n width: 20,\n height: 20\n}, el('path', {\n d: \"M16.1,16.6h-2.5c-1,0-1.9-0.6-2.4-1.5L11,14.5c-0.2-0.4-0.5-0.6-0.9-0.6c-0.4,0-0.8,0.2-0.9,0.6l-0.3,0.6 c-0.4,0.9-1.3,1.5-2.4,1.5H3.9c-2.2,0-3.9-1.8-3.9-3.9V7.3c0-2.2,1.8-3.9,3.9-3.9h12.2c2.2,0,3.9,1.8,3.9,3.9v1.5 c0,0.4-0.3,0.8-0.8,0.8c-0.4,0-0.8-0.3-0.8-0.8V7.3c0-1.3-1.1-2.3-2.3-2.3H3.9C2.6,4.9,1.6,6,1.6,7.3v5.4c0,1.3,1.1,2.3,2.3,2.3 h2.6c0.4,0,0.8-0.2,0.9-0.6l0.3-0.6c0.4-0.9,1.3-1.5,2.4-1.5c1,0,1.9,0.6,2.4,1.5l0.3,0.6c0.2,0.4,0.5,0.6,0.9,0.6h2.5 c1.3,0,2.3-1.1,2.3-2.3c0-0.4,0.3-0.8,0.8-0.8c0.4,0,0.8,0.3,0.8,0.8C20,14.9,18.2,16.6,16.1,16.6L16.1,16.6z M16.7,9.4 c0-1.3-1.1-2.3-2.3-2.3C13,7.1,12,8.1,12,9.4s1.1,2.3,2.3,2.3C15.6,11.7,16.7,10.7,16.7,9.4L16.7,9.4z M15.1,9.4 c0,0.4-0.4,0.8-0.8,0.8c-0.4,0-0.8-0.4-0.8-0.8s0.4-0.8,0.8-0.8C14.8,8.6,15.1,9,15.1,9.4L15.1,9.4z M8,9.4C8,8.1,7,7.1,5.7,7.1 S3.3,8.1,3.3,9.4s1.1,2.3,2.3,2.3S8,10.7,8,9.4L8,9.4z M6.4,9.4c0,0.4-0.4,0.8-0.8,0.8c-0.4,0-0.8-0.4-0.8-0.8s0.4-0.8,0.8-0.8 C6.1,8.6,6.4,9,6.4,9.4L6.4,9.4z M6.4,9.4\"\n}));\n\nvar wpvredit =\n/*#__PURE__*/\nfunction (_Component) {\n _inherits(wpvredit, _Component);\n\n function wpvredit() {\n var _this;\n\n _classCallCheck(this, wpvredit);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(wpvredit).apply(this, arguments));\n _this.state = {\n data: [{\n value: \"0\",\n label: \"None\"\n }]\n };\n return _this;\n }\n\n _createClass(wpvredit, [{\n key: \"componentDidMount\",\n value: function componentDidMount() {\n var _this2 = this;\n\n wp.apiFetch({\n path: 'wpvr/v1/panodata'\n }).then(function (data) {\n _this2.setState(_defineProperty({\n data: data\n }, \"data\", data));\n });\n }\n }, {\n key: \"render\",\n value: function render() {\n var _this3 = this;\n\n return [el(InspectorControls, {}, el(SelectControl, {\n label: 'Id',\n value: this.props.attributes.id,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n id: value\n });\n },\n options: this.state.data\n })), el(InspectorControls, {}, el(TextControl, {\n label: 'Width',\n value: this.props.attributes.width,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n width: value\n });\n }\n })), el(InspectorControls, {}, el(TextControl, {\n label: 'Height',\n value: this.props.attributes.height,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n height: value\n });\n }\n })), el(InspectorControls, {}, el(TextControl, {\n label: 'Radius',\n value: this.props.attributes.radius,\n onChange: function onChange(value) {\n _this3.props.setAttributes({\n radius: value\n });\n }\n })), React.createElement(\"p\", {\n className: \"wpvr-block-content\"\n }, \"WPVR id=\", this.props.attributes.id, \", Width=\", this.props.attributes.width, \"px, Height=\", this.props.attributes.height, \"px, Radius=\", this.props.attributes.radius, \"px\")];\n }\n }]);\n\n return wpvredit;\n}(Component);\n\nregisterBlockType('wpvr/wpvr-block', {\n title: 'WPVR',\n icon: iconEl,\n category: 'common',\n edit: wpvredit,\n save: function save(props) {\n return null;\n }\n});\n\n//# sourceURL=webpack:///./src/index.js?");
97
 
98
  /***/ })
99
 
elementor/elements/Wpvr-widget.php CHANGED
@@ -137,6 +137,16 @@ class Wpvr_Widget extends Widget_Base {
137
  ]
138
  );
139
 
 
 
 
 
 
 
 
 
 
 
140
  $this->end_controls_section();
141
 
142
  }
@@ -156,19 +166,23 @@ class Wpvr_Widget extends Widget_Base {
156
  $id = 0;
157
  $width = "600px";
158
  $height = "400px";
 
159
  $id = $settings['vr_id'];
160
  $width = $settings['vr_width'];
161
  $height = $settings['vr_height'];
 
162
  if (empty($width)) {
163
  $width = "600px";
164
  }
165
  if (empty($height)) {
166
  $height = "400px";
167
  }
168
-
 
 
169
 
170
  if ($id) {
171
- $shortcode = do_shortcode( shortcode_unautop( '[wpvr id="'.$id.'" width="'.$width.'" height="'.$height.'"]' ) );
172
  echo $shortcode;
173
  }
174
  }
137
  ]
138
  );
139
 
140
+ $this->add_control(
141
+ 'vr_radius',
142
+ [
143
+ 'label' => __( 'Radius:', 'wpvr' ),
144
+ 'type' => Controls_Manager::TEXT,
145
+ 'input_type' => 'text',
146
+ 'placeholder' => __( '', 'wpvr' ),
147
+ ]
148
+ );
149
+
150
  $this->end_controls_section();
151
 
152
  }
166
  $id = 0;
167
  $width = "600px";
168
  $height = "400px";
169
+ $radius = "0px";
170
  $id = $settings['vr_id'];
171
  $width = $settings['vr_width'];
172
  $height = $settings['vr_height'];
173
+ $radius = $settings['vr_radius'];
174
  if (empty($width)) {
175
  $width = "600px";
176
  }
177
  if (empty($height)) {
178
  $height = "400px";
179
  }
180
+ if (empty($radius)) {
181
+ $radius = "0px";
182
+ }
183
 
184
  if ($id) {
185
+ $shortcode = do_shortcode( shortcode_unautop( '[wpvr id="'.$id.'" width="'.$width.'" height="'.$height.'" radius="'.$radius.'"]' ) );
186
  echo $shortcode;
187
  }
188
  }
package-lock.json CHANGED
@@ -1241,12 +1241,19 @@
1241
  "dev": true
1242
  },
1243
  "axios": {
1244
- "version": "0.18.0",
1245
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
1246
- "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
1247
  "requires": {
1248
- "follow-redirects": "^1.3.0",
1249
- "is-buffer": "^1.1.5"
 
 
 
 
 
 
 
1250
  }
1251
  },
1252
  "babel-loader": {
@@ -2384,20 +2391,25 @@
2384
  }
2385
  },
2386
  "follow-redirects": {
2387
- "version": "1.7.0",
2388
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
2389
- "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
2390
  "requires": {
2391
- "debug": "^3.2.6"
2392
  },
2393
  "dependencies": {
2394
  "debug": {
2395
- "version": "3.2.6",
2396
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
2397
- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
2398
  "requires": {
2399
- "ms": "^2.1.1"
2400
  }
 
 
 
 
 
2401
  }
2402
  }
2403
  },
@@ -3296,7 +3308,8 @@
3296
  "is-buffer": {
3297
  "version": "1.1.6",
3298
  "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
3299
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
 
3300
  },
3301
  "is-callable": {
3302
  "version": "1.1.4",
@@ -3782,7 +3795,8 @@
3782
  "ms": {
3783
  "version": "2.1.1",
3784
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
3785
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
 
3786
  },
3787
  "nan": {
3788
  "version": "2.13.2",
1241
  "dev": true
1242
  },
1243
  "axios": {
1244
+ "version": "0.19.0",
1245
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz",
1246
+ "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==",
1247
  "requires": {
1248
+ "follow-redirects": "1.5.10",
1249
+ "is-buffer": "^2.0.2"
1250
+ },
1251
+ "dependencies": {
1252
+ "is-buffer": {
1253
+ "version": "2.0.3",
1254
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
1255
+ "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw=="
1256
+ }
1257
  }
1258
  },
1259
  "babel-loader": {
2391
  }
2392
  },
2393
  "follow-redirects": {
2394
+ "version": "1.5.10",
2395
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
2396
+ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
2397
  "requires": {
2398
+ "debug": "=3.1.0"
2399
  },
2400
  "dependencies": {
2401
  "debug": {
2402
+ "version": "3.1.0",
2403
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
2404
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
2405
  "requires": {
2406
+ "ms": "2.0.0"
2407
  }
2408
+ },
2409
+ "ms": {
2410
+ "version": "2.0.0",
2411
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
2412
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
2413
  }
2414
  }
2415
  },
3308
  "is-buffer": {
3309
  "version": "1.1.6",
3310
  "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
3311
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
3312
+ "dev": true
3313
  },
3314
  "is-callable": {
3315
  "version": "1.1.4",
3795
  "ms": {
3796
  "version": "2.1.1",
3797
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
3798
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
3799
+ "dev": true
3800
  },
3801
  "nan": {
3802
  "version": "2.13.2",
package.json CHANGED
@@ -22,6 +22,6 @@
22
  },
23
  "dependencies": {
24
  "@wordpress/api-fetch": "^3.1.2",
25
- "axios": "^0.18.0"
26
  }
27
  }
22
  },
23
  "dependencies": {
24
  "@wordpress/api-fetch": "^3.1.2",
25
+ "axios": "^0.19.0"
26
  }
27
  }
public/class-wpvr-public.php CHANGED
@@ -76,8 +76,8 @@ class Wpvr_Public {
76
  wp_enqueue_style( $this->plugin_name . 'fontawesome', 'https://use.fontawesome.com/releases/v5.7.2/css/all.css', array(), $this->version, 'all' );
77
  wp_enqueue_style('panellium-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/pannellum.css', array(), true);
78
  wp_enqueue_style('videojs-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/video-js.css', array(), true);
 
79
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-public.css', array(), $this->version, 'all' );
80
-
81
  }
82
 
83
  /**
@@ -102,6 +102,7 @@ class Wpvr_Public {
102
  wp_enqueue_script('panelliumlib-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/libpannellum.js', array(), true);
103
  wp_enqueue_script('videojs-js', plugin_dir_url( __FILE__ ) . 'js/video.js', array(), true);
104
  wp_enqueue_script('panelliumvid-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/videojs-pannellum-plugin.js', array(), true);
 
105
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-public.js', array( 'jquery' ), $this->version, false );
106
 
107
  }
@@ -128,7 +129,7 @@ class Wpvr_Public {
128
  'id' => 0,
129
  'width' => NULL,
130
  'height' => NULL,
131
- 'class' => NULL
132
  ), $atts
133
  )
134
  );
@@ -198,6 +199,11 @@ class Wpvr_Public {
198
  $control = $postdata['showControls'];
199
  }
200
 
 
 
 
 
 
201
  $gyro = false;
202
  if (isset($postdata['gyro'])) {
203
  $gyro = $postdata['gyro'];
@@ -529,16 +535,49 @@ class Wpvr_Public {
529
  $html .= '</style>';
530
  if ($width == 'fullwidth') {
531
  if (wpvr_isMobileDevice()) {
532
- $html .= '<div id="pano'.$id.'" class="pano-wrap" style="text-align:center;">';
 
 
 
 
 
 
533
  }
534
  else {
535
- $html .= '<div id="pano'.$id.'" class="pano-wrap vrfullwidth" style=" text-align:center; height: '.$height.';" >';
 
 
 
 
 
 
536
  }
537
  }
538
  else {
539
- $html .= '<div id="pano'.$id.'" class="pano-wrap" style=" text-align:center; width: '.$width.'; height: '.$height.'; margin: 0 auto;">';
 
 
 
 
 
 
540
  }
541
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
542
  $html .= '<i class="fa fa-times cross"></i>';
543
  $html .= '<div class="custom-ifram" style="display: none;">';
544
  $html .= '</div>';
@@ -560,8 +599,20 @@ class Wpvr_Public {
560
  $html .= '}';
561
  $html .= '}';
562
  $html .= '}';
563
- $html .= '}';
564
- $html .= 'pannellum.viewer(response[0]["panoid"], scenes);';
 
 
 
 
 
 
 
 
 
 
 
 
565
  $html .= '</script>';
566
  //script end
567
 
76
  wp_enqueue_style( $this->plugin_name . 'fontawesome', 'https://use.fontawesome.com/releases/v5.7.2/css/all.css', array(), $this->version, 'all' );
77
  wp_enqueue_style('panellium-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/pannellum.css', array(), true);
78
  wp_enqueue_style('videojs-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/video-js.css', array(), true);
79
+ wp_enqueue_style( 'owl-css', plugin_dir_url( __FILE__ ) . 'css/owl.carousel.css', array(), $this->version, 'all' );
80
  wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-public.css', array(), $this->version, 'all' );
 
81
  }
82
 
83
  /**
102
  wp_enqueue_script('panelliumlib-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/libpannellum.js', array(), true);
103
  wp_enqueue_script('videojs-js', plugin_dir_url( __FILE__ ) . 'js/video.js', array(), true);
104
  wp_enqueue_script('panelliumvid-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/videojs-pannellum-plugin.js', array(), true);
105
+ wp_enqueue_script( 'owl-js', plugin_dir_url( __FILE__ ) . 'js/owl.carousel.js', array( 'jquery' ), false );
106
  wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-public.js', array( 'jquery' ), $this->version, false );
107
 
108
  }
129
  'id' => 0,
130
  'width' => NULL,
131
  'height' => NULL,
132
+ 'radius' => NULL
133
  ), $atts
134
  )
135
  );
199
  $control = $postdata['showControls'];
200
  }
201
 
202
+ $vrgallery = false;
203
+ if (isset($postdata['vrgallery'])) {
204
+ $vrgallery = $postdata['vrgallery'];
205
+ }
206
+
207
  $gyro = false;
208
  if (isset($postdata['gyro'])) {
209
  $gyro = $postdata['gyro'];
535
  $html .= '</style>';
536
  if ($width == 'fullwidth') {
537
  if (wpvr_isMobileDevice()) {
538
+ if ($radius) {
539
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style="text-align:center; border-radius:'.$radius.';">';
540
+ }
541
+ else {
542
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style="text-align:center;">';
543
+ }
544
+
545
  }
546
  else {
547
+ if ($radius) {
548
+ $html .= '<div id="pano'.$id.'" class="pano-wrap vrfullwidth" style=" text-align:center; height: '.$height.'; border-radius:'.$radius.';" >';
549
+ }
550
+ else {
551
+ $html .= '<div id="pano'.$id.'" class="pano-wrap vrfullwidth" style=" text-align:center; height: '.$height.';" >';
552
+ }
553
+
554
  }
555
  }
556
  else {
557
+ if ($radius) {
558
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style=" text-align:center; width: '.$width.'; height: '.$height.'; margin: 0 auto; border-radius:'.$radius.';">';
559
+ }
560
+ else {
561
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style=" text-align:center; width: '.$width.'; height: '.$height.'; margin: 0 auto;">';
562
+ }
563
+
564
  }
565
+
566
+ if ($vrgallery) {
567
+ //===Carousal setup===//
568
+ $html .= '<div id="sccontrols" class="scene-gallery owl-carousel owl-theme">';
569
+ if (isset($panodata["scene-list"])) {
570
+ foreach ($panodata["scene-list"] as $panoscenes) {
571
+ $scene_key = $panoscenes['scene-id'];
572
+ $img_src_url = $panoscenes['scene-attachment-url'];
573
+ $html .= '<ul style="width:150px;"><li><img class="scctrl" id="'.$scene_key.'_gallery_'.$id.'" src="'.$img_src_url.'"></li></ul>';
574
+ }
575
+ }
576
+ $html .= '</div>';
577
+ //===Carousal setup end===//
578
+ }
579
+
580
+
581
  $html .= '<i class="fa fa-times cross"></i>';
582
  $html .= '<div class="custom-ifram" style="display: none;">';
583
  $html .= '</div>';
599
  $html .= '}';
600
  $html .= '}';
601
  $html .= '}';
602
+ $html .= '}';
603
+
604
+ $html .= 'var panoshow'.$id.' = pannellum.viewer(response[0]["panoid"], scenes);';
605
+ if ($vrgallery) {
606
+ if (isset($panodata["scene-list"])) {
607
+ foreach ($panodata["scene-list"] as $panoscenes) {
608
+ $scene_key = $panoscenes['scene-id'];
609
+ $scene_key_gallery = $panoscenes['scene-id'].'_gallery_'.$id;
610
+ $img_src_url = $panoscenes['scene-attachment-url'];
611
+ $html .= 'document.getElementById("'.$scene_key_gallery.'").addEventListener("dblclick", function(e) { panoshow'.$id.'.loadScene("'.$scene_key.'"); });';
612
+ }
613
+ }
614
+ }
615
+
616
  $html .= '</script>';
617
  //script end
618
 
public/css/owl.carousel.css ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Owl Carousel v2.3.4
3
+ * Copyright 2013-2018 David Deutsch
4
+ * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
5
+ */
6
+ /*
7
+ * Owl Carousel - Core
8
+ */
9
+ .owl-carousel {
10
+ display: none;
11
+ width: 100%;
12
+ -webkit-tap-highlight-color: transparent;
13
+ /* position relative and z-index fix webkit rendering fonts issue */
14
+ position: relative;
15
+ z-index: 1; }
16
+ .owl-carousel .owl-stage {
17
+ position: relative;
18
+ -ms-touch-action: pan-Y;
19
+ touch-action: manipulation;
20
+ -moz-backface-visibility: hidden;
21
+ /* fix firefox animation glitch */ }
22
+ .owl-carousel .owl-stage:after {
23
+ content: ".";
24
+ display: block;
25
+ clear: both;
26
+ visibility: hidden;
27
+ line-height: 0;
28
+ height: 0; }
29
+ .owl-carousel .owl-stage-outer {
30
+ position: relative;
31
+ overflow: hidden;
32
+ /* fix for flashing background */
33
+ -webkit-transform: translate3d(0px, 0px, 0px); }
34
+ .owl-carousel .owl-wrapper,
35
+ .owl-carousel .owl-item {
36
+ -webkit-backface-visibility: hidden;
37
+ -moz-backface-visibility: hidden;
38
+ -ms-backface-visibility: hidden;
39
+ -webkit-transform: translate3d(0, 0, 0);
40
+ -moz-transform: translate3d(0, 0, 0);
41
+ -ms-transform: translate3d(0, 0, 0); }
42
+ .owl-carousel .owl-item {
43
+ position: relative;
44
+ min-height: 1px;
45
+ float: left;
46
+ -webkit-backface-visibility: hidden;
47
+ -webkit-tap-highlight-color: transparent;
48
+ -webkit-touch-callout: none; }
49
+ .owl-carousel .owl-item img {
50
+ display: block;
51
+ width: 100%; }
52
+ .owl-carousel .owl-nav.disabled,
53
+ .owl-carousel .owl-dots.disabled {
54
+ display: none; }
55
+ .owl-carousel .owl-nav .owl-prev,
56
+ .owl-carousel .owl-nav .owl-next,
57
+ .owl-carousel .owl-dot {
58
+ cursor: pointer;
59
+ -webkit-user-select: none;
60
+ -khtml-user-select: none;
61
+ -moz-user-select: none;
62
+ -ms-user-select: none;
63
+ user-select: none; }
64
+ .owl-carousel .owl-nav button.owl-prev,
65
+ .owl-carousel .owl-nav button.owl-next,
66
+ .owl-carousel button.owl-dot {
67
+ background: none;
68
+ color: inherit;
69
+ border: none;
70
+ padding: 0 !important;
71
+ font: inherit; }
72
+ .owl-carousel.owl-loaded {
73
+ display: block; }
74
+ .owl-carousel.owl-loading {
75
+ opacity: 0;
76
+ display: block; }
77
+ .owl-carousel.owl-hidden {
78
+ opacity: 0; }
79
+ .owl-carousel.owl-refresh .owl-item {
80
+ visibility: hidden; }
81
+ .owl-carousel.owl-drag .owl-item {
82
+ -ms-touch-action: pan-y;
83
+ touch-action: pan-y;
84
+ -webkit-user-select: none;
85
+ -moz-user-select: none;
86
+ -ms-user-select: none;
87
+ user-select: none; }
88
+ .owl-carousel.owl-grab {
89
+ cursor: move;
90
+ cursor: grab; }
91
+ .owl-carousel.owl-rtl {
92
+ direction: rtl; }
93
+ .owl-carousel.owl-rtl .owl-item {
94
+ float: right; }
95
+
96
+ /* No Js */
97
+ .no-js .owl-carousel {
98
+ display: block; }
99
+
100
+ /*
101
+ * Owl Carousel - Animate Plugin
102
+ */
103
+ .owl-carousel .animated {
104
+ animation-duration: 1000ms;
105
+ animation-fill-mode: both; }
106
+
107
+ .owl-carousel .owl-animated-in {
108
+ z-index: 0; }
109
+
110
+ .owl-carousel .owl-animated-out {
111
+ z-index: 1; }
112
+
113
+ .owl-carousel .fadeOut {
114
+ animation-name: fadeOut; }
115
+
116
+ @keyframes fadeOut {
117
+ 0% {
118
+ opacity: 1; }
119
+ 100% {
120
+ opacity: 0; } }
121
+
122
+ /*
123
+ * Owl Carousel - Auto Height Plugin
124
+ */
125
+ .owl-height {
126
+ transition: height 500ms ease-in-out; }
127
+
128
+ /*
129
+ * Owl Carousel - Lazy Load Plugin
130
+ */
131
+ .owl-carousel .owl-item {
132
+ /**
133
+ This is introduced due to a bug in IE11 where lazy loading combined with autoheight plugin causes a wrong
134
+ calculation of the height of the owl-item that breaks page layouts
135
+ */ }
136
+ .owl-carousel .owl-item .owl-lazy {
137
+ opacity: 0;
138
+ transition: opacity 400ms ease; }
139
+ .owl-carousel .owl-item .owl-lazy[src^=""], .owl-carousel .owl-item .owl-lazy:not([src]) {
140
+ max-height: 0; }
141
+ .owl-carousel .owl-item img.owl-lazy {
142
+ transform-style: preserve-3d; }
143
+
144
+ /*
145
+ * Owl Carousel - Video Plugin
146
+ */
147
+ .owl-carousel .owl-video-wrapper {
148
+ position: relative;
149
+ height: 100%;
150
+ background: #000; }
151
+
152
+ .owl-carousel .owl-video-play-icon {
153
+ position: absolute;
154
+ height: 80px;
155
+ width: 80px;
156
+ left: 50%;
157
+ top: 50%;
158
+ margin-left: -40px;
159
+ margin-top: -40px;
160
+ background: url("owl.video.play.png") no-repeat;
161
+ cursor: pointer;
162
+ z-index: 1;
163
+ -webkit-backface-visibility: hidden;
164
+ transition: transform 100ms ease; }
165
+
166
+ .owl-carousel .owl-video-play-icon:hover {
167
+ -ms-transform: scale(1.3, 1.3);
168
+ transform: scale(1.3, 1.3); }
169
+
170
+ .owl-carousel .owl-video-playing .owl-video-tn,
171
+ .owl-carousel .owl-video-playing .owl-video-play-icon {
172
+ display: none; }
173
+
174
+ .owl-carousel .owl-video-tn {
175
+ opacity: 0;
176
+ height: 100%;
177
+ background-position: center center;
178
+ background-repeat: no-repeat;
179
+ background-size: contain;
180
+ transition: opacity 400ms ease; }
181
+
182
+ .owl-carousel .owl-video-frame {
183
+ position: relative;
184
+ z-index: 1;
185
+ height: 100%;
186
+ width: 100%; }
public/css/wpvr-public.css CHANGED
@@ -12,6 +12,34 @@ div.pnlm-hotspot-base.far:before{
12
  transform: translate(-50%, -50%);
13
  }
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  .vrfullwidth {
16
  width: 98vw;
17
  position: relative;
@@ -200,6 +228,16 @@ div.custom-ifram {
200
  }
201
 
202
  @media (max-width: 575px){
 
 
 
 
 
 
 
 
 
 
203
  div.custom-tooltip span img {
204
  height: 150px;
205
  width: 220px;
12
  transform: translate(-50%, -50%);
13
  }
14
 
15
+ .scene-gallery ul {
16
+ display: inline-grid;
17
+ }
18
+ .scene-gallery ul li {
19
+ list-style: none;
20
+ }
21
+ #sccontrols {
22
+ position: absolute;
23
+ bottom: 0;
24
+ z-index: 2;
25
+ text-align: center;
26
+ width: 100%;
27
+ padding-bottom: 3px;
28
+ background-color: rgba(0, 0, 0, 0.35);
29
+ color: #fff;
30
+ }
31
+ .scctrl {
32
+ border-radius: 5px !important;
33
+ width: 100px;
34
+ height: 100px !important;
35
+ display: inline-block;
36
+ cursor: pointer;
37
+ margin: 5px;
38
+ }
39
+ .scctrl:hover {
40
+ background: rgba(200, 200, 200, 1);
41
+ }
42
+
43
  .vrfullwidth {
44
  width: 98vw;
45
  position: relative;
228
  }
229
 
230
  @media (max-width: 575px){
231
+ .scene-gallery ul {
232
+ width: 100px !important;
233
+ }
234
+ .scctrl {
235
+ height: 50px !important;
236
+ }
237
+ .pnlm-container {
238
+ width: 100%!important;
239
+ height: 300px!important;
240
+ }
241
  div.custom-tooltip span img {
242
  height: 150px;
243
  width: 220px;
public/js/owl.carousel.js ADDED
@@ -0,0 +1,1756 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Owl carousel
3
+ * @version 2.3.4
4
+ * @author Bartosz Wojciechowski
5
+ * @author David Deutsch
6
+ * @license The MIT License (MIT)
7
+ * @todo Lazy Load Icon
8
+ * @todo prevent animationend bubling
9
+ * @todo itemsScaleUp
10
+ * @todo Test Zepto
11
+ * @todo stagePadding calculate wrong active classes
12
+ */
13
+ ;(function($, window, document, undefined) {
14
+
15
+ /**
16
+ * Creates a carousel.
17
+ * @class The Owl Carousel.
18
+ * @public
19
+ * @param {HTMLElement|jQuery} element - The element to create the carousel for.
20
+ * @param {Object} [options] - The options
21
+ */
22
+ function Owl(element, options) {
23
+
24
+ /**
25
+ * Current settings for the carousel.
26
+ * @public
27
+ */
28
+ this.settings = null;
29
+
30
+ /**
31
+ * Current options set by the caller including defaults.
32
+ * @public
33
+ */
34
+ this.options = $.extend({}, Owl.Defaults, options);
35
+
36
+ /**
37
+ * Plugin element.
38
+ * @public
39
+ */
40
+ this.$element = $(element);
41
+
42
+ /**
43
+ * Proxied event handlers.
44
+ * @protected
45
+ */
46
+ this._handlers = {};
47
+
48
+ /**
49
+ * References to the running plugins of this carousel.
50
+ * @protected
51
+ */
52
+ this._plugins = {};
53
+
54
+ /**
55
+ * Currently suppressed events to prevent them from being retriggered.
56
+ * @protected
57
+ */
58
+ this._supress = {};
59
+
60
+ /**
61
+ * Absolute current position.
62
+ * @protected
63
+ */
64
+ this._current = null;
65
+
66
+ /**
67
+ * Animation speed in milliseconds.
68
+ * @protected
69
+ */
70
+ this._speed = null;
71
+
72
+ /**
73
+ * Coordinates of all items in pixel.
74
+ * @todo The name of this member is missleading.
75
+ * @protected
76
+ */
77
+ this._coordinates = [];
78
+
79
+ /**
80
+ * Current breakpoint.
81
+ * @todo Real media queries would be nice.
82
+ * @protected
83
+ */
84
+ this._breakpoint = null;
85
+
86
+ /**
87
+ * Current width of the plugin element.
88
+ */
89
+ this._width = null;
90
+
91
+ /**
92
+ * All real items.
93
+ * @protected
94
+ */
95
+ this._items = [];
96
+
97
+ /**
98
+ * All cloned items.
99
+ * @protected
100
+ */
101
+ this._clones = [];
102
+
103
+ /**
104
+ * Merge values of all items.
105
+ * @todo Maybe this could be part of a plugin.
106
+ * @protected
107
+ */
108
+ this._mergers = [];
109
+
110
+ /**
111
+ * Widths of all items.
112
+ */
113
+ this._widths = [];
114
+
115
+ /**
116
+ * Invalidated parts within the update process.
117
+ * @protected
118
+ */
119
+ this._invalidated = {};
120
+
121
+ /**
122
+ * Ordered list of workers for the update process.
123
+ * @protected
124
+ */
125
+ this._pipe = [];
126
+
127
+ /**
128
+ * Current state information for the drag operation.
129
+ * @todo #261
130
+ * @protected
131
+ */
132
+ this._drag = {
133
+ time: null,
134
+ target: null,
135
+ pointer: null,
136
+ stage: {
137
+ start: null,
138
+ current: null
139
+ },
140
+ direction: null
141
+ };
142
+
143
+ /**
144
+ * Current state information and their tags.
145
+ * @type {Object}
146
+ * @protected
147
+ */
148
+ this._states = {
149
+ current: {},
150
+ tags: {
151
+ 'initializing': [ 'busy' ],
152
+ 'animating': [ 'busy' ],
153
+ 'dragging': [ 'interacting' ]
154
+ }
155
+ };
156
+
157
+ $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
158
+ this._handlers[handler] = $.proxy(this[handler], this);
159
+ }, this));
160
+
161
+ $.each(Owl.Plugins, $.proxy(function(key, plugin) {
162
+ this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
163
+ = new plugin(this);
164
+ }, this));
165
+
166
+ $.each(Owl.Workers, $.proxy(function(priority, worker) {
167
+ this._pipe.push({
168
+ 'filter': worker.filter,
169
+ 'run': $.proxy(worker.run, this)
170
+ });
171
+ }, this));
172
+
173
+ this.setup();
174
+ this.initialize();
175
+ }
176
+
177
+ /**
178
+ * Default options for the carousel.
179
+ * @public
180
+ */
181
+ Owl.Defaults = {
182
+ items: 3,
183
+ loop: false,
184
+ center: false,
185
+ rewind: false,
186
+ checkVisibility: true,
187
+
188
+ mouseDrag: true,
189
+ touchDrag: true,
190
+ pullDrag: true,
191
+ freeDrag: false,
192
+
193
+ margin: 0,
194
+ stagePadding: 0,
195
+
196
+ merge: false,
197
+ mergeFit: true,
198
+ autoWidth: false,
199
+
200
+ startPosition: 0,
201
+ rtl: false,
202
+
203
+ smartSpeed: 250,
204
+ fluidSpeed: false,
205
+ dragEndSpeed: false,
206
+
207
+ responsive: {},
208
+ responsiveRefreshRate: 200,
209
+ responsiveBaseElement: window,
210
+
211
+ fallbackEasing: 'swing',
212
+ slideTransition: '',
213
+
214
+ info: false,
215
+
216
+ nestedItemSelector: false,
217
+ itemElement: 'div',
218
+ stageElement: 'div',
219
+
220
+ refreshClass: 'owl-refresh',
221
+ loadedClass: 'owl-loaded',
222
+ loadingClass: 'owl-loading',
223
+ rtlClass: 'owl-rtl',
224
+ responsiveClass: 'owl-responsive',
225
+ dragClass: 'owl-drag',
226
+ itemClass: 'owl-item',
227
+ stageClass: 'owl-stage',
228
+ stageOuterClass: 'owl-stage-outer',
229
+ grabClass: 'owl-grab'
230
+ };
231
+
232
+ /**
233
+ * Enumeration for width.
234
+ * @public
235
+ * @readonly
236
+ * @enum {String}
237
+ */
238
+ Owl.Width = {
239
+ Default: 'default',
240
+ Inner: 'inner',
241
+ Outer: 'outer'
242
+ };
243
+
244
+ /**
245
+ * Enumeration for types.
246
+ * @public
247
+ * @readonly
248
+ * @enum {String}
249
+ */
250
+ Owl.Type = {
251
+ Event: 'event',
252
+ State: 'state'
253
+ };
254
+
255
+ /**
256
+ * Contains all registered plugins.
257
+ * @public
258
+ */
259
+ Owl.Plugins = {};
260
+
261
+ /**
262
+ * List of workers involved in the update process.
263
+ */
264
+ Owl.Workers = [ {
265
+ filter: [ 'width', 'settings' ],
266
+ run: function() {
267
+ this._width = this.$element.width();
268
+ }
269
+ }, {
270
+ filter: [ 'width', 'items', 'settings' ],
271
+ run: function(cache) {
272
+ cache.current = this._items && this._items[this.relative(this._current)];
273
+ }
274
+ }, {
275
+ filter: [ 'items', 'settings' ],
276
+ run: function() {
277
+ this.$stage.children('.cloned').remove();
278
+ }
279
+ }, {
280
+ filter: [ 'width', 'items', 'settings' ],
281
+ run: function(cache) {
282
+ var margin = this.settings.margin || '',
283
+ grid = !this.settings.autoWidth,
284
+ rtl = this.settings.rtl,
285
+ css = {
286
+ 'width': 'auto',
287
+ 'margin-left': rtl ? margin : '',
288
+ 'margin-right': rtl ? '' : margin
289
+ };
290
+
291
+ !grid && this.$stage.children().css(css);
292
+
293
+ cache.css = css;
294
+ }
295
+ }, {
296
+ filter: [ 'width', 'items', 'settings' ],
297
+ run: function(cache) {
298
+ var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
299
+ merge = null,
300
+ iterator = this._items.length,
301
+ grid = !this.settings.autoWidth,
302
+ widths = [];
303
+
304
+ cache.items = {
305
+ merge: false,
306
+ width: width
307
+ };
308
+
309
+ while (iterator--) {
310
+ merge = this._mergers[iterator];
311
+ merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
312
+
313
+ cache.items.merge = merge > 1 || cache.items.merge;
314
+
315
+ widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
316
+ }
317
+
318
+ this._widths = widths;
319
+ }
320
+ }, {
321
+ filter: [ 'items', 'settings' ],
322
+ run: function() {
323
+ var clones = [],
324
+ items = this._items,
325
+ settings = this.settings,
326
+ // TODO: Should be computed from number of min width items in stage
327
+ view = Math.max(settings.items * 2, 4),
328
+ size = Math.ceil(items.length / 2) * 2,
329
+ repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
330
+ append = '',
331
+ prepend = '';
332
+
333
+ repeat /= 2;
334
+
335
+ while (repeat > 0) {
336
+ // Switch to only using appended clones
337
+ clones.push(this.normalize(clones.length / 2, true));
338
+ $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').appendTo(this.$stage);
339
+ clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
340
+ $(items[clones[clones.length - 1]][0]).clone(true).addClass('cloned').prependTo(this.$stage);
341
+ repeat -= 1;
342
+ }
343
+ this._clones = clones;
344
+ }
345
+ }, {
346
+ filter: [ 'width', 'items', 'settings' ],
347
+ run: function() {
348
+ var rtl = this.settings.rtl ? 1 : -1,
349
+ size = this._clones.length + this._items.length,
350
+ iterator = -1,
351
+ previous = 0,
352
+ current = 0,
353
+ coordinates = [];
354
+
355
+ while (++iterator < size) {
356
+ previous = coordinates[iterator - 1] || 0;
357
+ current = this._widths[this.relative(iterator)] + this.settings.margin;
358
+ coordinates.push(previous + current * rtl);
359
+ }
360
+
361
+ this._coordinates = coordinates;
362
+ }
363
+ }, {
364
+ filter: [ 'width', 'items', 'settings' ],
365
+ run: function() {
366
+ var padding = this.settings.stagePadding,
367
+ coordinates = this._coordinates,
368
+ css = {
369
+ 'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
370
+ 'padding-left': padding || '',
371
+ 'padding-right': padding || ''
372
+ };
373
+
374
+ this.$stage.css(css);
375
+ }
376
+ }, {
377
+ filter: [ 'width', 'items', 'settings' ],
378
+ run: function(cache) {
379
+ var iterator = this._coordinates.length,
380
+ grid = !this.settings.autoWidth,
381
+ items = this.$stage.children();
382
+
383
+ if (grid && cache.items.merge) {
384
+ while (iterator--) {
385
+ cache.css.width = this._widths[this.relative(iterator)];
386
+ items.eq(iterator).css(cache.css);
387
+ }
388
+ } else if (grid) {
389
+ cache.css.width = cache.items.width;
390
+ items.css(cache.css);
391
+ }
392
+ }
393
+ }, {
394
+ filter: [ 'items' ],
395
+ run: function() {
396
+ this._coordinates.length < 1 && this.$stage.removeAttr('style');
397
+ }
398
+ }, {
399
+ filter: [ 'width', 'items', 'settings' ],
400
+ run: function(cache) {
401
+ cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
402
+ cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
403
+ this.reset(cache.current);
404
+ }
405
+ }, {
406
+ filter: [ 'position' ],
407
+ run: function() {
408
+ this.animate(this.coordinates(this._current));
409
+ }
410
+ }, {
411
+ filter: [ 'width', 'position', 'items', 'settings' ],
412
+ run: function() {
413
+ var rtl = this.settings.rtl ? 1 : -1,
414
+ padding = this.settings.stagePadding * 2,
415
+ begin = this.coordinates(this.current()) + padding,
416
+ end = begin + this.width() * rtl,
417
+ inner, outer, matches = [], i, n;
418
+
419
+ for (i = 0, n = this._coordinates.length; i < n; i++) {
420
+ inner = this._coordinates[i - 1] || 0;
421
+ outer = Math.abs(this._coordinates[i]) + padding * rtl;
422
+
423
+ if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
424
+ || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
425
+ matches.push(i);
426
+ }
427
+ }
428
+
429
+ this.$stage.children('.active').removeClass('active');
430
+ this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
431
+
432
+ this.$stage.children('.center').removeClass('center');
433
+ if (this.settings.center) {
434
+ this.$stage.children().eq(this.current()).addClass('center');
435
+ }
436
+ }
437
+ } ];
438
+
439
+ /**
440
+ * Create the stage DOM element
441
+ */
442
+ Owl.prototype.initializeStage = function() {
443
+ this.$stage = this.$element.find('.' + this.settings.stageClass);
444
+
445
+ // if the stage is already in the DOM, grab it and skip stage initialization
446
+ if (this.$stage.length) {
447
+ return;
448
+ }
449
+
450
+ this.$element.addClass(this.options.loadingClass);
451
+
452
+ // create stage
453
+ this.$stage = $('<' + this.settings.stageElement + '>', {
454
+ "class": this.settings.stageClass
455
+ }).wrap( $( '<div/>', {
456
+ "class": this.settings.stageOuterClass
457
+ }));
458
+
459
+ // append stage
460
+ this.$element.append(this.$stage.parent());
461
+ };
462
+
463
+ /**
464
+ * Create item DOM elements
465
+ */
466
+ Owl.prototype.initializeItems = function() {
467
+ var $items = this.$element.find('.owl-item');
468
+
469
+ // if the items are already in the DOM, grab them and skip item initialization
470
+ if ($items.length) {
471
+ this._items = $items.get().map(function(item) {
472
+ return $(item);
473
+ });
474
+
475
+ this._mergers = this._items.map(function() {
476
+ return 1;
477
+ });
478
+
479
+ this.refresh();
480
+
481
+ return;
482
+ }
483
+
484
+ // append content
485
+ this.replace(this.$element.children().not(this.$stage.parent()));
486
+
487
+ // check visibility
488
+ if (this.isVisible()) {
489
+ // update view
490
+ this.refresh();
491
+ } else {
492
+ // invalidate width
493
+ this.invalidate('width');
494
+ }
495
+
496
+ this.$element
497
+ .removeClass(this.options.loadingClass)
498
+ .addClass(this.options.loadedClass);
499
+ };
500
+
501
+ /**
502
+ * Initializes the carousel.
503
+ * @protected
504
+ */
505
+ Owl.prototype.initialize = function() {
506
+ this.enter('initializing');
507
+ this.trigger('initialize');
508
+
509
+ this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
510
+
511
+ if (this.settings.autoWidth && !this.is('pre-loading')) {
512
+ var imgs, nestedSelector, width;
513
+ imgs = this.$element.find('img');
514
+ nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
515
+ width = this.$element.children(nestedSelector).width();
516
+
517
+ if (imgs.length && width <= 0) {
518
+ this.preloadAutoWidthImages(imgs);
519
+ }
520
+ }
521
+
522
+ this.initializeStage();
523
+ this.initializeItems();
524
+
525
+ // register event handlers
526
+ this.registerEventHandlers();
527
+
528
+ this.leave('initializing');
529
+ this.trigger('initialized');
530
+ };
531
+
532
+ /**
533
+ * @returns {Boolean} visibility of $element
534
+ * if you know the carousel will always be visible you can set `checkVisibility` to `false` to
535
+ * prevent the expensive browser layout forced reflow the $element.is(':visible') does
536
+ */
537
+ Owl.prototype.isVisible = function() {
538
+ return this.settings.checkVisibility
539
+ ? this.$element.is(':visible')
540
+ : true;
541
+ };
542
+
543
+ /**
544
+ * Setups the current settings.
545
+ * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
546
+ * @todo Support for media queries by using `matchMedia` would be nice.
547
+ * @public
548
+ */
549
+ Owl.prototype.setup = function() {
550
+ var viewport = this.viewport(),
551
+ overwrites = this.options.responsive,
552
+ match = -1,
553
+ settings = null;
554
+
555
+ if (!overwrites) {
556
+ settings = $.extend({}, this.options);
557
+ } else {
558
+ $.each(overwrites, function(breakpoint) {
559
+ if (breakpoint <= viewport && breakpoint > match) {
560
+ match = Number(breakpoint);
561
+ }
562
+ });
563
+
564
+ settings = $.extend({}, this.options, overwrites[match]);
565
+ if (typeof settings.stagePadding === 'function') {
566
+ settings.stagePadding = settings.stagePadding();
567
+ }
568
+ delete settings.responsive;
569
+
570
+ // responsive class
571
+ if (settings.responsiveClass) {
572
+ this.$element.attr('class',
573
+ this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
574
+ );
575
+ }
576
+ }
577
+
578
+ this.trigger('change', { property: { name: 'settings', value: settings } });
579
+ this._breakpoint = match;
580
+ this.settings = settings;
581
+ this.invalidate('settings');
582
+ this.trigger('changed', { property: { name: 'settings', value: this.settings } });
583
+ };
584
+
585
+ /**
586
+ * Updates option logic if necessery.
587
+ * @protected
588
+ */
589
+ Owl.prototype.optionsLogic = function() {
590
+ if (this.settings.autoWidth) {
591
+ this.settings.stagePadding = false;
592
+ this.settings.merge = false;
593
+ }
594
+ };
595
+
596
+ /**
597
+ * Prepares an item before add.
598
+ * @todo Rename event parameter `content` to `item`.
599
+ * @protected
600
+ * @returns {jQuery|HTMLElement} - The item container.
601
+ */
602
+ Owl.prototype.prepare = function(item) {
603
+ var event = this.trigger('prepare', { content: item });
604
+
605
+ if (!event.data) {
606
+ event.data = $('<' + this.settings.itemElement + '/>')
607
+ .addClass(this.options.itemClass).append(item)
608
+ }
609
+
610
+ this.trigger('prepared', { content: event.data });
611
+
612
+ return event.data;
613
+ };
614
+
615
+ /**
616
+ * Updates the view.
617
+ * @public
618
+ */
619
+ Owl.prototype.update = function() {
620
+ var i = 0,
621
+ n = this._pipe.length,
622
+ filter = $.proxy(function(p) { return this[p] }, this._invalidated),
623
+ cache = {};
624
+
625
+ while (i < n) {
626
+ if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
627
+ this._pipe[i].run(cache);
628
+ }
629
+ i++;
630
+ }
631
+
632
+ this._invalidated = {};
633
+
634
+ !this.is('valid') && this.enter('valid');
635
+ };
636
+
637
+ /**
638
+ * Gets the width of the view.
639
+ * @public
640
+ * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
641
+ * @returns {Number} - The width of the view in pixel.
642
+ */
643
+ Owl.prototype.width = function(dimension) {
644
+ dimension = dimension || Owl.Width.Default;
645
+ switch (dimension) {
646
+ case Owl.Width.Inner:
647
+ case Owl.Width.Outer:
648
+ return this._width;
649
+ default:
650
+ return this._width - this.settings.stagePadding * 2 + this.settings.margin;
651
+ }
652
+ };
653
+
654
+ /**
655
+ * Refreshes the carousel primarily for adaptive purposes.
656
+ * @public
657
+ */
658
+ Owl.prototype.refresh = function(resizing) {
659
+ resizing = resizing || false;
660
+
661
+ this.enter('refreshing');
662
+ this.trigger('refresh');
663
+
664
+ this.setup();
665
+
666
+ this.optionsLogic();
667
+
668
+ this.$element.addClass(this.options.refreshClass);
669
+
670
+ this.update();
671
+
672
+ if (!resizing) {
673
+ this.onResize();
674
+ }
675
+
676
+ this.$element.removeClass(this.options.refreshClass);
677
+
678
+ this.leave('refreshing');
679
+ this.trigger('refreshed');
680
+ };
681
+
682
+ /**
683
+ * Checks window `resize` event.
684
+ * @protected
685
+ */
686
+ Owl.prototype.onThrottledResize = function() {
687
+ window.clearTimeout(this.resizeTimer);
688
+ this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
689
+ };
690
+
691
+ /**
692
+ * Checks window `resize` event.
693
+ * @protected
694
+ */
695
+ Owl.prototype.onResize = function() {
696
+ var resizing = true;
697
+
698
+ if (!this._items.length) {
699
+ return false;
700
+ }
701
+
702
+ if (this._width === this.$element.width()) {
703
+ return false;
704
+ }
705
+
706
+ if (!this.isVisible()) {
707
+ return false;
708
+ }
709
+
710
+ this.enter('resizing');
711
+
712
+ if (this.trigger('resize').isDefaultPrevented()) {
713
+ this.leave('resizing');
714
+ return false;
715
+ }
716
+
717
+ this.invalidate('width');
718
+
719
+ this.refresh(resizing);
720
+
721
+ this.leave('resizing');
722
+ this.trigger('resized');
723
+ };
724
+
725
+ /**
726
+ * Registers event handlers.
727
+ * @todo Check `msPointerEnabled`
728
+ * @todo #261
729
+ * @protected
730
+ */
731
+ Owl.prototype.registerEventHandlers = function() {
732
+ if ($.support.transition) {
733
+ this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
734
+ }
735
+
736
+ if (this.settings.responsive !== false) {
737
+ this.on(window, 'resize', this._handlers.onThrottledResize);
738
+ }
739
+
740
+ if (this.settings.mouseDrag) {
741
+ this.$element.addClass(this.options.dragClass);
742
+ this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
743
+ this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
744
+ }
745
+
746
+ if (this.settings.touchDrag){
747
+ this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
748
+ this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
749
+ }
750
+ };
751
+
752
+ /**
753
+ * Handles `touchstart` and `mousedown` events.
754
+ * @todo Horizontal swipe threshold as option
755
+ * @todo #261
756
+ * @protected
757
+ * @param {Event} event - The event arguments.
758
+ */
759
+ Owl.prototype.onDragStart = function(event) {
760
+ var stage = null;
761
+
762
+ if (event.which === 3) {
763
+ return;
764
+ }
765
+
766
+ if ($.support.transform) {
767
+ stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
768
+ stage = {
769
+ x: stage[stage.length === 16 ? 12 : 4],
770
+ y: stage[stage.length === 16 ? 13 : 5]
771
+ };
772
+ } else {
773
+ stage = this.$stage.position();
774
+ stage = {
775
+ x: this.settings.rtl ?
776
+ stage.left + this.$stage.width() - this.width() + this.settings.margin :
777
+ stage.left,
778
+ y: stage.top
779
+ };
780
+ }
781
+
782
+ if (this.is('animating')) {
783
+ $.support.transform ? this.animate(stage.x) : this.$stage.stop()
784
+ this.invalidate('position');
785
+ }
786
+
787
+ this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
788
+
789
+ this.speed(0);
790
+
791
+ this._drag.time = new Date().getTime();
792
+ this._drag.target = $(event.target);
793
+ this._drag.stage.start = stage;
794
+ this._drag.stage.current = stage;
795
+ this._drag.pointer = this.pointer(event);
796
+
797
+ $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
798
+
799
+ $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
800
+ var delta = this.difference(this._drag.pointer, this.pointer(event));
801
+
802
+ $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
803
+
804
+ if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
805
+ return;
806
+ }
807
+
808
+ event.preventDefault();
809
+
810
+ this.enter('dragging');
811
+ this.trigger('drag');
812
+ }, this));
813
+ };
814
+
815
+ /**
816
+ * Handles the `touchmove` and `mousemove` events.
817
+ * @todo #261
818
+ * @protected
819
+ * @param {Event} event - The event arguments.
820
+ */
821
+ Owl.prototype.onDragMove = function(event) {
822
+ var minimum = null,
823
+ maximum = null,
824
+ pull = null,
825
+ delta = this.difference(this._drag.pointer, this.pointer(event)),
826
+ stage = this.difference(this._drag.stage.start, delta);
827
+
828
+ if (!this.is('dragging')) {
829
+ return;
830
+ }
831
+
832
+ event.preventDefault();
833
+
834
+ if (this.settings.loop) {
835
+ minimum = this.coordinates(this.minimum());
836
+ maximum = this.coordinates(this.maximum() + 1) - minimum;
837
+ stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
838
+ } else {
839
+ minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
840
+ maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
841
+ pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
842
+ stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
843
+ }
844
+
845
+ this._drag.stage.current = stage;
846
+
847
+ this.animate(stage.x);
848
+ };
849
+
850
+ /**
851
+ * Handles the `touchend` and `mouseup` events.
852
+ * @todo #261
853
+ * @todo Threshold for click event
854
+ * @protected
855
+ * @param {Event} event - The event arguments.
856
+ */
857
+ Owl.prototype.onDragEnd = function(event) {
858
+ var delta = this.difference(this._drag.pointer, this.pointer(event)),
859
+ stage = this._drag.stage.current,
860
+ direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
861
+
862
+ $(document).off('.owl.core');
863
+
864
+ this.$element.removeClass(this.options.grabClass);
865
+
866
+ if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
867
+ this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
868
+ this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
869
+ this.invalidate('position');
870
+ this.update();
871
+
872
+ this._drag.direction = direction;
873
+
874
+ if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
875
+ this._drag.target.one('click.owl.core', function() { return false; });
876
+ }
877
+ }
878
+
879
+ if (!this.is('dragging')) {
880
+ return;
881
+ }
882
+
883
+ this.leave('dragging');
884
+ this.trigger('dragged');
885
+ };
886
+
887
+ /**
888
+ * Gets absolute position of the closest item for a coordinate.
889
+ * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
890
+ * @protected
891
+ * @param {Number} coordinate - The coordinate in pixel.
892
+ * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
893
+ * @return {Number} - The absolute position of the closest item.
894
+ */
895
+ Owl.prototype.closest = function(coordinate, direction) {
896
+ var position = -1,
897
+ pull = 30,
898
+ width = this.width(), // visible carousel width
899
+ count = this.settings.items,
900
+ itemWidth = Math.round(width / count),
901
+ coordinates = this.coordinates();
902
+
903
+ if (!this.settings.freeDrag) {
904
+ // check closest item
905
+ $.each(coordinates, $.proxy(function(index, value) {
906
+ // on a left pull, check on current index
907
+ if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
908
+ position = index;
909
+ // on a right pull, check on previous index
910
+ // to do so, subtract width from value and set position = index + 1
911
+ } else if (direction === 'right' && coordinate > value - itemWidth - pull && coordinate < value - itemWidth + pull) {
912
+ position = index + 1;
913
+ } else if (this.op(coordinate, '<', value)
914
+ && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
915
+ position = direction === 'left' ? index + 1 : index;
916
+ }
917
+ return position === -1;
918
+ }, this));
919
+ }
920
+
921
+ if (!this.settings.loop) {
922
+ // non loop boundries
923
+ if (this.op(coordinate, '>', coordinates[this.minimum()])) {
924
+ position = coordinate = this.minimum();
925
+ } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
926
+ position = coordinate = this.maximum();
927
+ }
928
+ }
929
+
930
+ return position;
931
+ };
932
+
933
+ /**
934
+ * Animates the stage.
935
+ * @todo #270
936
+ * @public
937
+ * @param {Number} coordinate - The coordinate in pixels.
938
+ */
939
+ Owl.prototype.animate = function(coordinate) {
940
+ var animate = this.speed() > 0;
941
+
942
+ this.is('animating') && this.onTransitionEnd();
943
+
944
+ if (animate) {
945
+ this.enter('animating');
946
+ this.trigger('translate');
947
+ }
948
+
949
+ if ($.support.transform3d && $.support.transition) {
950
+ this.$stage.css({
951
+ transform: 'translate3d(' + coordinate + 'px,0px,0px)',
952
+ transition: (this.speed() / 1000) + 's' + (
953
+ this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
954
+ )
955
+ });
956
+ } else if (animate) {
957
+ this.$stage.animate({
958
+ left: coordinate + 'px'
959
+ }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
960
+ } else {
961
+ this.$stage.css({
962
+ left: coordinate + 'px'
963
+ });
964
+ }
965
+ };
966
+
967
+ /**
968
+ * Checks whether the carousel is in a specific state or not.
969
+ * @param {String} state - The state to check.
970
+ * @returns {Boolean} - The flag which indicates if the carousel is busy.
971
+ */
972
+ Owl.prototype.is = function(state) {
973
+ return this._states.current[state] && this._states.current[state] > 0;
974
+ };
975
+
976
+ /**
977
+ * Sets the absolute position of the current item.
978
+ * @public
979
+ * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
980
+ * @returns {Number} - The absolute position of the current item.
981
+ */
982
+ Owl.prototype.current = function(position) {
983
+ if (position === undefined) {
984
+ return this._current;
985
+ }
986
+
987
+ if (this._items.length === 0) {
988
+ return undefined;
989
+ }
990
+
991
+ position = this.normalize(position);
992
+
993
+ if (this._current !== position) {
994
+ var event = this.trigger('change', { property: { name: 'position', value: position } });
995
+
996
+ if (event.data !== undefined) {
997
+ position = this.normalize(event.data);
998
+ }
999
+
1000
+ this._current = position;
1001
+
1002
+ this.invalidate('position');
1003
+
1004
+ this.trigger('changed', { property: { name: 'position', value: this._current } });
1005
+ }
1006
+
1007
+ return this._current;
1008
+ };
1009
+
1010
+ /**
1011
+ * Invalidates the given part of the update routine.
1012
+ * @param {String} [part] - The part to invalidate.
1013
+ * @returns {Array.<String>} - The invalidated parts.
1014
+ */
1015
+ Owl.prototype.invalidate = function(part) {
1016
+ if ($.type(part) === 'string') {
1017
+ this._invalidated[part] = true;
1018
+ this.is('valid') && this.leave('valid');
1019
+ }
1020
+ return $.map(this._invalidated, function(v, i) { return i });
1021
+ };
1022
+
1023
+ /**
1024
+ * Resets the absolute position of the current item.
1025
+ * @public
1026
+ * @param {Number} position - The absolute position of the new item.
1027
+ */
1028
+ Owl.prototype.reset = function(position) {
1029
+ position = this.normalize(position);
1030
+
1031
+ if (position === undefined) {
1032
+ return;
1033
+ }
1034
+
1035
+ this._speed = 0;
1036
+ this._current = position;
1037
+
1038
+ this.suppress([ 'translate', 'translated' ]);
1039
+
1040
+ this.animate(this.coordinates(position));
1041
+
1042
+ this.release([ 'translate', 'translated' ]);
1043
+ };
1044
+
1045
+ /**
1046
+ * Normalizes an absolute or a relative position of an item.
1047
+ * @public
1048
+ * @param {Number} position - The absolute or relative position to normalize.
1049
+ * @param {Boolean} [relative=false] - Whether the given position is relative or not.
1050
+ * @returns {Number} - The normalized position.
1051
+ */
1052
+ Owl.prototype.normalize = function(position, relative) {
1053
+ var n = this._items.length,
1054
+ m = relative ? 0 : this._clones.length;
1055
+
1056
+ if (!this.isNumeric(position) || n < 1) {
1057
+ position = undefined;
1058
+ } else if (position < 0 || position >= n + m) {
1059
+ position = ((position - m / 2) % n + n) % n + m / 2;
1060
+ }
1061
+
1062
+ return position;
1063
+ };
1064
+
1065
+ /**
1066
+ * Converts an absolute position of an item into a relative one.
1067
+ * @public
1068
+ * @param {Number} position - The absolute position to convert.
1069
+ * @returns {Number} - The converted position.
1070
+ */
1071
+ Owl.prototype.relative = function(position) {
1072
+ position -= this._clones.length / 2;
1073
+ return this.normalize(position, true);
1074
+ };
1075
+
1076
+ /**
1077
+ * Gets the maximum position for the current item.
1078
+ * @public
1079
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1080
+ * @returns {Number}
1081
+ */
1082
+ Owl.prototype.maximum = function(relative) {
1083
+ var settings = this.settings,
1084
+ maximum = this._coordinates.length,
1085
+ iterator,
1086
+ reciprocalItemsWidth,
1087
+ elementWidth;
1088
+
1089
+ if (settings.loop) {
1090
+ maximum = this._clones.length / 2 + this._items.length - 1;
1091
+ } else if (settings.autoWidth || settings.merge) {
1092
+ iterator = this._items.length;
1093
+ if (iterator) {
1094
+ reciprocalItemsWidth = this._items[--iterator].width();
1095
+ elementWidth = this.$element.width();
1096
+ while (iterator--) {
1097
+ reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
1098
+ if (reciprocalItemsWidth > elementWidth) {
1099
+ break;
1100
+ }
1101
+ }
1102
+ }
1103
+ maximum = iterator + 1;
1104
+ } else if (settings.center) {
1105
+ maximum = this._items.length - 1;
1106
+ } else {
1107
+ maximum = this._items.length - settings.items;
1108
+ }
1109
+
1110
+ if (relative) {
1111
+ maximum -= this._clones.length / 2;
1112
+ }
1113
+
1114
+ return Math.max(maximum, 0);
1115
+ };
1116
+
1117
+ /**
1118
+ * Gets the minimum position for the current item.
1119
+ * @public
1120
+ * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
1121
+ * @returns {Number}
1122
+ */
1123
+ Owl.prototype.minimum = function(relative) {
1124
+ return relative ? 0 : this._clones.length / 2;
1125
+ };
1126
+
1127
+ /**
1128
+ * Gets an item at the specified relative position.
1129
+ * @public
1130
+ * @param {Number} [position] - The relative position of the item.
1131
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1132
+ */
1133
+ Owl.prototype.items = function(position) {
1134
+ if (position === undefined) {
1135
+ return this._items.slice();
1136
+ }
1137
+
1138
+ position = this.normalize(position, true);
1139
+ return this._items[position];
1140
+ };
1141
+
1142
+ /**
1143
+ * Gets an item at the specified relative position.
1144
+ * @public
1145
+ * @param {Number} [position] - The relative position of the item.
1146
+ * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
1147
+ */
1148
+ Owl.prototype.mergers = function(position) {
1149
+ if (position === undefined) {
1150
+ return this._mergers.slice();
1151
+ }
1152
+
1153
+ position = this.normalize(position, true);
1154
+ return this._mergers[position];
1155
+ };
1156
+
1157
+ /**
1158
+ * Gets the absolute positions of clones for an item.
1159
+ * @public
1160
+ * @param {Number} [position] - The relative position of the item.
1161
+ * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
1162
+ */
1163
+ Owl.prototype.clones = function(position) {
1164
+ var odd = this._clones.length / 2,
1165
+ even = odd + this._items.length,
1166
+ map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
1167
+
1168
+ if (position === undefined) {
1169
+ return $.map(this._clones, function(v, i) { return map(i) });
1170
+ }
1171
+
1172
+ return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
1173
+ };
1174
+
1175
+ /**
1176
+ * Sets the current animation speed.
1177
+ * @public
1178
+ * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
1179
+ * @returns {Number} - The current animation speed in milliseconds.
1180
+ */
1181
+ Owl.prototype.speed = function(speed) {
1182
+ if (speed !== undefined) {
1183
+ this._speed = speed;
1184
+ }
1185
+
1186
+ return this._speed;
1187
+ };
1188
+
1189
+ /**
1190
+ * Gets the coordinate of an item.
1191
+ * @todo The name of this method is missleanding.
1192
+ * @public
1193
+ * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
1194
+ * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
1195
+ */
1196
+ Owl.prototype.coordinates = function(position) {
1197
+ var multiplier = 1,
1198
+ newPosition = position - 1,
1199
+ coordinate;
1200
+
1201
+ if (position === undefined) {
1202
+ return $.map(this._coordinates, $.proxy(function(coordinate, index) {
1203
+ return this.coordinates(index);
1204
+ }, this));
1205
+ }
1206
+
1207
+ if (this.settings.center) {
1208
+ if (this.settings.rtl) {
1209
+ multiplier = -1;
1210
+ newPosition = position + 1;
1211
+ }
1212
+
1213
+ coordinate = this._coordinates[position];
1214
+ coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
1215
+ } else {
1216
+ coordinate = this._coordinates[newPosition] || 0;
1217
+ }
1218
+
1219
+ coordinate = Math.ceil(coordinate);
1220
+
1221
+ return coordinate;
1222
+ };
1223
+
1224
+ /**
1225
+ * Calculates the speed for a translation.
1226
+ * @protected
1227
+ * @param {Number} from - The absolute position of the start item.
1228
+ * @param {Number} to - The absolute position of the target item.
1229
+ * @param {Number} [factor=undefined] - The time factor in milliseconds.
1230
+ * @returns {Number} - The time in milliseconds for the translation.
1231
+ */
1232
+ Owl.prototype.duration = function(from, to, factor) {
1233
+ if (factor === 0) {
1234
+ return 0;
1235
+ }
1236
+
1237
+ return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
1238
+ };
1239
+
1240
+ /**
1241
+ * Slides to the specified item.
1242
+ * @public
1243
+ * @param {Number} position - The position of the item.
1244
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1245
+ */
1246
+ Owl.prototype.to = function(position, speed) {
1247
+ var current = this.current(),
1248
+ revert = null,
1249
+ distance = position - this.relative(current),
1250
+ direction = (distance > 0) - (distance < 0),
1251
+ items = this._items.length,
1252
+ minimum = this.minimum(),
1253
+ maximum = this.maximum();
1254
+
1255
+ if (this.settings.loop) {
1256
+ if (!this.settings.rewind && Math.abs(distance) > items / 2) {
1257
+ distance += direction * -1 * items;
1258
+ }
1259
+
1260
+ position = current + distance;
1261
+ revert = ((position - minimum) % items + items) % items + minimum;
1262
+
1263
+ if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
1264
+ current = revert - distance;
1265
+ position = revert;
1266
+ this.reset(current);
1267
+ }
1268
+ } else if (this.settings.rewind) {
1269
+ maximum += 1;
1270
+ position = (position % maximum + maximum) % maximum;
1271
+ } else {
1272
+ position = Math.max(minimum, Math.min(maximum, position));
1273
+ }
1274
+
1275
+ this.speed(this.duration(current, position, speed));
1276
+ this.current(position);
1277
+
1278
+ if (this.isVisible()) {
1279
+ this.update();
1280
+ }
1281
+ };
1282
+
1283
+ /**
1284
+ * Slides to the next item.
1285
+ * @public
1286
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1287
+ */
1288
+ Owl.prototype.next = function(speed) {
1289
+ speed = speed || false;
1290
+ this.to(this.relative(this.current()) + 1, speed);
1291
+ };
1292
+
1293
+ /**
1294
+ * Slides to the previous item.
1295
+ * @public
1296
+ * @param {Number} [speed] - The time in milliseconds for the transition.
1297
+ */
1298
+ Owl.prototype.prev = function(speed) {
1299
+ speed = speed || false;
1300
+ this.to(this.relative(this.current()) - 1, speed);
1301
+ };
1302
+
1303
+ /**
1304
+ * Handles the end of an animation.
1305
+ * @protected
1306
+ * @param {Event} event - The event arguments.
1307
+ */
1308
+ Owl.prototype.onTransitionEnd = function(event) {
1309
+
1310
+ // if css2 animation then event object is undefined
1311
+ if (event !== undefined) {
1312
+ event.stopPropagation();
1313
+
1314
+ // Catch only owl-stage transitionEnd event
1315
+ if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
1316
+ return false;
1317
+ }
1318
+ }
1319
+
1320
+ this.leave('animating');
1321
+ this.trigger('translated');
1322
+ };
1323
+
1324
+ /**
1325
+ * Gets viewport width.
1326
+ * @protected
1327
+ * @return {Number} - The width in pixel.
1328
+ */
1329
+ Owl.prototype.viewport = function() {
1330
+ var width;
1331
+ if (this.options.responsiveBaseElement !== window) {
1332
+ width = $(this.options.responsiveBaseElement).width();
1333
+ } else if (window.innerWidth) {
1334
+ width = window.innerWidth;
1335
+ } else if (document.documentElement && document.documentElement.clientWidth) {
1336
+ width = document.documentElement.clientWidth;
1337
+ } else {
1338
+ console.warn('Can not detect viewport width.');
1339
+ }
1340
+ return width;
1341
+ };
1342
+
1343
+ /**
1344
+ * Replaces the current content.
1345
+ * @public
1346
+ * @param {HTMLElement|jQuery|String} content - The new content.
1347
+ */
1348
+ Owl.prototype.replace = function(content) {
1349
+ this.$stage.empty();
1350
+ this._items = [];
1351
+
1352
+ if (content) {
1353
+ content = (content instanceof jQuery) ? content : $(content);
1354
+ }
1355
+
1356
+ if (this.settings.nestedItemSelector) {
1357
+ content = content.find('.' + this.settings.nestedItemSelector);
1358
+ }
1359
+
1360
+ content.filter(function() {
1361
+ return this.nodeType === 1;
1362
+ }).each($.proxy(function(index, item) {
1363
+ item = this.prepare(item);
1364
+ this.$stage.append(item);
1365
+ this._items.push(item);
1366
+ this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1367
+ }, this));
1368
+
1369
+ this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
1370
+
1371
+ this.invalidate('items');
1372
+ };
1373
+
1374
+ /**
1375
+ * Adds an item.
1376
+ * @todo Use `item` instead of `content` for the event arguments.
1377
+ * @public
1378
+ * @param {HTMLElement|jQuery|String} content - The item content to add.
1379
+ * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
1380
+ */
1381
+ Owl.prototype.add = function(content, position) {
1382
+ var current = this.relative(this._current);
1383
+
1384
+ position = position === undefined ? this._items.length : this.normalize(position, true);
1385
+ content = content instanceof jQuery ? content : $(content);
1386
+
1387
+ this.trigger('add', { content: content, position: position });
1388
+
1389
+ content = this.prepare(content);
1390
+
1391
+ if (this._items.length === 0 || position === this._items.length) {
1392
+ this._items.length === 0 && this.$stage.append(content);
1393
+ this._items.length !== 0 && this._items[position - 1].after(content);
1394
+ this._items.push(content);
1395
+ this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1396
+ } else {
1397
+ this._items[position].before(content);
1398
+ this._items.splice(position, 0, content);
1399
+ this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
1400
+ }
1401
+
1402
+ this._items[current] && this.reset(this._items[current].index());
1403
+
1404
+ this.invalidate('items');
1405
+
1406
+ this.trigger('added', { content: content, position: position });
1407
+ };
1408
+
1409
+ /**
1410
+ * Removes an item by its position.
1411
+ * @todo Use `item` instead of `content` for the event arguments.
1412
+ * @public
1413
+ * @param {Number} position - The relative position of the item to remove.
1414
+ */
1415
+ Owl.prototype.remove = function(position) {
1416
+ position = this.normalize(position, true);
1417
+
1418
+ if (position === undefined) {
1419
+ return;
1420
+ }
1421
+
1422
+ this.trigger('remove', { content: this._items[position], position: position });
1423
+
1424
+ this._items[position].remove();
1425
+ this._items.splice(position, 1);
1426
+ this._mergers.splice(position, 1);
1427
+
1428
+ this.invalidate('items');
1429
+
1430
+ this.trigger('removed', { content: null, position: position });
1431
+ };
1432
+
1433
+ /**
1434
+ * Preloads images with auto width.
1435
+ * @todo Replace by a more generic approach
1436
+ * @protected
1437
+ */
1438
+ Owl.prototype.preloadAutoWidthImages = function(images) {
1439
+ images.each($.proxy(function(i, element) {
1440
+ this.enter('pre-loading');
1441
+ element = $(element);
1442
+ $(new Image()).one('load', $.proxy(function(e) {
1443
+ element.attr('src', e.target.src);
1444
+ element.css('opacity', 1);
1445
+ this.leave('pre-loading');
1446
+ !this.is('pre-loading') && !this.is('initializing') && this.refresh();
1447
+ }, this)).attr('src', (window.devicePixelRatio > 1) ? element.attr('data-src-retina') : element.attr('data-src') || element.attr('src'));
1448
+ }, this));
1449
+ };
1450
+
1451
+ /**
1452
+ * Destroys the carousel.
1453
+ * @public
1454
+ */
1455
+ Owl.prototype.destroy = function() {
1456
+
1457
+ this.$element.off('.owl.core');
1458
+ this.$stage.off('.owl.core');
1459
+ $(document).off('.owl.core');
1460
+
1461
+ if (this.settings.responsive !== false) {
1462
+ window.clearTimeout(this.resizeTimer);
1463
+ this.off(window, 'resize', this._handlers.onThrottledResize);
1464
+ }
1465
+
1466
+ for (var i in this._plugins) {
1467
+ this._plugins[i].destroy();
1468
+ }
1469
+
1470
+ this.$stage.children('.cloned').remove();
1471
+
1472
+ this.$stage.unwrap();
1473
+ this.$stage.children().contents().unwrap();
1474
+ this.$stage.children().unwrap();
1475
+ this.$stage.remove();
1476
+ this.$element
1477
+ .removeClass(this.options.refreshClass)
1478
+ .removeClass(this.options.loadingClass)
1479
+ .removeClass(this.options.loadedClass)
1480
+ .removeClass(this.options.rtlClass)
1481
+ .removeClass(this.options.dragClass)
1482
+ .removeClass(this.options.grabClass)
1483
+ .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
1484
+ .removeData('owl.carousel');
1485
+ };
1486
+
1487
+ /**
1488
+ * Operators to calculate right-to-left and left-to-right.
1489
+ * @protected
1490
+ * @param {Number} [a] - The left side operand.
1491
+ * @param {String} [o] - The operator.
1492
+ * @param {Number} [b] - The right side operand.
1493
+ */
1494
+ Owl.prototype.op = function(a, o, b) {
1495
+ var rtl = this.settings.rtl;
1496
+ switch (o) {
1497
+ case '<':
1498
+ return rtl ? a > b : a < b;
1499
+ case '>':
1500
+ return rtl ? a < b : a > b;
1501
+ case '>=':
1502
+ return rtl ? a <= b : a >= b;
1503
+ case '<=':
1504
+ return rtl ? a >= b : a <= b;
1505
+ default:
1506
+ break;
1507
+ }
1508
+ };
1509
+
1510
+ /**
1511
+ * Attaches to an internal event.
1512
+ * @protected
1513
+ * @param {HTMLElement} element - The event source.
1514
+ * @param {String} event - The event name.
1515
+ * @param {Function} listener - The event handler to attach.
1516
+ * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
1517
+ */
1518
+ Owl.prototype.on = function(element, event, listener, capture) {
1519
+ if (element.addEventListener) {
1520
+ element.addEventListener(event, listener, capture);
1521
+ } else if (element.attachEvent) {
1522
+ element.attachEvent('on' + event, listener);
1523
+ }
1524
+ };
1525
+
1526
+ /**
1527
+ * Detaches from an internal event.
1528
+ * @protected
1529
+ * @param {HTMLElement} element - The event source.
1530
+ * @param {String} event - The event name.
1531
+ * @param {Function} listener - The attached event handler to detach.
1532
+ * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
1533
+ */
1534
+ Owl.prototype.off = function(element, event, listener, capture) {
1535
+ if (element.removeEventListener) {
1536
+ element.removeEventListener(event, listener, capture);
1537
+ } else if (element.detachEvent) {
1538
+ element.detachEvent('on' + event, listener);
1539
+ }
1540
+ };
1541
+
1542
+ /**
1543
+ * Triggers a public event.
1544
+ * @todo Remove `status`, `relatedTarget` should be used instead.
1545
+ * @protected
1546
+ * @param {String} name - The event name.
1547
+ * @param {*} [data=null] - The event data.
1548
+ * @param {String} [namespace=carousel] - The event namespace.
1549
+ * @param {String} [state] - The state which is associated with the event.
1550
+ * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
1551
+ * @returns {Event} - The event arguments.
1552
+ */
1553
+ Owl.prototype.trigger = function(name, data, namespace, state, enter) {
1554
+ var status = {
1555
+ item: { count: this._items.length, index: this.current() }
1556
+ }, handler = $.camelCase(
1557
+ $.grep([ 'on', name, namespace ], function(v) { return v })
1558
+ .join('-').toLowerCase()
1559
+ ), event = $.Event(
1560
+ [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
1561
+ $.extend({ relatedTarget: this }, status, data)
1562
+ );
1563
+
1564
+ if (!this._supress[name]) {
1565
+ $.each(this._plugins, function(name, plugin) {
1566
+ if (plugin.onTrigger) {
1567
+ plugin.onTrigger(event);
1568
+ }
1569
+ });
1570
+
1571
+ this.register({ type: Owl.Type.Event, name: name });
1572
+ this.$element.trigger(event);
1573
+
1574
+ if (this.settings && typeof this.settings[handler] === 'function') {
1575
+ this.settings[handler].call(this, event);
1576
+ }
1577
+ }
1578
+
1579
+ return event;
1580
+ };
1581
+
1582
+ /**
1583
+ * Enters a state.
1584
+ * @param name - The state name.
1585
+ */
1586
+ Owl.prototype.enter = function(name) {
1587
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1588
+ if (this._states.current[name] === undefined) {
1589
+ this._states.current[name] = 0;
1590
+ }
1591
+
1592
+ this._states.current[name]++;
1593
+ }, this));
1594
+ };
1595
+
1596
+ /**
1597
+ * Leaves a state.
1598
+ * @param name - The state name.
1599
+ */
1600
+ Owl.prototype.leave = function(name) {
1601
+ $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
1602
+ this._states.current[name]--;
1603
+ }, this));
1604
+ };
1605
+
1606
+ /**
1607
+ * Registers an event or state.
1608
+ * @public
1609
+ * @param {Object} object - The event or state to register.
1610
+ */
1611
+ Owl.prototype.register = function(object) {
1612
+ if (object.type === Owl.Type.Event) {
1613
+ if (!$.event.special[object.name]) {
1614
+ $.event.special[object.name] = {};
1615
+ }
1616
+
1617
+ if (!$.event.special[object.name].owl) {
1618
+ var _default = $.event.special[object.name]._default;
1619
+ $.event.special[object.name]._default = function(e) {
1620
+ if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
1621
+ return _default.apply(this, arguments);
1622
+ }
1623
+ return e.namespace && e.namespace.indexOf('owl') > -1;
1624
+ };
1625
+ $.event.special[object.name].owl = true;
1626
+ }
1627
+ } else if (object.type === Owl.Type.State) {
1628
+ if (!this._states.tags[object.name]) {
1629
+ this._states.tags[object.name] = object.tags;
1630
+ } else {
1631
+ this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
1632
+ }
1633
+
1634
+ this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
1635
+ return $.inArray(tag, this._states.tags[object.name]) === i;
1636
+ }, this));
1637
+ }
1638
+ };
1639
+
1640
+ /**
1641
+ * Suppresses events.
1642
+ * @protected
1643
+ * @param {Array.<String>} events - The events to suppress.
1644
+ */
1645
+ Owl.prototype.suppress = function(events) {
1646
+ $.each(events, $.proxy(function(index, event) {
1647
+ this._supress[event] = true;
1648
+ }, this));
1649
+ };
1650
+
1651
+ /**
1652
+ * Releases suppressed events.
1653
+ * @protected
1654
+ * @param {Array.<String>} events - The events to release.
1655
+ */
1656
+ Owl.prototype.release = function(events) {
1657
+ $.each(events, $.proxy(function(index, event) {
1658
+ delete this._supress[event];
1659
+ }, this));
1660
+ };
1661
+
1662
+ /**
1663
+ * Gets unified pointer coordinates from event.
1664
+ * @todo #261
1665
+ * @protected
1666
+ * @param {Event} - The `mousedown` or `touchstart` event.
1667
+ * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
1668
+ */
1669
+ Owl.prototype.pointer = function(event) {
1670
+ var result = { x: null, y: null };
1671
+
1672
+ event = event.originalEvent || event || window.event;
1673
+
1674
+ event = event.touches && event.touches.length ?
1675
+ event.touches[0] : event.changedTouches && event.changedTouches.length ?
1676
+ event.changedTouches[0] : event;
1677
+
1678
+ if (event.pageX) {
1679
+ result.x = event.pageX;
1680
+ result.y = event.pageY;
1681
+ } else {
1682
+ result.x = event.clientX;
1683
+ result.y = event.clientY;
1684
+ }
1685
+
1686
+ return result;
1687
+ };
1688
+
1689
+ /**
1690
+ * Determines if the input is a Number or something that can be coerced to a Number
1691
+ * @protected
1692
+ * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
1693
+ * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
1694
+ */
1695
+ Owl.prototype.isNumeric = function(number) {
1696
+ return !isNaN(parseFloat(number));
1697
+ };
1698
+
1699
+ /**
1700
+ * Gets the difference of two vectors.
1701
+ * @todo #261
1702
+ * @protected
1703
+ * @param {Object} - The first vector.
1704
+ * @param {Object} - The second vector.
1705
+ * @returns {Object} - The difference.
1706
+ */
1707
+ Owl.prototype.difference = function(first, second) {
1708
+ return {
1709
+ x: first.x - second.x,
1710
+ y: first.y - second.y
1711
+ };
1712
+ };
1713
+
1714
+ /**
1715
+ * The jQuery Plugin for the Owl Carousel
1716
+ * @todo Navigation plugin `next` and `prev`
1717
+ * @public
1718
+ */
1719
+ $.fn.owlCarousel = function(option) {
1720
+ var args = Array.prototype.slice.call(arguments, 1);
1721
+
1722
+ return this.each(function() {
1723
+ var $this = $(this),
1724
+ data = $this.data('owl.carousel');
1725
+
1726
+ if (!data) {
1727
+ data = new Owl(this, typeof option == 'object' && option);
1728
+ $this.data('owl.carousel', data);
1729
+
1730
+ $.each([
1731
+ 'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
1732
+ ], function(i, event) {
1733
+ data.register({ type: Owl.Type.Event, name: event });
1734
+ data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
1735
+ if (e.namespace && e.relatedTarget !== this) {
1736
+ this.suppress([ event ]);
1737
+ data[event].apply(this, [].slice.call(arguments, 1));
1738
+ this.release([ event ]);
1739
+ }
1740
+ }, data));
1741
+ });
1742
+ }
1743
+
1744
+ if (typeof option == 'string' && option.charAt(0) !== '_') {
1745
+ data[option].apply(data, args);
1746
+ }
1747
+ });
1748
+ };
1749
+
1750
+ /**
1751
+ * The constructor for the jQuery Plugin
1752
+ * @public
1753
+ */
1754
+ $.fn.owlCarousel.Constructor = Owl;
1755
+
1756
+ })(window.Zepto || window.jQuery, window, document);
public/js/wpvr-public.js CHANGED
@@ -27,7 +27,7 @@
27
  * single DOM-ready or window-load handler for a particular page.
28
  * Although scripts in the WordPress core, Plugins and Themes may be
29
  * practising this, we should strive to set a better example in our own work.
30
- */
31
 
32
  })( jQuery );
33
 
27
  * single DOM-ready or window-load handler for a particular page.
28
  * Although scripts in the WordPress core, Plugins and Themes may be
29
  * practising this, we should strive to set a better example in our own work.
30
+ */
31
 
32
  })( jQuery );
33
 
src/index.js CHANGED
@@ -55,8 +55,16 @@ class wpvredit extends Component {
55
  } )
56
  ),
57
 
 
 
 
 
 
 
 
 
58
  <p className="wpvr-block-content">
59
- WPVR id={this.props.attributes.id}, Width={this.props.attributes.width}px, Height={this.props.attributes.height}px
60
  </p>
61
 
62
  ];
55
  } )
56
  ),
57
 
58
+ el( InspectorControls, {},
59
+ el( TextControl, {
60
+ label: 'Radius',
61
+ value: this.props.attributes.radius,
62
+ onChange: ( value ) => { this.props.setAttributes( { radius: value } ); },
63
+ } )
64
+ ),
65
+
66
  <p className="wpvr-block-content">
67
+ WPVR id={this.props.attributes.id}, Width={this.props.attributes.width}px, Height={this.props.attributes.height}px, Radius={this.props.attributes.radius}px
68
  </p>
69
 
70
  ];
wpvr.php CHANGED
@@ -16,7 +16,7 @@
16
  * Plugin Name: WP VR
17
  * Plugin URI: https://rextheme.com/wpvr/
18
  * Description: WP VR - 360 Panorama and virtual tour creator for WordPress is a customized panaroma & virtual builder tool for WordPress Website.
19
- * Version: 3.0.0
20
  * Author: Rextheme
21
  * Author URI: http://rextheme.com/
22
  * License: GPL-2.0+
@@ -149,6 +149,10 @@ function wpvr_block() {
149
  'type' => 'string',
150
  'default' => '400',
151
  ),
 
 
 
 
152
  'content' => array(
153
  'type' => 'string',
154
  'source'=> 'html',
@@ -177,7 +181,9 @@ function wpvr_block_render( $attributes ) {
177
  if (isset($attributes['height'])) {
178
  $height = $attributes['height'];
179
  }
180
-
 
 
181
 
182
  $postdata = get_post_meta( $id, 'panodata', true );
183
  $panoid = 'pano'.$id;
@@ -231,6 +237,11 @@ function wpvr_block_render( $attributes ) {
231
  $control = $postdata['showControls'];
232
  }
233
 
 
 
 
 
 
234
  $gyro = false;
235
  if (isset($postdata['gyro'])) {
236
  $gyro = $postdata['gyro'];
@@ -566,15 +577,29 @@ function wpvr_block_render( $attributes ) {
566
 
567
  if ($width == 'fullwidth') {
568
  if (wpvr_isMobileDevice()) {
569
- $html .= '<div id="pano'.$id.'" class="pano-wrap" style="text-align:center;" >';
570
  }
571
  else {
572
- $html .= '<div id="pano'.$id.'" class="pano-wrap vrfullwidth" style=" text-align:center; height: '.$height.'px;" >';
573
  }
574
  }
575
  else {
576
- $html .= '<div id="pano'.$id.'" class="pano-wrap" style=" text-align:center; width: '.$width.'px; height: '.$height.'px; margin: 0 auto;">';
577
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  $html .= '<i class="fa fa-times cross"></i>';
579
  $html .= '<div class="custom-ifram" style="display: none;">';
580
  $html .= '</div>';
@@ -598,7 +623,17 @@ function wpvr_block_render( $attributes ) {
598
  $html .= '}';
599
  $html .= '}';
600
  $html .= '}';
601
- $html .= 'pannellum.viewer(response[0]["panoid"], scenes);';
 
 
 
 
 
 
 
 
 
 
602
  $html .= '</script>';
603
  //script end
604
  return $html;
16
  * Plugin Name: WP VR
17
  * Plugin URI: https://rextheme.com/wpvr/
18
  * Description: WP VR - 360 Panorama and virtual tour creator for WordPress is a customized panaroma & virtual builder tool for WordPress Website.
19
+ * Version: 3.1.0
20
  * Author: Rextheme
21
  * Author URI: http://rextheme.com/
22
  * License: GPL-2.0+
149
  'type' => 'string',
150
  'default' => '400',
151
  ),
152
+ 'radius' => array(
153
+ 'type' => 'string',
154
+ 'default' => '0',
155
+ ),
156
  'content' => array(
157
  'type' => 'string',
158
  'source'=> 'html',
181
  if (isset($attributes['height'])) {
182
  $height = $attributes['height'];
183
  }
184
+ if(isset($attributes['radius'])) {
185
+ $radius = $attributes['radius'].'px';
186
+ }
187
 
188
  $postdata = get_post_meta( $id, 'panodata', true );
189
  $panoid = 'pano'.$id;
237
  $control = $postdata['showControls'];
238
  }
239
 
240
+ $vrgallery = false;
241
+ if (isset($postdata['vrgallery'])) {
242
+ $vrgallery = $postdata['vrgallery'];
243
+ }
244
+
245
  $gyro = false;
246
  if (isset($postdata['gyro'])) {
247
  $gyro = $postdata['gyro'];
577
 
578
  if ($width == 'fullwidth') {
579
  if (wpvr_isMobileDevice()) {
580
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style="text-align:center; border-radius:'.$radius.';" >';
581
  }
582
  else {
583
+ $html .= '<div id="pano'.$id.'" class="pano-wrap vrfullwidth" style=" text-align:center; height: '.$height.'px; border-radius:'.$radius.'; " >';
584
  }
585
  }
586
  else {
587
+ $html .= '<div id="pano'.$id.'" class="pano-wrap" style=" text-align:center; width: '.$width.'px; height: '.$height.'px; margin: 0 auto; border-radius:'.$radius.';">';
588
+ }
589
+ if ($vrgallery) {
590
+ //===Carousal setup===//
591
+ $html .= '<div id="sccontrols" class="scene-gallery owl-carousel owl-theme">';
592
+ if (isset($panodata["scene-list"])) {
593
+ foreach ($panodata["scene-list"] as $panoscenes) {
594
+ $scene_key = $panoscenes['scene-id'];
595
+ $img_src_url = $panoscenes['scene-attachment-url'];
596
+ $html .= '<ul style="width:150px;"><li><img class="scctrl" id="'.$scene_key.'_gallery_'.$id.'" src="'.$img_src_url.'"></li></ul>';
597
+ }
598
+ }
599
+ $html .= '</div>';
600
+ //===Carousal setup end===//
601
+ }
602
+
603
  $html .= '<i class="fa fa-times cross"></i>';
604
  $html .= '<div class="custom-ifram" style="display: none;">';
605
  $html .= '</div>';
623
  $html .= '}';
624
  $html .= '}';
625
  $html .= '}';
626
+ $html .= 'var panoshow'.$id.' = pannellum.viewer(response[0]["panoid"], scenes);';
627
+ if ($vrgallery) {
628
+ if (isset($panodata["scene-list"])) {
629
+ foreach ($panodata["scene-list"] as $panoscenes) {
630
+ $scene_key = $panoscenes['scene-id'];
631
+ $scene_key_gallery = $panoscenes['scene-id'].'_gallery_'.$id;
632
+ $img_src_url = $panoscenes['scene-attachment-url'];
633
+ $html .= 'document.getElementById("'.$scene_key_gallery.'").addEventListener("dblclick", function(e) { panoshow'.$id.'.loadScene("'.$scene_key.'"); });';
634
+ }
635
+ }
636
+ }
637
  $html .= '</script>';
638
  //script end
639
  return $html;