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

Version Description

Download this release

Release Info

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

Code changes from version 3.4.8 to 1.0.2

LICENSE.txt CHANGED
File without changes
README.txt CHANGED
@@ -1,130 +1,69 @@
1
  === WP VR - 360 Panorama and virtual tour creator for WordPress ===
2
  Contributors: rextheme, coderexco
3
  Donate link: https://rextheme.com/wp-vr-360-panorama-and-virtual-tour-creator-for-wordpress/
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.3
7
- Stable tag: 3.4.8
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
12
- Let site visitors take a virtual tour and get them excited!! Let them experience the glimpse of a live tour of your place.
13
 
14
  == Description ==
15
- Create amazing virtual tours on your own easily using WPVR. Let visitors take a tour of your place remotely, and get them more excited.
16
 
17
- With WPVR, you can create a virtual tour where visitors can navigate a 360 view of your location, switch between several scenes, get information on items on the location, zoom in and out to get a better view and get an overall idea about how your place may look in reality.
18
 
19
- Simply provide a 360 panoramic image, and this plugin will transform it into a realistic tour.
20
 
 
 
21
 
22
- >WPVR is fully compatible with Gutenberg Block Editor and Elementor Page Builder.
 
23
 
 
 
24
 
25
- [Demo Virtual Tour (Pro)](https://rextheme.com/docs/wp-vr/demo-tours/pro-demo-virtual-tour/) | [Demo Tour (Free)](https://rextheme.com/docs/wp-vr/demo-tours/demo-tour-wpvr-free/) | [Documentation](https://rextheme.com/docs/wp-vr/) | [Premium Version](https://rextheme.com/wpvr/)
 
26
 
27
 
28
- == Why Use WPVR? ==
29
- WPVR gives all the features needed to create a quality virtual tour without any hassle.
30
-
31
- https://www.youtube.com/watch?v=vG411d1qX3c
32
-
33
- Get several exclusive features, such as:
34
-
35
- **Simple interface optimized to create virtual tours easily** 
36
- Simple, easy, and straight forward options to add your 360 panoramic images and create a virtual tour.
37
-
38
- You can also add an auto rotation effect, scene fade animation when transmitting between scenes and many more to create an attractive virtual tour.
39
-
40
- Plus, it includes the feature to preview the tour at the back-end for proper inspection and tour creation.
41
-
42
- >Read detailed [documentation](https://rextheme.com/docs/wp-vr/) and [video tutorials](https://www.youtube.com/watch?v=vG411d1qX3c&list=PLelDqLncNWcVNqy7zoqtt8N-pyqy0-93z) for assistance.
43
-
44
- **Create an interactive realistic tour with multiple scenes**
45
- Add several scenes and add hotspots to connect them into a tour. Create multiple hotspots for every scene at your own will, to connect to different scenes and generate a realistic tour experience.
46
-
47
- >Gyroscope support for mobile devices on WPVR Pro.
48
-
49
- Plus, hotspots can be used to provide information on click or hover, which will act as a guide to viewers.
50
-
51
-
52
- **Customize hotspots to create more attraction**
53
- WPVR comes with over 900+ custom icons to choose from, to use as hotspots. It features to change colors and add blinking animation to the custom icons to make the hotspots more catchy.
54
-
55
- Also, WPVR allows you to add custom icons on your own using custom CSS. 
56
-
57
- >Get a reliable support team to help you out at all times.
58
-
59
- Get more features for full control of the tour such as scene boundary control, zoom level control, default scene face, and many more.
60
-
61
- **Embed virtual tour without hassle**
62
- Once a tour is created, it will generate a tour ID which is used to embed the tour on the website either through Gutenberg block or Elementor widget.
63
-
64
- The tour will also generate a shortcode. For classic editor or visual composer, use the shortcode to embed the tour. (Use the Raw HTML block on visual composer.)
65
-
66
- **Gutenberg Block Support**
67
- On Gutenberg block editor has the WPVR block under the common blocks. It is used to embed the virtual tour. Provide the tour ID and assign your desired width and height, and the tour will be embedded.
68
-
69
- **Elementor Widget Support**
70
- The Elementor page builder will have a WPVR widget under the general widgets. Drag and drop the widget onto the page. Provide the tour ID and set your required width and height to get a live preview.
71
-
72
- For more control over creating a virtual tour, learn about the [Premium version](https://rextheme.com/wpvr/).
73
-
74
-
75
- = FEATURES =
76
- * Gutenberg block support
77
- * Elementor widget support
78
  * Responsive default design
79
  * Preview tour on back-end
80
- * Add multiple scenes and hotspots
81
- * Auto rotation with speed control
82
- * Auto rotation pause and stop control
83
- * Keyboard direction keys or mouse to navigate
84
- * Keyboard +/- keys or mouse scroll to control zoom
85
- * Scene type hotspot to connect scenes
86
- * Info type hotspots to give information, on-click or hover
87
- * Embed video, image or website link to hotspots
88
- * On screen controls and full screen mode
89
- * Hotspot customization with custom CSS
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
 
97
- = PREMIUM FEATURES =
98
- * All free features
99
- * Unlimited scenes and hotspots (limited to 5 in free version)
100
- * Gyroscope support on mobile devices
101
- * 900+ premium hotspot icons
102
- * Color picker for custom hotspot
103
- * Control max, min and default zoom level
104
- * Scene boundary control
105
- * Custom default scene face
106
- * Custom compass for panorama
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
- * Custom control buttons
112
- * Google street view embed
113
- * Company logo
114
- * Personalized support (e-mail or forum)
115
-
116
- [Instructions to upgrade to pro](https://rextheme.com/docs/wp-vr/how-to-upgrade-to-pro/)
117
 
118
  **Upcoming Features**
119
- - Ground map
120
- - Connect multiple tours
121
- - Background music
 
 
 
 
 
122
 
123
- **[Documentation](https://rextheme.com/docs/wp-vr/)**
124
 
125
  == Frequently Asked Questions ==
126
  = 1. Why should I use WPVR? =
127
- You can easily create a Virtual Tour for your place using WPVR. You simply need to provide a 360 degree panoramic photo, and this plugin will create a virtual tour which visitors can navigate easily. You can further add hotspots to include information or add more scenes to navigate to.
128
 
129
  = 2. Installation =
130
  You can download the plugin either from wordpress.org or from rextheme.com. Once you have downloaded the file, you can then go to your dashboard, under plugin, select Add New and upload the file. Then Install and activate the plugin. Once activated, on the left side under your dashboard, you will find the option WPVR at the bottom.
@@ -138,47 +77,17 @@ Yes, you can include image source or video embed link on the section On Click Co
138
  = 5. Can I Customize the Content on the hotspot? =
139
  Yes. You can create a custom class on your theme, stating whatever style you want. Then you can input the class name on the Hotspot Custom Class section in a hotspot, and the content displayed will be customized according to the style you set.
140
 
141
- = 6. How can I embed a virtual tour using Gutenberg Block Editor?? =
142
- Under common blocks, you will find a block called WPVR. Add WPVR block. Select the block and on the dynamic toolbar on the right, you will get the options to add ID, Height and Width. Collect the ID from the virtual tour you created. Assign height and width according to your convenience.
143
-
144
- = 7. What do I do if I get “THE FILE (image link) COULD NOT BE ACCESSED” error? =
145
- Sometimes when you add a tour on your site, you might face this issue that rather than loading the tour it will give the error “THE FILE (…) COULD NOT BE ACCESSED.”
146
-
147
- This error shows up when you are running a website under “HTTPS” (secured with SSL certificate) whereas your image link is under “HTTP” (unsecured).
148
-
149
- To solve this issue, go to your WordPress Dashboard > Settings > General. Here make sure you have “https” added to both “WordPress Address (URL)” and “Site Address (URL)”. That’s it. Your virtual tour will load with no issues. 
150
-
151
- = 8. How to activate Gyroscope on IOS devices? =
152
- 1. Go to Settings > Safari
153
- 2. Scroll down to the Privacy & Security section
154
- 3. Enable Motion & Orientation Access
155
 
156
- That’s it. Now you can go to the browser and open the page with the virtual tour.
157
 
158
- You will find the gyroscope icon at the top left side.
159
-
160
- = 9. I Use Auto-optimize plugin =
161
- If you use Auto-optimize, then you need to exclude our plugin from their minification function.
162
-
163
- Simply add "/plugins/wpvr" to exclusion field (or use the location where you store plugins)
164
 
165
 
166
  == Screenshots ==
167
- 1. Demo view
168
- 2. Demo view
169
- 3. Demo view
170
- 4. Demo view
171
- 5. Demo view
172
- 6. Demo view
173
- 7. Demo view
174
- 8. Demo view
175
- 9. Demo view
176
- 10. Demo view
177
- 11. Demo view
178
- 12. Demo view
179
- 13. Demo view
180
- 14. Demo view
181
- 15. Demo view
182
 
183
  == Changelog ==
184
 
@@ -190,110 +99,5 @@ Simply add "/plugins/wpvr" to exclusion field (or use the location where you sto
190
  * Default scene can be selected from scene tab.
191
  * Default height and width given for shortcodes.
192
 
193
- = 2.0.0 =
194
- * Gutenberg block support
195
- * Bug fix.
196
-
197
- = 2.1.0 =
198
- * Save draft fixed.
199
- * Error handling fixed.
200
- * Video support added.
201
- * Slider revolution conflict fix.
202
- * Auto rotation
203
- * Rotation pause and stop control
204
-
205
- = 2.1.1 =
206
- * Dynamic Font-Awesome icon added for hotspot.
207
- * Dynamic color picker added for hotspot color.
208
- * Custom panorama compass support.
209
- * Default zoom level.
210
- * Maximum and minimum zoom range.
211
- * Customize each scene's default face on load.
212
- * Scene grab control and custom boundary for each scene.
213
-
214
- = 2.2.0 =
215
- * Scene title and author tag support.
216
- * Elementor widget support.
217
-
218
- = 2.3.0 =
219
- * Elementor widget support for free.
220
- * Mozilla Firefox bug fix.
221
- * CDN load fix.
222
- * Block input dropdown added.
223
- * Hotspot based scene face added.
224
-
225
- = 2.4.0 =
226
- * Font-awesome icon load fix.
227
- * Plugin conflict fix.
228
- * Rextheme link removed from premium version.
229
-
230
- = 2.5.0 =
231
- * Gyroscope support on premium version.
232
- * Appsero error fix.
233
- * Gutenberg block column layout fix.
234
-
235
- = 2.6.0 =
236
- * Duplicate tour.
237
- * Blink animation automated.
238
- * Language issue fixed.
239
-
240
- = 2.7.0 =
241
- * Post memory limit fix.
242
-
243
- = 2.8.0 =
244
- * Dynamic error reporting added.
245
-
246
- = 2.9.0 =
247
- * Tour selector updated on vr block.
248
-
249
- = 3.0.0 =
250
- * File import & export system added.
251
- * Fullwidth tag added.
252
- * Placeholder color changed.
253
-
254
- = 3.1.0 =
255
- * Custom scene gallery.
256
- * Border radius tag added.
257
- * Modified preview window.
258
-
259
- = 3.2.0 =
260
- * Custom scene gallery conflict and bug fix for iphone and ipad.
261
-
262
- = 3.3.0 =
263
- * Placeholder change.
264
-
265
- = 3.4.0 =
266
- * Repeater delete confirmation fix.
267
-
268
- = 3.4.1 =
269
- * Gallery carousal fix
270
-
271
- = 3.4.2 =
272
- * Gallery carousal design fix
273
- * Css and js restricted
274
-
275
- = 3.4.3 =
276
- * Autorotation error fix
277
- * Ziparchive class error fix
278
-
279
- = 3.4.4 =
280
- * Rotation fix on default scene face
281
- * Rotation fix on hotspot to target scene face
282
- * Plugin library update
283
-
284
- = 3.4.5 =
285
- * Wordpress.com hosting support fixed
286
-
287
- = 3.4.6 =
288
- * Custom control feature for pro version
289
- * WordPress 5.3 bug fix
290
-
291
- = 3.4.7 =
292
- * Google street view embed
293
-
294
- = 3.4.8 =
295
- * Company logo on pro version
296
- * Made preview load more efficient
297
-
298
  == Upgrade Notice ==
299
  Please do update the WP VR to the latest version. Each update makes it sure your plugin is supporting all tour features.  
1
  === WP VR - 360 Panorama and virtual tour creator for WordPress ===
2
  Contributors: rextheme, coderexco
3
  Donate link: https://rextheme.com/wp-vr-360-panorama-and-virtual-tour-creator-for-wordpress/
4
+ Tags: virtual reality, panorama, panorama viewer, virtual tour, 360 panorama, real estate tour, interactive tour
5
  Requires at least: 4.0
6
+ Tested up to: 5.0
7
+ Stable tag: 1.0.2
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
12
+ Let customers take a virtual tour and get them excited!! Let them experience the glimpse of a live tour of your place.
13
 
14
  == Description ==
15
+ With the WPVR, set up a virtual tour for your customer where they can navigate a 360 view of your location, switch between several spots (or rooms), get information on items on the location, zoom in and out to get better view, and get an overall idea about how your place may look in reality.
16
 
 
17
 
18
+ > Get your customers hooked by giving them a tour that makes them realize how amazing your place is. Check for **[Documentation](https://rextheme.com/docs/wpvr-360-panorama-and-virtual-tour-creator-for-wordpress/)** 
19
 
20
+ **Easy and simple interface** 
21
+ Simple, easy and straight forward options to add your images and create a tour.
22
 
23
+ **Easy direction and navigation tools**
24
+ Create multiple hotspots for each scene at your own will. You can add hotspot type: info to get on-click or hover information or add URL. You can use hotspot type: scene and connect it to visit other scenes.
25
 
26
+ **Customize style easily**
27
+ You can implement your own custom style class and, alter the design and display of content from hotspot easily.
28
 
29
+ **Easy to embed your virtual tour:**
30
+ Creating every tour location generates a shortcode. You can simply apply this shorcode on your page along with proper width and height, and your website will include the virtual tour just the way you want.
31
 
32
 
33
+ = Features: =
34
+ = Free Version =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  * Responsive default design
36
  * Preview tour on back-end
37
+ * Default Zoom Control
38
+ * Option to set scene fade animation duration
39
+ * Customization freedom of hotspot contents
40
+ * Supports Equiretangular Panaromic Image type
41
+ * Extensive keyboard and move navigation: Use direction keys or click and drag to navigate
42
+ * Mouse scroll or keyboard buttons to zoom in and out
43
+ * Generates shortcodes to embed item on webpage
44
+ * Supports full screen
 
 
 
 
 
 
45
  * Support from support forum
46
 
47
+ = Premium Version =
48
+ * Unlimited scenes
49
+ * Unlimited hotspots
50
+ * Personalized support on both support forum and our support e-mail.
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  **Upcoming Features**
54
+ - Panoramic image type support: Cubemap, Multiresolution
55
+ - Target scene angle of view.
56
+ - Target scene default zoom level.
57
+ - Horizontal and vertical grab control.
58
+ - Gutenberg block support.
59
+ - Auto rotation
60
+ - Rotational angle (in seconds)
61
+ - On screen control button.
62
 
 
63
 
64
  == Frequently Asked Questions ==
65
  = 1. Why should I use WPVR? =
66
+ You can easily create a Virtual Tour for your place using WPVR. You simply need to provide a 360 degree panoramic photo, and this plugin will create a virtual tour which customers can navigate easily. You can further add hotspots to include information or add more scenes to navigate to.
67
 
68
  = 2. Installation =
69
  You can download the plugin either from wordpress.org or from rextheme.com. Once you have downloaded the file, you can then go to your dashboard, under plugin, select Add New and upload the file. Then Install and activate the plugin. Once activated, on the left side under your dashboard, you will find the option WPVR at the bottom.
77
  = 5. Can I Customize the Content on the hotspot? =
78
  Yes. You can create a custom class on your theme, stating whatever style you want. Then you can input the class name on the Hotspot Custom Class section in a hotspot, and the content displayed will be customized according to the style you set.
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
+ **[Documentation](https://rextheme.com/docs/wpvr-360-panorama-and-virtual-tour-creator-for-wordpress/)** 
82
 
 
 
 
 
 
 
83
 
84
 
85
  == Screenshots ==
86
+ 1. Front-end view.
87
+ 2. Scene setup window.
88
+ 3. Hotspot setup window.
89
+ 4. Preview window.
90
+ 5. General settings window
 
 
 
 
 
 
 
 
 
 
91
 
92
  == Changelog ==
93
 
99
  * Default scene can be selected from scene tab.
100
  * Default height and width given for shortcodes.
101
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  == Upgrade Notice ==
103
  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-pages.php CHANGED
@@ -24,8 +24,9 @@ class Wpvr_Admin_Pages {
24
  add_submenu_page( 'wpvr', 'Wpvr', 'Tours','manage_options', 'edit.php?post_type=wpvr_item', NULL);
25
 
26
  add_submenu_page( 'wpvr', 'Wpvr', 'Add New Tour','manage_options', 'post-new.php?post_type=wpvr_item', NULL);
27
-
28
- do_action('wpvr_pro_license_page');
 
29
 
30
  }
31
 
@@ -38,3 +39,4 @@ class Wpvr_Admin_Pages {
38
  require_once plugin_dir_path(__FILE__) . '/partials/wpvr_license.php';
39
  }
40
  }
 
24
  add_submenu_page( 'wpvr', 'Wpvr', 'Tours','manage_options', 'edit.php?post_type=wpvr_item', NULL);
25
 
26
  add_submenu_page( 'wpvr', 'Wpvr', 'Add New Tour','manage_options', 'post-new.php?post_type=wpvr_item', NULL);
27
+ if(is_plugin_active( 'wpvr-pro/wpvr-pro.php' )){
28
+ add_submenu_page( 'wpvr', 'wpvrpro', 'WPVR License','manage_options', 'wpvrpro', array( $this, 'wpvr_pro_admin_doc'));
29
+ }
30
 
31
  }
32
 
39
  require_once plugin_dir_path(__FILE__) . '/partials/wpvr_license.php';
40
  }
41
  }
42
+
admin/class-wpvr-admin.php CHANGED
@@ -79,23 +79,16 @@ class Wpvr_Admin {
79
  * between the defined hooks and the functions defined in this
80
  * class.
81
  */
 
 
82
 
83
- $screen = get_current_screen();
84
- if ($screen->id=="toplevel_page_wpvr") {
85
- wp_enqueue_style( 'materialize-css', plugin_dir_url( __FILE__ ) . 'css/materialize.min.css', array(), $this->version, 'all' );
86
- wp_enqueue_style( 'materialize-icons', plugin_dir_url( __FILE__ ) . 'lib/materializeicon.css', array(), $this->version, 'all' );
87
- wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-admin.css', array(), $this->version, 'all' );
88
- }
89
 
90
- if ($screen->id=="wpvr_item") {
91
- wp_enqueue_style( $this->plugin_name . 'fontawesome', plugin_dir_url( __FILE__ ) . 'lib/fontawesome/css/all.css', array(), $this->version, 'all' );
92
- wp_enqueue_style( 'icon-picker-css', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.min.css', array(), $this->version, 'all' );
93
- wp_enqueue_style( 'icon-picker-css-theme', plugin_dir_url( __FILE__ ) . 'css/jquery.fonticonpicker.grey.min.css', array(), $this->version, 'all' );
94
- wp_enqueue_style( 'owl-css', plugin_dir_url( __FILE__ ) . 'css/owl.carousel.css', array(), $this->version, 'all' );
95
- wp_enqueue_style('panellium-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/pannellum.css', array(), true);
96
- wp_enqueue_style('videojs-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/video-js.css', array(), true);
97
- wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-admin.css', array(), $this->version, 'all' );
98
- }
99
 
100
  }
101
 
@@ -117,33 +110,17 @@ class Wpvr_Admin {
117
  * between the defined hooks and the functions defined in this
118
  * class.
119
  */
120
- wp_enqueue_script( 'wp-api' );
121
- $adscreen = get_current_screen();
122
  wp_enqueue_media();
123
- if ($adscreen->id=="wpvr_item") {
124
- wp_enqueue_script('icon-picker', plugin_dir_url( __FILE__ ) . 'lib/jquery.fonticonpicker.min.js', array(), true);
125
- wp_enqueue_script('panellium-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/pannellum.js', array(), true);
126
- wp_enqueue_script('panelliumlib-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/libpannellum.js', array(), true);
127
- wp_enqueue_script( 'videojs-js', plugin_dir_url( __FILE__ ) .'js/video.js', array('jquery'), true);
128
- wp_enqueue_script('panelliumvid-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/videojs-pannellum-plugin.js', array(), true);
129
- wp_enqueue_script( 'jquery-repeater', plugin_dir_url( __FILE__ ) .'js/jquery.repeater.min.js', array('jquery'), true);
130
- wp_enqueue_script('icon-picker', plugin_dir_url( __FILE__ ) . 'lib/jquery.fonticonpicker.min.js', array(), true);
131
- wp_enqueue_script( 'owl', plugin_dir_url( __FILE__ ) . 'js/owl.carousel.js', array( 'jquery' ), false );
132
- wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-admin.js', array( 'jquery' ), $this->version, false );
133
- wp_localize_script( $this->plugin_name, 'wpvr_obj', array(
134
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
135
- 'ajax_nonce' => wp_create_nonce('wpvr'),
136
- ) );
137
- }
138
 
139
- if ($adscreen->id=="toplevel_page_wpvr") {
140
- wp_enqueue_script( 'materialize-js', plugin_dir_url( __FILE__ ) . 'js/materialize.min.js', array( 'jquery' ), $this->version, false );
141
- }
142
- wp_enqueue_script( 'wpvr-global', plugin_dir_url( __FILE__ ) . 'js/wpvr-global.js', array( 'jquery' ), $this->version, false );
143
- wp_localize_script( 'wpvr-global', 'wpvr_global_obj', array(
144
- 'ajaxurl' => admin_url( 'admin-ajax.php' ),
145
- 'ajax_nonce' => wp_create_nonce('wpvr_global'),
146
- ) );
147
  }
148
 
149
  /**
@@ -157,8 +134,8 @@ class Wpvr_Admin {
157
  */
158
 
159
  add_meta_box(
160
- $this->post_type . '_builder_box',
161
- __('Tour Preview', $this->plugin_name),
162
  array($this, 'wpvr_display_meta_box_builder'),
163
  $this->post_type,
164
  'advanced',
@@ -166,7 +143,7 @@ class Wpvr_Admin {
166
  );
167
 
168
  add_meta_box(
169
- $this->post_type . '_shortcode_box',
170
  __('Using this VR', $this->plugin_name),
171
  array($this, 'wpvr_display_meta_box_shortcode'),
172
  $this->post_type,
@@ -195,7 +172,7 @@ class Wpvr_Admin {
195
  'all_items' => __( 'All Tours', $this->plugin_name ),
196
  'menu_name' => __( 'Wpvr', $this->plugin_name ),
197
  );
198
-
199
  $args = array(
200
  'labels' => $labels,
201
  'public' => false,
@@ -204,7 +181,7 @@ class Wpvr_Admin {
204
  'menu_position' => 100,
205
  'supports' => array( 'title' ),
206
  );
207
-
208
  /**
209
  * Documentation : https://codex.wordpress.org/Function_Reference/register_post_type
210
  */
@@ -218,7 +195,7 @@ class Wpvr_Admin {
218
  */
219
  function wpvr_manage_posts_custom_column( $column_name ){
220
  $post = get_post();
221
-
222
  switch( $column_name ) {
223
  case 'shortcode' :
224
  echo '<code>[wpvr id="' . $post->ID . '"]</code>';
@@ -252,7 +229,7 @@ class Wpvr_Admin {
252
  public function wpvr_post_updated_messages( $messages ) {
253
  $messages[$this->post_type][1] = __( 'Wpvr item updated.', $this->plugin_name);
254
  $messages[$this->post_type][4] = __( 'Wpvr item updated.', $this->plugin_name);
255
-
256
  return $messages;
257
  }
258
 
@@ -262,7 +239,7 @@ class Wpvr_Admin {
262
  * @since 1.0.0
263
  */
264
  public function wpvr_display_meta_box_shortcode() {
265
-
266
  include_once( 'partials/wpvr-meta-box-shortcode-display.php' );
267
  }
268
 
@@ -283,398 +260,163 @@ class Wpvr_Admin {
283
  }
284
  public function wpvr_setup($post) {
285
 
286
-
287
- $data_limit = 5;
288
-
289
- $scene_limit = $data_limit + 1;
 
 
 
290
  $postdata = get_post_meta( $post->ID, 'panodata', true );
291
-
292
-
293
- $autoload = true;
294
  if (isset($postdata["autoLoad"])) {
295
  $autoload = $postdata["autoLoad"];
296
  }
297
-
298
- $control = true;
299
  if (isset($postdata["showControls"])) {
300
  $control = $postdata["showControls"];
301
  }
302
-
303
  $default_scene = '';
304
  if (isset($postdata["defaultscene"])) {
305
  $default_scene = $postdata["defaultscene"];
306
  }
307
-
308
- $preview = '';
309
- if (isset($postdata['preview'])) {
310
- $preview = $postdata['preview'];
311
- }
312
-
313
- $autorotation = '';
314
- if (isset($postdata["autoRotate"])) {
315
- $autorotation = $postdata["autoRotate"];
316
- }
317
- else {
318
- $autorotation = -5;
319
- }
320
- $autorotationinactivedelay = '';
321
- if (isset($postdata["autoRotateInactivityDelay"])) {
322
- $autorotationinactivedelay = $postdata["autoRotateInactivityDelay"];
323
- }
324
-
325
- $autorotationstopdelay = '';
326
- if (isset($postdata["autoRotateStopDelay"])) {
327
- $autorotationstopdelay = $postdata["autoRotateStopDelay"];
328
- }
329
-
330
  $scene_fade_duration = '';
331
  if (isset($postdata["scenefadeduration"])) {
332
  $scene_fade_duration = $postdata["scenefadeduration"];
333
  }
334
-
335
  $pano_data = '';
336
  if (isset($postdata["panodata"])) {
337
  $pano_data = $postdata["panodata"];
338
  }
339
-
340
- $custom_icon_array = new Wpvr_fontawesome_icons();
341
- $custom_icon = $custom_icon_array->icon;
342
-
343
  $html = '';
344
 
345
  $html .= '<div class="pano-setup">';
346
-
347
  $html .= '<div class="pano-alert scene-alert">';
348
  $html .= '<span class="destroy"><i class="fa fa-times"></i></span>';
349
  $html .= '<p></p>';
350
  $html .= '</div>';
351
-
352
  $html .='<div class="rex-pano-tabs">';
353
  $html .='<nav class="rex-pano-tab-nav rex-pano-nav-menu main-nav">';
354
  $html .='<ul>';
355
- $html .='<li class="general active"><span data-href="#general"><i class="fa fa-cogs"></i> '.__('general','wpvr').'</span></li>';
356
- $html .='<li class="scene"><span data-href="#scenes"><i class="fa fa-image"></i> '.__('Scenes','wpvr').'</span></li>';
357
- $html .='<li class="hotspot"><span data-href="#scenes"><i class="far fa-dot-circle"></i> '.__('hotspot','wpvr').'</span></li>';
358
- $html .='<li class="video"><span data-href="#video"><i class="fas fa-video"></i> '.__('Video','wpvr').'</span></li>';
359
  $html .='</ul>';
360
  $html .='</nav>';
361
-
362
  $html .='<div class="rex-pano-tab-content">';
363
  $html .='<div class="rex-pano-tab general active" id="general">';
364
-
365
- $html .= '<h6 class="title"> '.__('General Settings : ','wpvr').'</h6>';
366
-
367
- //=Control Setup=
368
- if ($control == false) {
369
- $html .= '<div class="single-settings controls">';
370
- $html .= '<span>'.__('Show Controls: ','wpvr').'</span>';
371
  $html .= '<ul>';
372
  $html .= '<li class="radio-btn">';
373
- $html .= '<input class="styled-radio" id="styled-radio-3" type="radio" name="controls" value="off" checked>';
374
- $html .= '<label for="styled-radio-3">Off</label>';
375
  $html .= '</li>';
376
-
377
  $html .= '<li class="radio-btn">';
378
- $html .= '<input class="styled-radio" id="styled-radio-4" type="radio" name="controls" value="on" >';
379
- $html .= '<label for="styled-radio-4">On</label>';
380
  $html .= '</li>';
381
  $html .= '</ul>';
382
  $html .= '</div>';
383
  }
384
  else {
385
- $html .= '<div class="single-settings controls">';
386
- $html .= '<span>'.__('Show Controls: ','wpvr').'</span>';
387
  $html .= '<ul>';
388
  $html .= '<li class="radio-btn">';
389
- $html .= '<input class="styled-radio" id="styled-radio-3" type="radio" name="controls" value="off" >';
390
- $html .= '<label for="styled-radio-3">Off</label>';
391
  $html .= '</li>';
392
-
393
  $html .= '<li class="radio-btn">';
394
- $html .= '<input class="styled-radio" id="styled-radio-4" type="radio" name="controls" value="on" checked>';
395
- $html .= '<label for="styled-radio-4">On</label>';
396
  $html .= '</li>';
397
  $html .= '</ul>';
398
  $html .= '</div>';
399
  }
400
- //=Control setup End=//
401
-
402
- //=scene fade duration=//
403
- $html .= '<div class="single-settings scene-fade-duration">';
404
- $html .= '<span>'.__('Scene Fade Duration: ','wpvr').'</span>';
405
- $html .= '<input type="number" name="scene-fade-duration" value="'.$scene_fade_duration.'" />';
406
- $html .= '</div>';
407
- //=scene fade duration End=//
408
 
409
- //=Autoload setup=//
410
- if ($autoload == true) {
411
- $html .= '<div class="single-settings autoload">';
412
- $html .= '<span>'.__('Autoload: ','wpvr').'</span>';
413
  $html .= '<ul>';
414
  $html .= '<li class="radio-btn">';
415
- $html .= '<input class="styled-radio" id="styled-radio-1" type="radio" name="autoload" value="off">';
416
- $html .= '<label for="styled-radio-1">Off</label>';
417
  $html .= '</li>';
418
-
419
  $html .= '<li class="radio-btn">';
420
- $html .= '<input class="styled-radio" id="styled-radio-2" type="radio" name="autoload" value="on" checked >';
421
- $html .= '<label for="styled-radio-2">On</label>';
422
  $html .= '</li>';
423
  $html .= '</ul>';
424
  $html .= '</div>';
425
  }
426
  else {
427
- $html .= '<div class="single-settings autoload">';
428
- $html .= '<span>'.__('Autoload: ','wpvr').' </span>';
429
  $html .= '<ul>';
430
  $html .= '<li class="radio-btn">';
431
- $html .= '<input class="styled-radio" id="styled-radio-1" type="radio" name="autoload" value="off" checked >';
432
- $html .= '<label for="styled-radio-1">Off</label>';
433
  $html .= '</li>';
434
-
435
  $html .= '<li class="radio-btn">';
436
- $html .= '<input class="styled-radio" id="styled-radio-2" type="radio" name="autoload" value="on">';
437
- $html .= '<label for="styled-radio-2">On</label>';
438
  $html .= '</li>';
439
  $html .= '</ul>';
440
  $html .= '</div>';
441
  }
442
- //=Autoload setup End=//
443
-
444
- //===preview image===//
445
- if (!empty($preview)) {
446
- $html .= '<div class="single-settings preview-setting">';
447
- $html .= '<span>'.__('Preview Upload or add link : ','wpvr').'</span>';
448
- $html .= '<div class="form-group">';
449
- $html .= '<img class="prev-img" src="'.$preview.'">';
450
- $html .= '<input type="text" name="preview-attachment-url" class="preview-attachment-url" value="'.$preview.'"><br>';
451
- $html .= '<input type="button" class="preview-upload" data-info="" value="Upload"/>';
452
- $html .= '</div>';
453
- $html .= '</div>';
454
- }
455
- else {
456
- $html .= '<div class="single-settings preview-setting">';
457
- $html .= '<span>'.__('Preview Upload or add link : ','wpvr').'</span>';
458
- $html .= '<div class="form-group">';
459
- $html .= '<img class="prev-img" src="" style="display: none;">';
460
- $html .= '<input type="text" name="preview-attachment-url" class="preview-attachment-url" value=""><br>';
461
- $html .= '<input type="button" class="preview-upload" data-info="" value="Upload"/>';
462
- $html .= '</div>';
463
- $html .= '</div>';
464
- }
465
- //===preview image end===//
466
-
467
- //===Autorotation on off set==//
468
- if (isset($postdata["autoRotate"])) {
469
- $html .= '<div class="single-settings autoload">';
470
- $html .= '<span>'.__('Auto Rotation: ','wpvr').' </span>';
471
- $html .= '<ul>';
472
- $html .= '<li class="radio-btn">';
473
- $html .= '<input class="styled-radio" id="styled-radio-11" type="radio" name="autorotation" value="off" >';
474
- $html .= '<label for="styled-radio-11">Off</label>';
475
- $html .= '</li>';
476
-
477
- $html .= '<li class="radio-btn">';
478
- $html .= '<input class="styled-radio" id="styled-radio-12" type="radio" name="autorotation" value="on" checked >';
479
- $html .= '<label for="styled-radio-12">On</label>';
480
- $html .= '</li>';
481
- $html .= '</ul>';
482
- $html .= '</div>';
483
- }
484
- else {
485
- $html .= '<div class="single-settings autoload">';
486
- $html .= '<span>'.__('Auto Rotation: ','wpvr').' </span>';
487
- $html .= '<ul>';
488
- $html .= '<li class="radio-btn">';
489
- $html .= '<input class="styled-radio" id="styled-radio-11" type="radio" name="autorotation" value="off" checked >';
490
- $html .= '<label for="styled-radio-11">Off</label>';
491
- $html .= '</li>';
492
-
493
- $html .= '<li class="radio-btn">';
494
- $html .= '<input class="styled-radio" id="styled-radio-12" type="radio" name="autorotation" value="on">';
495
- $html .= '<label for="styled-radio-12">On</label>';
496
- $html .= '</li>';
497
- $html .= '</ul>';
498
- $html .= '</div>';
499
- }
500
- //===Autorotation on off set==//
501
-
502
- //=Auto Rotation=//
503
- $html .= '<div class="single-settings scene-fade-duration autorotationdata" >';
504
- $html .= '<span>'.__('Auto Rotation: ','wpvr').'</span>';
505
- $html .= '<input type="number" name="auto-rotation" value="'.$autorotation.'" placeholder="-5" />';
506
- $html .= '<div class="field-tooltip">';
507
- $html .= '<i class="fa fa-question-circle"></i>';
508
- $html .= '<span>'.__('Will automatically rotate the panorama for each page load. You can define rotation speed with number values. Positive number for counter-clockwise and negative number for clockwise. As an example "-5" will rotate the panorama clockwise.','wpvr').'</span>';
509
- $html .= '</div>';
510
- $html .= '</div>';
511
- //=Auto Rotation=//
512
-
513
- //=Auto rotation inactive delay=//
514
- $html .= '<div class="single-settings scene-fade-duration autorotationdata" >';
515
- $html .= '<span>'.__('Auto Rotation Inactive Delay: ','wpvr').'</span>';
516
- $html .= '<input type="number" name="auto-rotation-inactive-delay" value="'.$autorotationinactivedelay.'" placeholder="2000" />';
517
- $html .= '<div class="field-tooltip">';
518
- $html .= '<i class="fa fa-question-circle"></i>';
519
- $html .= '<span>'.__('Will pause the rotation for few times. You can put the time value in miliseconds. As an example "2000" will pause the rotation for 2 seconds.','wpvr').'</span>';
520
- $html .= '</div>';
521
- $html .= '</div>';
522
- //=Auto rotation inactive delay=//
523
-
524
- //=Auto rotation stop delay=//
525
- $html .= '<div class="single-settings scene-fade-duration autorotationdata" >';
526
- $html .= '<span>'.__('Auto Rotation Stop Delay: ','wpvr').'</span>';
527
- $html .= '<input type="number" name="auto-rotation-stop-delay" value="'.$autorotationstopdelay.'" placeholder="2000" />';
528
- $html .= '<div class="field-tooltip">';
529
- $html .= '<i class="fa fa-question-circle"></i>';
530
- $html .= '<span>'.__('Will stop the auto rotation after given time value. As an example for "2000" the roation will stop after 2 seconds on each page load.','wpvr').'</span>';
531
- $html .= '</div>';
532
- $html .= '</div>';
533
- //=Auto rotation stop delay=//
534
 
 
 
 
 
 
 
 
535
  $html .='</div>';
536
  //---end general tab----
537
-
538
  $html .='<div class="rex-pano-tab" id="scenes">';
539
-
540
  //=Scene and Hotspot repeater=//
541
  if (empty($pano_data)) {
542
- $html .= '<div class="scene-setup rex-pano-sub-tabs" data-limit="'.$scene_limit.'">';
543
-
544
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu scene-nav">';
545
  $html .= '<ul>';
546
- $html .= '<li class="active"><span data-index="1" data-href="#scene-1"><i class="fa fa-image"></i></span></li>';
547
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i></span></li>';
548
  $html .= '</ul>';
549
  $html .= '</nav>';
550
-
551
  $html .= '<div data-repeater-list="scene-list" class="rex-pano-tab-content">';
552
-
553
- $html .= '<div data-repeater-item class="single-scene rex-pano-tab" data-title="0" id="scene-0">';
554
-
555
- $html .= '<div class="scene-content">';
556
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene Setting </h6>';
557
-
558
- //==Set Default Scene==//
559
- $html .= '<div class="single-settings dscene">';
560
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
561
- $html .= '<select class="dscen" name="dscene">';
562
- $html .= '<option value="on"> Yes</option>';
563
- $html .= '<option value="off" selected > No</option>';
564
- $html .= '</select>';
565
- $html .= '</div>';
566
- //==Set Default Scene end==//
567
- $html .= '<div class=scene-setting>';
568
- $html .= '<label for="scene-id">'.__('Scene ID : ','wpvr').'</label>';
569
- $html .= '<input class="sceneid" type="text" name="scene-id"/>';
570
- $html .= '</div>';
571
-
572
- $html .= '<div class=scene-setting>';
573
- $html .= '<label for="scene-type">'.__('Scene Type : ','wpvr').'</label>';
574
- $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
575
- $html .= '</div>';
576
-
577
- $html .= '<div class=scene-setting>';
578
- $html .= '<label for="scene-upload">'.__('Scene Upload: ','wpvr').'</label>';
579
- $html .= '<div class="form-group">';
580
- $html .= '<img src="" style="display: none;"><br>';
581
- $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
582
- $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="">';
583
- $html .= '</div>';
584
- $html .= '</div>';
585
- $html .= '</div>';
586
-
587
- //--hotspot setup--
588
- $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
589
-
590
- $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
591
- $html .= '<ul>';
592
- $html .= '<li class="active"><span data-index="1" data-href="#scene-0-hotspot-1"><i class="far fa-dot-circle"></i></span></li>';
593
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> </span></li>';
594
- $html .= '</ul>';
595
- $html .= '</nav>';
596
-
597
- $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
598
- $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-0-hotspot-1">';
599
-
600
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
601
-
602
- $html .= '<div class="wrapper">';
603
- $html .= '<div class="hotspot-setting">';
604
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
605
- $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
606
- $html .= '</div>';
607
-
608
- $html .= '<div class="hotspot-setting">';
609
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
610
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch"/>';
611
- $html .= '</div>';
612
-
613
- $html .= '<div class="hotspot-setting">';
614
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
615
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw"/>';
616
- $html .= '</div>';
617
-
618
- $html .= '<div class="hotspot-setting">';
619
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
620
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
621
- $html .= '</div>';
622
-
623
- $html .= '</div>';
624
-
625
- $html .= '<div class="hotspot-type hotspot-setting">';
626
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
627
- $html .= '<select name="hotspot-type">';
628
- $html .= '<option value="info" selected> Info</option>';
629
- $html .= '<option value="scene"> Scene</option>';
630
- $html .= '</select>';
631
-
632
- $html .= '<div class="hotspot-url">';
633
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
634
- $html .= '<input type="url" name="hotspot-url" value="" />';
635
- $html .= '</div>';
636
-
637
- $html .= '<div class="hotspot-content">';
638
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
639
- $html .= '<textarea name="hotspot-content"></textarea>';
640
- $html .= '</div>';
641
-
642
- $html .= '<div class="hotspot-hover">';
643
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
644
- $html .= '<textarea name="hotspot-hover"></textarea>';
645
- $html .= '</div>';
646
-
647
- $html .= '<div class="hotspot-scene" style="display:none;" >';
648
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
649
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
650
- $html .= '<option value="none" selected> None</option>';
651
- $html .= '</select>';
652
- $html .= '</div>';
653
-
654
- $html .= '<div class="hotspot-scene" style="display:none;" >';
655
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').' </label>';
656
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
657
- $html .= '</div>';
658
-
659
- $html .= '</div>';
660
- //=Hotspot type End=//
661
- $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
662
- $html .= '</div>';
663
- $html .= '</div>';
664
-
665
- $html .= '</div>';
666
- $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>';
667
- $html .= '</div>';
668
-
669
-
670
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab active" data-title="1" id="scene-1">';
671
-
672
  $html .= '<div class="scene-content">';
673
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene Setting </h6>';
674
 
675
  //==Set Default Scene==//
676
- $html .= '<div class="single-settings dscene">';
677
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
678
  $html .= '<select class="dscen" name="dscene">';
679
  $html .= '<option value="on"> Yes</option>';
680
  $html .= '<option value="off" selected > No</option>';
@@ -683,140 +425,134 @@ class Wpvr_Admin {
683
  //==Set Default Scene end==//
684
 
685
  $html .= '<div class=scene-setting>';
686
- $html .= '<label for="scene-id">'.__('Scene ID : ','wpvr').'</label>';
687
- $html .= '<input class="sceneid" type="text" name="scene-id"/>';
688
  $html .= '</div>';
689
 
690
  $html .= '<div class=scene-setting>';
691
- $html .= '<label for="scene-type">'.__('Scene Type : ','wpvr').'</label>';
692
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
693
  $html .= '</div>';
694
 
695
  $html .= '<div class=scene-setting>';
696
- $html .= '<label for="scene-upload">'.__('Scene Upload: ','wpvr').'</label>';
697
  $html .= '<div class="form-group">';
698
- $html .= '<img src="" style="display: none;"><br>';
699
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
700
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="">';
701
  $html .= '</div>';
702
  $html .= '</div>';
703
  $html .= '</div>';
704
-
705
- //--hotspot setup--//
706
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
707
-
708
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
709
  $html .= '<ul>';
710
- $html .= '<li class="active"><span data-index="1" data-href="#scene-1-hotspot-1"><i class="far fa-dot-circle"></i></span></li>';
711
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> </span></li>';
712
  $html .= '</ul>';
713
  $html .= '</nav>';
714
-
715
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
716
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-1-hotspot-1">';
717
-
718
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
719
-
720
  $html .= '<div class="wrapper">';
721
  $html .= '<div class="hotspot-setting">';
722
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
723
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
724
  $html .= '</div>';
725
 
726
  $html .= '<div class="hotspot-setting">';
727
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
728
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch"/>';
729
  $html .= '</div>';
730
 
731
  $html .= '<div class="hotspot-setting">';
732
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
733
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw"/>';
734
  $html .= '</div>';
735
 
736
- $html .= '<div class="hotspot-setting">';
737
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
738
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
739
- $html .= '</div>';
740
-
741
  $html .= '</div>';
742
-
743
  $html .= '<div class="hotspot-type hotspot-setting">';
744
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
745
  $html .= '<select name="hotspot-type">';
746
  $html .= '<option value="info" selected> Info</option>';
747
  $html .= '<option value="scene"> Scene</option>';
748
  $html .= '</select>';
749
 
750
  $html .= '<div class="hotspot-url">';
751
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').'</label>';
752
  $html .= '<input type="url" name="hotspot-url" value="" />';
753
  $html .= '</div>';
754
-
755
  $html .= '<div class="hotspot-content">';
756
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
757
  $html .= '<textarea name="hotspot-content"></textarea>';
758
  $html .= '</div>';
759
-
760
  $html .= '<div class="hotspot-hover">';
761
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
762
  $html .= '<textarea name="hotspot-hover"></textarea>';
763
  $html .= '</div>';
764
-
765
  $html .= '<div class="hotspot-scene" style="display:none;" >';
766
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
767
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
768
- $html .= '<option value="none"> None</option>';
769
- $html .= '</select>';
770
  $html .= '</div>';
771
- $html .= '<div class="hotspot-scene" style="display:none;" >';
772
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
773
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
774
- $html .= '</div>';
775
-
776
  $html .= '</div>';
777
  //=Hotspot type End=//
778
- $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
779
  $html .= '</div>';
780
  $html .= '</div>';
 
781
  $html .= '</div>';
782
- $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>';
783
  $html .= '</div>';
784
  $html .= '</div>';
785
-
786
- $html .= '</div>';
787
  }
788
  else {
789
- $html .= '<div class="scene-setup rex-pano-sub-tabs" data-limit="'.$scene_limit.'">';
790
-
791
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu scene-nav">';
792
  $html .= '<ul>';
 
793
  $i = 1;
794
- $firstvalue = reset($pano_data["scene-list"]);
795
  foreach ($pano_data["scene-list"] as $pano_scenes) {
796
- if ($pano_scenes['scene-id'] == $firstvalue['scene-id']) {
797
- $html .= '<li class="active"><span data-index="'.$i.'" data-href="#scene-'.$i.'"><i class="fa fa-image"></i></span></li>';
798
  }
799
  else {
800
- $html .= '<li><span data-index="'.$i.'" data-href="#scene-'.$i.'"><i class="fa fa-image"></i></span></li>';
801
  }
802
  $i++;
803
  }
804
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i></span></li>';
805
  $html .= '</ul>';
806
  $html .= '</nav>';
807
-
808
 
809
  $html .= '<div data-repeater-list="scene-list" class="rex-pano-tab-content">';
810
 
811
- //===Default empty repeater declared by nazmus sakib===//
812
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab" data-title="0" id="scene-0">';
813
-
814
  $html .= '<div class="scene-content">';
815
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene Setting </h6>';
816
 
817
  //==Set Default Scene==//
818
- $html .= '<div class="single-settings dscene">';
819
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
820
  $html .= '<select class="dscen" name="dscene">';
821
  $html .= '<option value="on"> Yes</option>';
822
  $html .= '<option value="off" selected > No</option>';
@@ -824,107 +560,99 @@ class Wpvr_Admin {
824
  $html .= '</div>';
825
  //==Set Default Scene end==//
826
  $html .= '<div class=scene-setting>';
827
- $html .= '<label for="scene-id">'.__('Scene ID : ','wpvr').'</label>';
828
- $html .= '<input class="sceneid" type="text" name="scene-id"/>';
829
  $html .= '</div>';
830
 
831
  $html .= '<div class=scene-setting>';
832
- $html .= '<label for="scene-type">'.__('Scene Type : ','wpvr').'</label>';
833
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
834
  $html .= '</div>';
835
 
836
  $html .= '<div class=scene-setting>';
837
- $html .= '<label for="scene-upload">'.__('Scene Upload: ','wpvr').'</label>';
838
  $html .= '<div class="form-group">';
839
- $html .= '<img src="" style="display: none;"><br>';
840
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
841
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="">';
842
  $html .= '</div>';
843
  $html .= '</div>';
844
  $html .= '</div>';
845
-
846
- //--hotspot setup--//
847
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
848
-
849
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
850
  $html .= '<ul>';
851
- $html .= '<li class="active"><span data-index="1" data-href="#scene-0-hotspot-1"><i class="far fa-dot-circle"></i></span></li>';
852
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> </span></li>';
853
  $html .= '</ul>';
854
  $html .= '</nav>';
855
-
856
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
857
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-0-hotspot-1">';
858
-
859
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
860
-
861
  $html .= '<div class="wrapper">';
862
  $html .= '<div class="hotspot-setting">';
863
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
864
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
865
  $html .= '</div>';
866
 
867
  $html .= '<div class="hotspot-setting">';
868
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
869
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch"/>';
870
  $html .= '</div>';
871
 
872
  $html .= '<div class="hotspot-setting">';
873
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
874
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw"/>';
875
  $html .= '</div>';
876
 
877
- $html .= '<div class="hotspot-setting">';
878
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
879
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
880
- $html .= '</div>';
881
-
882
  $html .= '</div>';
883
-
884
  $html .= '<div class="hotspot-type hotspot-setting">';
885
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
886
  $html .= '<select name="hotspot-type">';
887
  $html .= '<option value="info" selected> Info</option>';
888
  $html .= '<option value="scene"> Scene</option>';
889
  $html .= '</select>';
890
 
891
  $html .= '<div class="hotspot-url">';
892
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
893
  $html .= '<input type="url" name="hotspot-url" value="" />';
894
  $html .= '</div>';
895
-
896
  $html .= '<div class="hotspot-content">';
897
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
898
  $html .= '<textarea name="hotspot-content"></textarea>';
899
  $html .= '</div>';
900
-
901
  $html .= '<div class="hotspot-hover">';
902
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
903
  $html .= '<textarea name="hotspot-hover"></textarea>';
904
  $html .= '</div>';
905
-
906
- $html .= '<div class="hotspot-scene" style="display:none;" >';
907
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
908
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
909
- $html .= '<option value="none" selected> None</option>';
910
- $html .= '</select>';
911
- $html .= '</div>';
912
-
913
  $html .= '<div class="hotspot-scene" style="display:none;" >';
914
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').' </label>';
915
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
916
  $html .= '</div>';
917
-
918
  $html .= '</div>';
919
  //=Hotspot type End=//
920
- $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
921
  $html .= '</div>';
922
  $html .= '</div>';
923
-
924
  $html .= '</div>';
925
- $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>';
926
  $html .= '</div>';
927
- //==Empty repeater end==//
928
 
929
  $s = 1;
930
  foreach ($pano_data["scene-list"] as $pano_scenes) {
@@ -938,32 +666,28 @@ class Wpvr_Admin {
938
  $scene_type = $pano_scenes["scene-type"];
939
  $scene_photo = '';
940
  $scene_photo = $pano_scenes["scene-attachment-url"];
941
-
942
  $pano_hotspots = array();
943
- if (isset($pano_scenes["hotspot-list"])) {
944
- $pano_hotspots = $pano_scenes["hotspot-list"];
945
- }
946
-
947
- $firstvalueset = reset($pano_data["scene-list"]);
948
- if ($pano_scenes['scene-id'] == $firstvalueset['scene-id']) {
949
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab active" data-title="1" id="scene-'.$s.'">';
950
-
951
  $html .= '<div class="scene-content">';
952
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene Setting </h6>';
953
  //==Set Default Scene==//
954
  if ($dscene == 'on') {
955
- $html .= '<div class="single-settings dscene">';
956
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
957
  $html .= '<select class="dscen" name="dscene">';
958
  $html .= '<option value="on" selected > Yes</option>';
959
  $html .= '<option value="off"> No</option>';
960
  $html .= '</select>';
961
  $html .= '</div>';
962
-
963
  }
964
  else {
965
- $html .= '<div class="single-settings dscene">';
966
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
967
  $html .= '<select class="dscen" name="dscene">';
968
  $html .= '<option value="on"> Yes</option>';
969
  $html .= '<option value="off" selected > No</option>';
@@ -972,50 +696,47 @@ class Wpvr_Admin {
972
  }
973
  //==Set Default Scene end==//
974
  $html .= '<div class=scene-setting>';
975
- $html .= '<label for="scene-id">'.__('Scene ID : ','wpvr').'</label>';
976
- $html .= '<input class="sceneid" type="text" name="scene-id" value="'.$scene_id.'" />';
977
  $html .= '</div>';
978
 
979
  $html .= '<div class=scene-setting>';
980
- $html .= '<label for="scene-type">'.__('Scene Type : ','wpvr').'</label>';
981
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
982
  $html .= '</div>';
983
 
984
  $html .= '<div class=scene-setting>';
985
- $html .= '<label for="scene-upload">'.__('Scene Upload: ','wpvr').'</label>';
986
  $html .= '<div class="form-group">';
987
- $html .= '<img name ="scene-photo" src="'.$scene_photo.'"> <br/>';
988
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
989
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="'.$scene_photo.'">';
990
  $html .= '</div>';
991
  $html .= '</div>';
992
- $html .= '</div>';
993
-
994
  if (!empty($pano_hotspots)) {
995
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
996
-
997
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
998
  $html .= '<ul>';
999
  $j = 1;
1000
- $firstvaluehotspot = reset($pano_hotspots);
1001
  foreach ($pano_hotspots as $pano_hotspot) {
1002
-
1003
- if ($pano_hotspot['hotspot-title'] == $firstvaluehotspot['hotspot-title']) {
1004
- $html .= '<li class="active"><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'"><i class="far fa-dot-circle"></i></span></li>';
1005
  }
1006
  else {
1007
- $html .= '<li><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'"><i class="far fa-dot-circle"></i></span></li>';
1008
  }
1009
  $j++;
1010
  }
1011
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i></span></li>';
1012
  $html .= '</ul>';
1013
  $html .= '</nav>';
1014
-
1015
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
1016
-
1017
  $h = 1;
1018
- $firstvaluehotspotset = reset($pano_hotspots);
1019
  foreach ($pano_hotspots as $pano_hotspot) {
1020
  $hotspot_title = '';
1021
  $hotspot_title = $pano_hotspot['hotspot-title'];
@@ -1034,339 +755,300 @@ class Wpvr_Admin {
1034
  $hotspot_target_scene = '';
1035
  $hotspot_target_scene = $pano_hotspot['hotspot-scene'];
1036
  $hotspot_custom_class = '';
1037
- if (isset($pano_hotspot['hotspot-customclass'])) {
1038
- $hotspot_custom_class = $pano_hotspot['hotspot-customclass'];
1039
- }
1040
-
1041
- if ($pano_hotspot['hotspot-title'] == $firstvaluehotspotset['hotspot-title']) {
1042
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1043
-
1044
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
1045
-
1046
  $html .= '<div class="wrapper">';
1047
  $html .= '<div class="hotspot-setting">';
1048
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1049
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1050
  $html .= '</div>';
1051
 
1052
  $html .= '<div class="hotspot-setting">';
1053
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'
1054
- </label>';
1055
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1056
  $html .= '</div>';
1057
 
1058
  $html .= '<div class="hotspot-setting">';
1059
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1060
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1061
  $html .= '</div>';
1062
 
1063
- $html .= '<div class="hotspot-setting">';
1064
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1065
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1066
- $html .= '</div>';
1067
-
1068
  $html .= '</div>';
1069
-
1070
  //=Hotspot type=//
1071
  if ($hotspot_type == "info") {
1072
-
1073
  $html .= '<div class="hotspot-type hotspot-setting">';
1074
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1075
  $html .= '<select name="hotspot-type">';
1076
  $html .= '<option value="info" selected> Info</option>';
1077
  $html .= '<option value="scene"> Scene</option>';
1078
  $html .= '</select>';
1079
 
1080
  $html .= '<div class="hotspot-url">';
1081
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
1082
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1083
  $html .= '</div>';
1084
 
1085
  $html .= '<div class="hotspot-content">';
1086
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1087
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1088
  $html .= '</div>';
1089
 
1090
  $html .= '<div class="hotspot-hover">';
1091
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').' </label>';
1092
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1093
  $html .= '</div>';
1094
 
1095
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1096
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1097
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1098
- $html .= '<option value="none" selected> None</option>';
1099
- $html .= '</select>';
1100
- $html .= '</div>';
1101
-
1102
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1103
- $html .= '<label for="hotspot-scene"> '.__('Target Scene ID: ','wpvr').'</label>';
1104
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
1105
  $html .= '</div>';
1106
 
1107
  $html .= '</div>';
1108
-
1109
  }
1110
  else {
1111
-
1112
  $html .= '<div class="hotspot-type hotspot-setting">';
1113
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1114
- $html .= '<select class="trtr" name="hotspot-type">';
1115
  $html .= '<option value="info"> Info</option>';
1116
  $html .= '<option value="scene" selected> Scene</option>';
1117
  $html .= '</select>';
1118
 
1119
  $html .= '<div class="hotspot-url" style="display:none;">';
1120
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').'</label>';
1121
  $html .= '<input type="url" name="hotspot-url" />';
1122
  $html .= '</div>';
1123
 
1124
- $html .= '<div class="hotspot-content" style="display:none;">';
1125
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').' </label>';
1126
  $html .= '<textarea name="hotspot-content"></textarea>';
1127
  $html .= '</div>';
1128
 
1129
  $html .= '<div class="hotspot-hover">';
1130
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
1131
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1132
  $html .= '</div>';
1133
 
1134
- $html .= '<div class="hotspot-scene" >';
1135
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1136
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1137
- $html .= '<option value="none" selected> None</option>';
1138
- $html .= '</select>';
1139
- $html .= '</div>';
1140
-
1141
  $html .= '<div class="hotspot-scene">';
1142
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1143
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" disabled />';
1144
  $html .= '</div>';
1145
 
1146
  $html .= '</div>';
1147
-
1148
  }
1149
  //=Hotspot type End=//
1150
- $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1151
- $html .= '</div>';
1152
  }
1153
  else {
1154
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1155
-
1156
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
1157
-
1158
  $html .= '<div class="wrapper">';
1159
  $html .= '<div class="hotspot-setting">';
1160
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1161
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1162
  $html .= '</div>';
1163
 
1164
  $html .= '<div class="hotspot-setting">';
1165
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
1166
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1167
  $html .= '</div>';
1168
 
1169
  $html .= '<div class="hotspot-setting">';
1170
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1171
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1172
  $html .= '</div>';
1173
 
1174
- $html .= '<div class="hotspot-setting">';
1175
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1176
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1177
- $html .= '</div>';
1178
-
1179
  $html .= '</div>';
1180
-
1181
  //=Hotspot type=//
1182
  if ($hotspot_type == "info") {
1183
-
1184
  $html .= '<div class="hotspot-type hotspot-setting">';
1185
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1186
  $html .= '<select name="hotspot-type">';
1187
  $html .= '<option value="info" selected> Info</option>';
1188
  $html .= '<option value="scene"> Scene</option>';
1189
  $html .= '</select>';
1190
 
1191
  $html .= '<div class="hotspot-url">';
1192
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
1193
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1194
  $html .= '</div>';
1195
 
1196
  $html .= '<div class="hotspot-content">';
1197
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1198
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1199
  $html .= '</div>';
1200
 
1201
  $html .= '<div class="hotspot-hover">';
1202
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
1203
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1204
  $html .= '</div>';
1205
 
1206
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1207
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1208
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1209
- $html .= '<option value="none" selected> None</option>';
1210
- $html .= '</select>';
1211
- $html .= '</div>';
1212
-
1213
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1214
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1215
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled />';
1216
  $html .= '</div>';
1217
 
1218
  $html .= '</div>';
1219
-
1220
  }
1221
  else {
1222
-
1223
  $html .= '<div class="hotspot-type hotspot-setting">';
1224
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1225
- $html .= '<select class="trtr" name="hotspot-type">';
1226
  $html .= '<option value="info"> Info</option>';
1227
  $html .= '<option value="scene" selected> Scene</option>';
1228
  $html .= '</select>';
1229
 
1230
  $html .= '<div class="hotspot-url" style="display:none;">';
1231
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').'</label>';
1232
  $html .= '<input type="url" name="hotspot-url" />';
1233
  $html .= '</div>';
1234
 
1235
- $html .= '<div class="hotspot-content" style="display:none;">';
1236
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1237
  $html .= '<textarea name="hotspot-content"></textarea>';
1238
  $html .= '</div>';
1239
 
1240
  $html .= '<div class="hotspot-hover">';
1241
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').' </label>';
1242
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1243
  $html .= '</div>';
1244
 
1245
- $html .= '<div class="hotspot-scene" >';
1246
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1247
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1248
- $html .= '<option value="none" selected> None</option>';
1249
- $html .= '</select>';
1250
- $html .= '</div>';
1251
-
1252
  $html .= '<div class="hotspot-scene">';
1253
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1254
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" disabled />';
1255
  $html .= '</div>';
1256
 
1257
  $html .= '</div>';
1258
-
1259
  }
1260
  //=Hotspot type End=//
1261
- $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1262
  $html .= '</div>';
1263
  }
1264
  $h++;
1265
  }
1266
  $html .= '</div>';
1267
- $html .= '</div>';
1268
  }
1269
  else {
1270
- $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
1271
-
1272
- $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
1273
- $html .= '<ul>';
1274
- $html .= '<li class="active"><span data-index="1" data-href="#scene-'.$s.'-hotspot-1"><i class="far fa-dot-circle"></i></span></li>';
1275
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> </span></li>';
1276
- $html .= '</ul>';
1277
- $html .= '</nav>';
1278
-
1279
- $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
1280
- $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-1">';
1281
-
1282
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
1283
-
1284
- $html .= '<div class="wrapper">';
1285
- $html .= '<div class="hotspot-setting">';
1286
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1287
- $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
1288
- $html .= '</div>';
1289
-
1290
- $html .= '<div class="hotspot-setting">';
1291
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
1292
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch"/>';
1293
- $html .= '</div>';
1294
-
1295
- $html .= '<div class="hotspot-setting">';
1296
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1297
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw"/>';
1298
- $html .= '</div>';
1299
-
1300
- $html .= '<div class="hotspot-setting">';
1301
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1302
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
1303
- $html .= '</div>';
1304
-
1305
- $html .= '</div>';
1306
-
1307
- $html .= '<div class="hotspot-type hotspot-setting">';
1308
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1309
- $html .= '<select name="hotspot-type">';
1310
- $html .= '<option value="info" selected> Info</option>';
1311
- $html .= '<option value="scene"> Scene</option>';
1312
- $html .= '</select>';
1313
-
1314
- $html .= '<div class="hotspot-url">';
1315
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').'</label>';
1316
- $html .= '<input type="url" name="hotspot-url" value="" />';
1317
- $html .= '</div>';
1318
-
1319
- $html .= '<div class="hotspot-content">';
1320
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1321
- $html .= '<textarea name="hotspot-content"></textarea>';
1322
- $html .= '</div>';
1323
-
1324
- $html .= '<div class="hotspot-hover">';
1325
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
1326
- $html .= '<textarea name="hotspot-hover"></textarea>';
1327
- $html .= '</div>';
1328
-
1329
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1330
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1331
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1332
- $html .= '<option value="none"> None</option>';
1333
- $html .= '</select>';
1334
- $html .= '</div>';
1335
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1336
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1337
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
1338
- $html .= '</div>';
1339
-
1340
- $html .= '</div>';
1341
- //=Hotspot type End=//
1342
- $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1343
- $html .= '</div>';
1344
- $html .= '</div>';
1345
- $html .= '</div>';
1346
  }
1347
- $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>';
1348
  $html .= '</div>';
1349
  }
1350
  else {
1351
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab" data-title="1" id="scene-'.$s.'">';
1352
-
1353
  $html .= '<div class="scene-content">';
1354
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene Setting </h6>';
1355
 
1356
  //==Set Default Scene==//
1357
  if ($dscene == 'on') {
1358
- $html .= '<div class="single-settings dscene">';
1359
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
1360
  $html .= '<select class="dscen" name="dscene">';
1361
  $html .= '<option value="on" selected > Yes</option>';
1362
  $html .= '<option value="off"> No</option>';
1363
  $html .= '</select>';
1364
  $html .= '</div>';
1365
-
1366
  }
1367
  else {
1368
- $html .= '<div class="single-settings dscene">';
1369
- $html .= '<span>'.__('Set as default: ','wpvr').'</span>';
1370
  $html .= '<select class="dscen" name="dscene">';
1371
  $html .= '<option value="on"> Yes</option>';
1372
  $html .= '<option value="off" selected> No</option>';
@@ -1376,46 +1058,46 @@ class Wpvr_Admin {
1376
  //==Set Default Scene end==//
1377
 
1378
  $html .= '<div class=scene-setting>';
1379
- $html .= '<label for="scene-id">'.__('Scene ID : ','wpvr').'</label>';
1380
- $html .= '<input class="sceneid" type="text" name="scene-id" value="'.$scene_id.'" />';
1381
  $html .= '</div>';
1382
 
1383
  $html .= '<div class=scene-setting>';
1384
- $html .= '<label for="scene-type">'.__('Scene Type : ','wpvr').'</label>';
1385
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
1386
  $html .= '</div>';
1387
 
1388
  $html .= '<div class=scene-setting>';
1389
- $html .= '<label for="scene-upload">'.__('Scene Upload: ','wpvr').'</label>';
1390
  $html .= '<div class="form-group">';
1391
- $html .= '<img name ="scene-photo" src="'.$scene_photo.'"> <br/>';
1392
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
1393
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="'.$scene_photo.'">';
1394
  $html .= '</div>';
1395
  $html .= '</div>';
1396
- $html .= '</div>';
1397
-
1398
  if (!empty($pano_hotspots)) {
1399
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
1400
-
1401
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
1402
  $html .= '<ul>';
1403
  $j = 1;
1404
  foreach ($pano_hotspots as $pano_hotspot) {
1405
  if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
1406
- $html .= '<li class="active"><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'"><i class="far fa-dot-circle"></i></span></li>';
1407
  }
1408
  else {
1409
- $html .= '<li><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'"><i class="far fa-dot-circle"></i></span></li>';
1410
  }
1411
  $j++;
1412
  }
1413
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i></span></li>';
1414
  $html .= '</ul>';
1415
  $html .= '</nav>';
1416
-
1417
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
1418
-
1419
  $h = 1;
1420
  foreach ($pano_hotspots as $pano_hotspot) {
1421
  $hotspot_title = '';
@@ -1435,425 +1117,304 @@ class Wpvr_Admin {
1435
  $hotspot_target_scene = '';
1436
  $hotspot_target_scene = $pano_hotspot['hotspot-scene'];
1437
  $hotspot_custom_class = '';
1438
- if (isset($pano_hotspot['hotspot-customclass'])) {
1439
- $hotspot_custom_class = $pano_hotspot['hotspot-customclass'];
1440
- }
1441
-
1442
  if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
1443
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1444
-
1445
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
1446
-
1447
  $html .= '<div class="wrapper">';
1448
  $html .= '<div class="hotspot-setting">';
1449
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1450
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1451
  $html .= '</div>';
1452
 
1453
  $html .= '<div class="hotspot-setting">';
1454
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
1455
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1456
  $html .= '</div>';
1457
 
1458
  $html .= '<div class="hotspot-setting">';
1459
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1460
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1461
  $html .= '</div>';
1462
 
1463
- $html .= '<div class="hotspot-setting">';
1464
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1465
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1466
- $html .= '</div>';
1467
-
1468
  $html .= '</div>';
1469
-
1470
  //=Hotspot type=//
1471
  if ($hotspot_type == "info") {
1472
-
1473
  $html .= '<div class="hotspot-type hotspot-setting">';
1474
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1475
  $html .= '<select name="hotspot-type">';
1476
  $html .= '<option value="info" selected> Info</option>';
1477
  $html .= '<option value="scene"> Scene</option>';
1478
  $html .= '</select>';
1479
 
1480
  $html .= '<div class="hotspot-url">';
1481
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
1482
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1483
  $html .= '</div>';
1484
 
1485
  $html .= '<div class="hotspot-content">';
1486
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').' </label>';
1487
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1488
  $html .= '</div>';
1489
 
1490
  $html .= '<div class="hotspot-hover">';
1491
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').' </label>';
1492
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1493
  $html .= '</div>';
1494
 
1495
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1496
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1497
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1498
- $html .= '<option value="none" selected> None</option>';
1499
- $html .= '</select>';
1500
- $html .= '</div>';
1501
-
1502
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1503
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').' </label>';
1504
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene"/>';
1505
  $html .= '</div>';
1506
 
1507
  $html .= '</div>';
1508
-
1509
  }
1510
  else {
1511
-
1512
  $html .= '<div class="hotspot-type hotspot-setting">';
1513
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1514
- $html .= '<select class="trtr" name="hotspot-type">';
1515
  $html .= '<option value="info"> Info</option>';
1516
  $html .= '<option value="scene" selected> Scene</option>';
1517
  $html .= '</select>';
1518
 
1519
  $html .= '<div class="hotspot-url" style="display:none;">';
1520
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
1521
  $html .= '<input type="url" name="hotspot-url" />';
1522
  $html .= '</div>';
1523
 
1524
- $html .= '<div class="hotspot-content" style="display:none;">';
1525
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1526
  $html .= '<textarea name="hotspot-content"></textarea>';
1527
  $html .= '</div>';
1528
 
1529
  $html .= '<div class="hotspot-hover">';
1530
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').' </label>';
1531
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1532
  $html .= '</div>';
1533
 
1534
- $html .= '<div class="hotspot-scene" >';
1535
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1536
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1537
- $html .= '<option value="none" selected> None</option>';
1538
- $html .= '</select>';
1539
- $html .= '</div>';
1540
-
1541
  $html .= '<div class="hotspot-scene">';
1542
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1543
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" disabled />';
1544
  $html .= '</div>';
1545
 
1546
  $html .= '</div>';
1547
-
1548
  }
1549
  //=Hotspot type End=//
1550
- $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1551
- $html .= '</div>';
1552
  }
1553
  else {
1554
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1555
-
1556
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting</h6>';
1557
-
1558
  $html .= '<div class="wrapper">';
1559
  $html .= '<div class="hotspot-setting">';
1560
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1561
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1562
  $html .= '</div>';
1563
 
1564
  $html .= '<div class="hotspot-setting">';
1565
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
1566
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1567
  $html .= '</div>';
1568
 
1569
  $html .= '<div class="hotspot-setting">';
1570
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1571
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1572
  $html .= '</div>';
1573
 
1574
- $html .= '<div class="hotspot-setting">';
1575
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1576
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1577
- $html .= '</div>';
1578
-
1579
  $html .= '</div>';
1580
-
1581
  //=Hotspot type=//
1582
  if ($hotspot_type == "info") {
1583
-
1584
  $html .= '<div class="hotspot-type hotspot-setting">';
1585
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1586
  $html .= '<select name="hotspot-type">';
1587
  $html .= '<option value="info" selected> Info</option>';
1588
  $html .= '<option value="scene"> Scene</option>';
1589
  $html .= '</select>';
1590
 
1591
  $html .= '<div class="hotspot-url">';
1592
- $html .= '<label for="hotspot-url">'.__(' URL: ','wpvr').'</label>';
1593
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1594
  $html .= '</div>';
1595
 
1596
  $html .= '<div class="hotspot-content">';
1597
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').' </label>';
1598
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1599
  $html .= '</div>';
1600
 
1601
  $html .= '<div class="hotspot-hover">';
1602
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').' </label>';
1603
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1604
  $html .= '</div>';
1605
 
1606
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1607
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1608
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1609
- $html .= '<option value="none" selected> None</option>';
1610
- $html .= '</select>';
1611
- $html .= '</div>';
1612
-
1613
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1614
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').' </label>';
1615
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled />';
1616
  $html .= '</div>';
1617
 
1618
  $html .= '</div>';
1619
-
1620
  }
1621
  else {
1622
-
1623
  $html .= '<div class="hotspot-type hotspot-setting">';
1624
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1625
- $html .= '<select class="trtr" name="hotspot-type">';
1626
  $html .= '<option value="info"> Info</option>';
1627
  $html .= '<option value="scene" selected> Scene</option>';
1628
  $html .= '</select>';
1629
 
1630
  $html .= '<div class="hotspot-url" style="display:none;">';
1631
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').' </label>';
1632
  $html .= '<input type="url" name="hotspot-url" />';
1633
  $html .= '</div>';
1634
 
1635
- $html .= '<div class="hotspot-content" style="display:none;">';
1636
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').' </label>';
1637
  $html .= '<textarea name="hotspot-content"></textarea>';
1638
  $html .= '</div>';
1639
 
1640
  $html .= '<div class="hotspot-hover">';
1641
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
1642
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1643
  $html .= '</div>';
1644
 
1645
- $html .= '<div class="hotspot-scene" >';
1646
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1647
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1648
- $html .= '<option value="none" selected> None</option>';
1649
- $html .= '</select>';
1650
- $html .= '</div>';
1651
-
1652
  $html .= '<div class="hotspot-scene">';
1653
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').' </label>';
1654
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" disabled />';
1655
  $html .= '</div>';
1656
 
1657
  $html .= '</div>';
1658
-
1659
  }
1660
  //=Hotspot type End=//
1661
- $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1662
  $html .= '</div>';
1663
  }
1664
  $h++;
1665
  }
1666
  $html .= '</div>';
1667
- $html .= '</div>';
1668
  }
1669
  else {
1670
- $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
1671
-
1672
- $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
1673
- $html .= '<ul>';
1674
- $html .= '<li class="active"><span data-index="1" data-href="#scene-'.$s.'-hotspot-1"><i class="far fa-dot-circle"></i></span></li>';
1675
- $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> </span></li>';
1676
- $html .= '</ul>';
1677
- $html .= '</nav>';
1678
-
1679
- $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
1680
- $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-1">';
1681
-
1682
- $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot Setting </h6>';
1683
-
1684
- $html .= '<div class="wrapper">';
1685
- $html .= '<div class="hotspot-setting">';
1686
- $html .= '<label for="hotspot-title">'.__('Hotspot ID : ','wpvr').'</label>';
1687
- $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
1688
- $html .= '</div>';
1689
-
1690
- $html .= '<div class="hotspot-setting">';
1691
- $html .= '<label for="hotspot-pitch">'.__('Pitch: ','wpvr').'</label>';
1692
- $html .= '<input type="text" class="hotspot-pitch" name="hotspot-pitch"/>';
1693
- $html .= '</div>';
1694
-
1695
- $html .= '<div class="hotspot-setting">';
1696
- $html .= '<label for="hotspot-yaw">'.__('Yaw: ','wpvr').'</label>';
1697
- $html .= '<input type="text" class="hotspot-yaw" name="hotspot-yaw"/>';
1698
- $html .= '</div>';
1699
-
1700
- $html .= '<div class="hotspot-setting">';
1701
- $html .= '<label for="hotspot-customclass">'.__('Hotspot custom icon class: ','wpvr').'</label>';
1702
- $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
1703
- $html .= '</div>';
1704
-
1705
- $html .= '</div>';
1706
-
1707
- $html .= '<div class="hotspot-type hotspot-setting">';
1708
- $html .= '<label for="hotspot-type">'.__('Hotspot-Type: ','wpvr').'</label>';
1709
- $html .= '<select name="hotspot-type">';
1710
- $html .= '<option value="info" selected> Info</option>';
1711
- $html .= '<option value="scene"> Scene</option>';
1712
- $html .= '</select>';
1713
-
1714
- $html .= '<div class="hotspot-url">';
1715
- $html .= '<label for="hotspot-url">'.__('URL: ','wpvr').'</label>';
1716
- $html .= '<input type="url" name="hotspot-url" value="" />';
1717
- $html .= '</div>';
1718
-
1719
- $html .= '<div class="hotspot-content">';
1720
- $html .= '<label for="hotspot-content">'.__('On click Content: ','wpvr').'</label>';
1721
- $html .= '<textarea name="hotspot-content"></textarea>';
1722
- $html .= '</div>';
1723
-
1724
- $html .= '<div class="hotspot-hover">';
1725
- $html .= '<label for="hotspot-hover">'.__('On hover Content: ','wpvr').'</label>';
1726
- $html .= '<textarea name="hotspot-hover"></textarea>';
1727
- $html .= '</div>';
1728
-
1729
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1730
- $html .= '<label for="hotspot-scene">'.__('Select Target Scene from List: ','wpvr').'</label>';
1731
- $html .= '<select class="hotspotscene" name="hotspot-scene-list">';
1732
- $html .= '<option value="none"> None</option>';
1733
- $html .= '</select>';
1734
- $html .= '</div>';
1735
- $html .= '<div class="hotspot-scene" style="display:none;" >';
1736
- $html .= '<label for="hotspot-scene">'.__('Target Scene ID: ','wpvr').'</label>';
1737
- $html .= '<input class="hotspotsceneinfodata" type="text" name="hotspot-scene" disabled/>';
1738
- $html .= '</div>';
1739
-
1740
- $html .= '</div>';
1741
- //=Hotspot type End=//
1742
- $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="far fa-trash-alt"></i></button>';
1743
- $html .= '</div>';
1744
- $html .= '</div>';
1745
- $html .= '</div>';
1746
  }
1747
- $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>';
1748
  $html .= '</div>';
1749
  }
1750
  $s++;
1751
  }
1752
  $html .= '</div>';
1753
-
1754
  $html .= '</div>';
1755
  }
1756
-
1757
  $html .= '<div class="preview-btn-wrapper">';
1758
  $html .= '<div class="preview-btn-area clearfix">';
1759
-
1760
- $html .= '<button id="panolenspreview">'.__('Preview','wpvr').'</button>';
1761
  $html .= '</div>';
1762
  $html .= '</div>';
1763
  $html .='</div>';
1764
  //---end scenes tab----
1765
- $html .= '<div id="error_occured"></div>';
1766
- //----start video tab content---------
1767
- $html .='<div class="rex-pano-tab video" id="video">';
1768
- $html .= '<h6 class="title"> '.__('Video Settings : ','wpvr').'</h6>';
1769
- //==Video Setup==//
1770
- if (isset($postdata['vidid'])) {
1771
- $vidautoplay = $postdata['vidautoplay'];
1772
- $vidautoplay_on = '';
1773
- $vidautoplay_off = '';
1774
- if (!empty($vidautoplay)) {
1775
- $vidautoplay_on = 'checked';
1776
- }
1777
- else {
1778
- $vidautoplay_off = 'checked';
1779
- }
1780
-
1781
- $vidcontrol = $postdata['vidcontrol'];
1782
- $vidcontrol_on = '';
1783
- $vidcontrol_off = '';
1784
- if (!empty($vidcontrol)) {
1785
- $vidcontrol_on = 'checked';
1786
- }
1787
- else {
1788
- $vidcontrol_off = 'checked';
1789
- }
1790
- $html .= '<div class="single-settings videosetup">';
1791
- $html .= '<span>Enable Video: </span>';
1792
- $html .= '<ul>';
1793
- $html .= '<li class="radio-btn">';
1794
- $html .= '<input class="styled-radio" id="styled-radio" type="radio" name="panovideo" value="off" >';
1795
- $html .= '<label for="styled-radio">Off</label>';
1796
- $html .= '</li>';
1797
-
1798
- $html .= '<li class="radio-btn">';
1799
- $html .= '<input class="styled-radio" id="styled-radio-0" type="radio" name="panovideo" value="on" checked>';
1800
- $html .= '<label for="styled-radio-0">On</label>';
1801
- $html .= '</li>';
1802
- $html .= '</ul>';
1803
- $html .= '</div>';
1804
-
1805
-
1806
- $html .= '<div class="video-setting" style="display:none;">';
1807
- $html .= '<div class="single-settings">';
1808
- $html .= '<span>Upload or add link: </span>';
1809
- $html .= '<div class="form-group">';
1810
- $html .= '<input type="text" name="video-attachment-url" placeholder="Paste Youtube or Vimeo link or upload" class="video-attachment-url" value="'.$postdata['vidurl'].'">';
1811
- $html .= '<input type="button" class="video-upload" data-info="" value="Upload" />';
1812
- $html .= '</div>';
1813
- $html .= '</div>';
1814
- $html .= '<button id="videopreview">Preview</button>';
1815
- $html .= '</div>';
1816
- }
1817
- else {
1818
- $html .= '<div class="single-settings videosetup">';
1819
- $html .= '<span>Enable Video: </span>';
1820
- $html .= '<ul>';
1821
- $html .= '<li class="radio-btn">';
1822
- $html .= '<input class="styled-radio" id="styled-radio" type="radio" name="panovideo" value="off" checked >';
1823
- $html .= '<label for="styled-radio">Off</label>';
1824
- $html .= '</li>';
1825
-
1826
- $html .= '<li class="radio-btn">';
1827
- $html .= '<input class="styled-radio" id="styled-radio-0" type="radio" name="panovideo" value="on" >';
1828
- $html .= '<label for="styled-radio-0">On</label>';
1829
- $html .= '</li>';
1830
- $html .= '</ul>';
1831
- $html .= '</div>';
1832
-
1833
- //==Video setup end==//
1834
-
1835
- //==Video Setting==/
1836
- $html .= '<div class="video-setting" style="display:none;">';
1837
- $html .= '<div class="single-settings">';
1838
- $html .= '<span>Upload or add link: </span>';
1839
- $html .= '<div class="form-group">';
1840
- $html .= '<input type="text" placeholder="Paste Youtube or Vimeo link or upload" name="video-attachment-url" class="video-attachment-url" value="">';
1841
- $html .= '<input type="button" class="video-upload" data-info="" value="Upload"/>';
1842
- $html .= '</div>';
1843
- $html .= '</div>';
1844
- $html .= '<button id="videopreview">Preview</button>';
1845
- $html .= '</div>';
1846
- }
1847
- //==Video Setting End==//
1848
- $html .='</div>';
1849
- //---end video tab----
1850
  $html .='</div>';
1851
  //---end rex-pano-tab-content----
 
1852
  $html .='</div>';
1853
  //---end rex-pano-tabs---
1854
- $html .= '</div>';
1855
- $html .= '<div class="wpvr-loading" style="display:none;">Loading&#8230;</div>';
1856
- echo $html;
1857
  }
1858
 
1859
  }
79
  * between the defined hooks and the functions defined in this
80
  * class.
81
  */
82
+ wp_enqueue_style( $this->plugin_name . 'fontawesome', 'https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', array(), $this->version, 'all' );
83
+ wp_enqueue_style( 'materialize-icons', 'https://fonts.googleapis.com/icon?family=Material+Icons', array(), $this->version, 'all' );
84
 
85
+ $screen = get_current_screen();
 
 
 
 
 
86
 
87
+ if ($screen->id=="toplevel_page_wpvr") {
88
+ wp_enqueue_style( 'materialize-css', plugin_dir_url( __FILE__ ) . 'css/materialize.min.css', array(), $this->version, 'all' );
89
+ }
90
+ wp_enqueue_style('panellium-css', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/css/pannellum.css', array(), true);
91
+ wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/wpvr-admin.css', array(), $this->version, 'all' );
 
 
 
 
92
 
93
  }
94
 
110
  * between the defined hooks and the functions defined in this
111
  * class.
112
  */
 
 
113
  wp_enqueue_media();
114
+ wp_enqueue_script('panellium-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/pannellum.js', array(), true);
115
+ wp_enqueue_script('panelliumlib-js', plugin_dir_url( __FILE__ ) . 'lib/pannellum/src/js/libpannellum.js', array(), true);
116
+ wp_enqueue_script( 'materialize-js', plugin_dir_url( __FILE__ ) . 'js/materialize.min.js', array( 'jquery' ), $this->version, false );
117
+ wp_enqueue_script( 'jquery-repeater', plugin_dir_url( __FILE__ ) .'js/jquery.repeater.min.js', array('jquery'), true);
118
+ wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/wpvr-admin.js', array( 'jquery' ), $this->version, false );
119
+ wp_localize_script( $this->plugin_name, 'wpvr_obj', array(
120
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
121
+ 'ajax_nonce' => wp_create_nonce('wpvr'),
122
+ ) );
 
 
 
 
 
 
123
 
 
 
 
 
 
 
 
 
124
  }
125
 
126
  /**
134
  */
135
 
136
  add_meta_box(
137
+ $this->post_type . '_builder_box',
138
+ __('Preview', $this->plugin_name),
139
  array($this, 'wpvr_display_meta_box_builder'),
140
  $this->post_type,
141
  'advanced',
143
  );
144
 
145
  add_meta_box(
146
+ $this->post_type . '_shortcode_box',
147
  __('Using this VR', $this->plugin_name),
148
  array($this, 'wpvr_display_meta_box_shortcode'),
149
  $this->post_type,
172
  'all_items' => __( 'All Tours', $this->plugin_name ),
173
  'menu_name' => __( 'Wpvr', $this->plugin_name ),
174
  );
175
+
176
  $args = array(
177
  'labels' => $labels,
178
  'public' => false,
181
  'menu_position' => 100,
182
  'supports' => array( 'title' ),
183
  );
184
+
185
  /**
186
  * Documentation : https://codex.wordpress.org/Function_Reference/register_post_type
187
  */
195
  */
196
  function wpvr_manage_posts_custom_column( $column_name ){
197
  $post = get_post();
198
+
199
  switch( $column_name ) {
200
  case 'shortcode' :
201
  echo '<code>[wpvr id="' . $post->ID . '"]</code>';
229
  public function wpvr_post_updated_messages( $messages ) {
230
  $messages[$this->post_type][1] = __( 'Wpvr item updated.', $this->plugin_name);
231
  $messages[$this->post_type][4] = __( 'Wpvr item updated.', $this->plugin_name);
232
+
233
  return $messages;
234
  }
235
 
239
  * @since 1.0.0
240
  */
241
  public function wpvr_display_meta_box_shortcode() {
242
+
243
  include_once( 'partials/wpvr-meta-box-shortcode-display.php' );
244
  }
245
 
260
  }
261
  public function wpvr_setup($post) {
262
 
263
+ $status = get_option( 'wpvr_edd_license_status' );
264
+ if( $status !== false && $status == 'valid' ) {
265
+ $data_limit = 999999999;
266
+ }
267
+ else {
268
+ $data_limit = 5;
269
+ }
270
  $postdata = get_post_meta( $post->ID, 'panodata', true );
271
+ $autoload = false;
 
 
272
  if (isset($postdata["autoLoad"])) {
273
  $autoload = $postdata["autoLoad"];
274
  }
275
+
276
+ $control = false;
277
  if (isset($postdata["showControls"])) {
278
  $control = $postdata["showControls"];
279
  }
280
+
281
  $default_scene = '';
282
  if (isset($postdata["defaultscene"])) {
283
  $default_scene = $postdata["defaultscene"];
284
  }
285
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  $scene_fade_duration = '';
287
  if (isset($postdata["scenefadeduration"])) {
288
  $scene_fade_duration = $postdata["scenefadeduration"];
289
  }
290
+
291
  $pano_data = '';
292
  if (isset($postdata["panodata"])) {
293
  $pano_data = $postdata["panodata"];
294
  }
295
+
 
 
 
296
  $html = '';
297
 
298
  $html .= '<div class="pano-setup">';
299
+
300
  $html .= '<div class="pano-alert scene-alert">';
301
  $html .= '<span class="destroy"><i class="fa fa-times"></i></span>';
302
  $html .= '<p></p>';
303
  $html .= '</div>';
304
+
305
  $html .='<div class="rex-pano-tabs">';
306
  $html .='<nav class="rex-pano-tab-nav rex-pano-nav-menu main-nav">';
307
  $html .='<ul>';
308
+ $html .='<li class="general active"><span data-href="#general"><i class="fa fa-cogs"></i> general</span></li>';
309
+ $html .='<li class="scene"><span data-href="#scenes"><i class="fa fa-photo"></i> Scenes</span></li>';
310
+ $html .='<li class="hotspot"><span data-href="#scenes"><i class="fa fa-dot-circle-o"></i> hotspot</span></li>';
 
311
  $html .='</ul>';
312
  $html .='</nav>';
313
+
314
  $html .='<div class="rex-pano-tab-content">';
315
  $html .='<div class="rex-pano-tab general active" id="general">';
316
+
317
+ $html .= '<h6 class="title"> General Settings : </h6>';
318
+ //=Autoload setup=
319
+ if ($autoload == true) {
320
+ $html .= '<div class="single-settings autoload">';
321
+ $html .= '<span>Autoload: </span>';
 
322
  $html .= '<ul>';
323
  $html .= '<li class="radio-btn">';
324
+ $html .= '<input class="styled-radio" id="styled-radio-1" type="radio" name="autoload" value="off">';
325
+ $html .= '<label for="styled-radio-1">Off</label>';
326
  $html .= '</li>';
327
+
328
  $html .= '<li class="radio-btn">';
329
+ $html .= '<input class="styled-radio" id="styled-radio-2" type="radio" name="autoload" value="on" checked >';
330
+ $html .= '<label for="styled-radio-2">On</label>';
331
  $html .= '</li>';
332
  $html .= '</ul>';
333
  $html .= '</div>';
334
  }
335
  else {
336
+ $html .= '<div class="single-settings autoload">';
337
+ $html .= '<span>Autoload: </span>';
338
  $html .= '<ul>';
339
  $html .= '<li class="radio-btn">';
340
+ $html .= '<input class="styled-radio" id="styled-radio-1" type="radio" name="autoload" value="off" checked >';
341
+ $html .= '<label for="styled-radio-1">Off</label>';
342
  $html .= '</li>';
343
+
344
  $html .= '<li class="radio-btn">';
345
+ $html .= '<input class="styled-radio" id="styled-radio-2" type="radio" name="autoload" value="on">';
346
+ $html .= '<label for="styled-radio-2">On</label>';
347
  $html .= '</li>';
348
  $html .= '</ul>';
349
  $html .= '</div>';
350
  }
351
+ //=Autoload setup End=
 
 
 
 
 
 
 
352
 
353
+ //=Control Setup=
354
+ if ($control == true) {
355
+ $html .= '<div class="single-settings controls">';
356
+ $html .= '<span>Show Controls: </span>';
357
  $html .= '<ul>';
358
  $html .= '<li class="radio-btn">';
359
+ $html .= '<input class="styled-radio" id="styled-radio-3" type="radio" name="controls" value="off">';
360
+ $html .= '<label for="styled-radio-3">Off</label>';
361
  $html .= '</li>';
362
+
363
  $html .= '<li class="radio-btn">';
364
+ $html .= '<input class="styled-radio" id="styled-radio-4" type="radio" name="controls" value="on" checked >';
365
+ $html .= '<label for="styled-radio-4">On</label>';
366
  $html .= '</li>';
367
  $html .= '</ul>';
368
  $html .= '</div>';
369
  }
370
  else {
371
+ $html .= '<div class="single-settings controls">';
372
+ $html .= '<span>Show Controls: </span>';
373
  $html .= '<ul>';
374
  $html .= '<li class="radio-btn">';
375
+ $html .= '<input class="styled-radio" id="styled-radio-3" type="radio" name="controls" value="off" checked >';
376
+ $html .= '<label for="styled-radio-3">Off</label>';
377
  $html .= '</li>';
378
+
379
  $html .= '<li class="radio-btn">';
380
+ $html .= '<input class="styled-radio" id="styled-radio-4" type="radio" name="controls" value="on">';
381
+ $html .= '<label for="styled-radio-4">On</label>';
382
  $html .= '</li>';
383
  $html .= '</ul>';
384
  $html .= '</div>';
385
  }
386
+ //=Control setup End=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
+ //=scene fade duration=
389
+ $html .= '<div class="single-settings scene-fade-duration">';
390
+ $html .= '<span>Scene Fade Duration: </span>';
391
+ $html .= '<input type="number" name="scene-fade-duration" value="'.$scene_fade_duration.'" />';
392
+ $html .= '</div>';
393
+ //=scene fade duration End=
394
+
395
  $html .='</div>';
396
  //---end general tab----
397
+
398
  $html .='<div class="rex-pano-tab" id="scenes">';
399
+
400
  //=Scene and Hotspot repeater=//
401
  if (empty($pano_data)) {
402
+ $html .= '<div class="scene-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
403
+
404
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu scene-nav">';
405
  $html .= '<ul>';
406
+ $html .= '<li class="active"><span data-index="1" data-href="#scene-1">Scene 1</span></li>';
407
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
408
  $html .= '</ul>';
409
  $html .= '</nav>';
410
+
411
  $html .= '<div data-repeater-list="scene-list" class="rex-pano-tab-content">';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab active" data-title="1" id="scene-1">';
413
+
414
  $html .= '<div class="scene-content">';
415
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene <span class="scene-num">1</span> Setting </h6>';
416
 
417
  //==Set Default Scene==//
418
+ $html .= '<div class="single-settings dscene">';
419
+ $html .= '<span>Set as default: </span>';
420
  $html .= '<select class="dscen" name="dscene">';
421
  $html .= '<option value="on"> Yes</option>';
422
  $html .= '<option value="off" selected > No</option>';
425
  //==Set Default Scene end==//
426
 
427
  $html .= '<div class=scene-setting>';
428
+ $html .= '<label for="scene-id">Scene ID : </label>';
429
+ $html .= '<input type="text" name="scene-id"/>';
430
  $html .= '</div>';
431
 
432
  $html .= '<div class=scene-setting>';
433
+ $html .= '<label for="scene-type">Scene Type : </label>';
434
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
435
  $html .= '</div>';
436
 
437
  $html .= '<div class=scene-setting>';
438
+ $html .= '<label for="scene-upload">Scene Upload: </label>';
439
  $html .= '<div class="form-group">';
440
+ $html .= '<img src="" style="display: none;"><br>';
441
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
442
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="">';
443
  $html .= '</div>';
444
  $html .= '</div>';
445
  $html .= '</div>';
446
+
447
+ //--hotspot setup--
448
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
449
+
450
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
451
  $html .= '<ul>';
452
+ $html .= '<li class="active"><span data-index="1" data-href="#scene-1-hotspot-1">Hotspot 1</span></li>';
453
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
454
  $html .= '</ul>';
455
  $html .= '</nav>';
456
+
457
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
458
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-1-hotspot-1">';
459
+
460
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">1</span> Setting for <span>Scene <span class="scene-num">1</span></span> </h6>';
461
+
462
  $html .= '<div class="wrapper">';
463
  $html .= '<div class="hotspot-setting">';
464
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
465
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
466
  $html .= '</div>';
467
 
468
  $html .= '<div class="hotspot-setting">';
469
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
470
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch"/>';
471
  $html .= '</div>';
472
 
473
  $html .= '<div class="hotspot-setting">';
474
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
475
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw"/>';
476
  $html .= '</div>';
477
 
478
+ $html .= '<div class="hotspot-setting">';
479
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
480
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
481
+ $html .= '</div>';
 
482
  $html .= '</div>';
483
+
484
  $html .= '<div class="hotspot-type hotspot-setting">';
485
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
486
  $html .= '<select name="hotspot-type">';
487
  $html .= '<option value="info" selected> Info</option>';
488
  $html .= '<option value="scene"> Scene</option>';
489
  $html .= '</select>';
490
 
491
  $html .= '<div class="hotspot-url">';
492
+ $html .= '<label for="hotspot-url"> URL: </label>';
493
  $html .= '<input type="url" name="hotspot-url" value="" />';
494
  $html .= '</div>';
495
+
496
  $html .= '<div class="hotspot-content">';
497
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
498
  $html .= '<textarea name="hotspot-content"></textarea>';
499
  $html .= '</div>';
500
+
501
  $html .= '<div class="hotspot-hover">';
502
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
503
  $html .= '<textarea name="hotspot-hover"></textarea>';
504
  $html .= '</div>';
505
+
506
  $html .= '<div class="hotspot-scene" style="display:none;" >';
507
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
508
+ $html .= '<input type="text" name="hotspot-scene"/>';
 
 
509
  $html .= '</div>';
510
+
 
 
 
 
511
  $html .= '</div>';
512
  //=Hotspot type End=//
513
+ $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
514
  $html .= '</div>';
515
  $html .= '</div>';
516
+
517
  $html .= '</div>';
518
+ $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="fa fa-trash-o"></i></button>';
519
  $html .= '</div>';
520
  $html .= '</div>';
521
+
522
+ $html .= '</div>';
523
  }
524
  else {
525
+ $html .= '<div class="scene-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
526
+
527
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu scene-nav">';
528
  $html .= '<ul>';
529
+ $html .= '<li><span data-index="0" data-href="#scene-0">Scene 0</span></li>';
530
  $i = 1;
 
531
  foreach ($pano_data["scene-list"] as $pano_scenes) {
532
+ if ($pano_scenes['scene-id'] == $pano_data['scene-list'][0]['scene-id']) {
533
+ $html .= '<li class="active"><span data-index="'.$i.'" data-href="#scene-'.$i.'">Scene '.$i.'</span></li>';
534
  }
535
  else {
536
+ $html .= '<li><span data-index="'.$i.'" data-href="#scene-'.$i.'">Scene '.$i.'</span></li>';
537
  }
538
  $i++;
539
  }
540
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
541
  $html .= '</ul>';
542
  $html .= '</nav>';
543
+
544
 
545
  $html .= '<div data-repeater-list="scene-list" class="rex-pano-tab-content">';
546
 
547
+ //test
548
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab" data-title="0" id="scene-0">';
549
+
550
  $html .= '<div class="scene-content">';
551
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene <span class="scene-num">0</span> Setting </h6>';
552
 
553
  //==Set Default Scene==//
554
+ $html .= '<div class="single-settings dscene">';
555
+ $html .= '<span>Set as default: </span>';
556
  $html .= '<select class="dscen" name="dscene">';
557
  $html .= '<option value="on"> Yes</option>';
558
  $html .= '<option value="off" selected > No</option>';
560
  $html .= '</div>';
561
  //==Set Default Scene end==//
562
  $html .= '<div class=scene-setting>';
563
+ $html .= '<label for="scene-id">Scene ID : </label>';
564
+ $html .= '<input type="text" name="scene-id"/>';
565
  $html .= '</div>';
566
 
567
  $html .= '<div class=scene-setting>';
568
+ $html .= '<label for="scene-type">Scene Type : </label>';
569
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
570
  $html .= '</div>';
571
 
572
  $html .= '<div class=scene-setting>';
573
+ $html .= '<label for="scene-upload">Scene Upload: </label>';
574
  $html .= '<div class="form-group">';
575
+ $html .= '<img src="" style="display: none;"><br>';
576
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
577
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="">';
578
  $html .= '</div>';
579
  $html .= '</div>';
580
  $html .= '</div>';
581
+
582
+ //--hotspot setup--
583
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
584
+
585
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
586
  $html .= '<ul>';
587
+ $html .= '<li class="active"><span data-index="1" data-href="#scene-0-hotspot-1">Hotspot 1</span></li>';
588
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
589
  $html .= '</ul>';
590
  $html .= '</nav>';
591
+
592
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
593
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-0-hotspot-1">';
594
+
595
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">1</span> Setting for <span>Scene <span class="scene-num">0</span></span> </h6>';
596
+
597
  $html .= '<div class="wrapper">';
598
  $html .= '<div class="hotspot-setting">';
599
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
600
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
601
  $html .= '</div>';
602
 
603
  $html .= '<div class="hotspot-setting">';
604
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
605
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch"/>';
606
  $html .= '</div>';
607
 
608
  $html .= '<div class="hotspot-setting">';
609
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
610
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw"/>';
611
  $html .= '</div>';
612
 
613
+ $html .= '<div class="hotspot-setting">';
614
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
615
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
616
+ $html .= '</div>';
 
617
  $html .= '</div>';
618
+
619
  $html .= '<div class="hotspot-type hotspot-setting">';
620
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
621
  $html .= '<select name="hotspot-type">';
622
  $html .= '<option value="info" selected> Info</option>';
623
  $html .= '<option value="scene"> Scene</option>';
624
  $html .= '</select>';
625
 
626
  $html .= '<div class="hotspot-url">';
627
+ $html .= '<label for="hotspot-url"> URL: </label>';
628
  $html .= '<input type="url" name="hotspot-url" value="" />';
629
  $html .= '</div>';
630
+
631
  $html .= '<div class="hotspot-content">';
632
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
633
  $html .= '<textarea name="hotspot-content"></textarea>';
634
  $html .= '</div>';
635
+
636
  $html .= '<div class="hotspot-hover">';
637
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
638
  $html .= '<textarea name="hotspot-hover"></textarea>';
639
  $html .= '</div>';
640
+
 
 
 
 
 
 
 
641
  $html .= '<div class="hotspot-scene" style="display:none;" >';
642
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
643
+ $html .= '<input type="text" name="hotspot-scene"/>';
644
  $html .= '</div>';
645
+
646
  $html .= '</div>';
647
  //=Hotspot type End=//
648
+ $html .= '<button data-repeater-delete title="Delete Hotspot" type="button" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
649
  $html .= '</div>';
650
  $html .= '</div>';
651
+
652
  $html .= '</div>';
653
+ $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="fa fa-trash-o"></i></button>';
654
  $html .= '</div>';
655
+ //test
656
 
657
  $s = 1;
658
  foreach ($pano_data["scene-list"] as $pano_scenes) {
666
  $scene_type = $pano_scenes["scene-type"];
667
  $scene_photo = '';
668
  $scene_photo = $pano_scenes["scene-attachment-url"];
 
669
  $pano_hotspots = array();
670
+ $pano_hotspots = $pano_scenes["hotspot-list"];
671
+
672
+ if ($pano_scenes['scene-id'] == $pano_data['scene-list'][0]['scene-id']) {
 
 
 
673
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab active" data-title="1" id="scene-'.$s.'">';
674
+
675
  $html .= '<div class="scene-content">';
676
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene <span class="scene-num">'.$s.'</span> Setting </h6>';
677
  //==Set Default Scene==//
678
  if ($dscene == 'on') {
679
+ $html .= '<div class="single-settings dscene">';
680
+ $html .= '<span>Set as default: </span>';
681
  $html .= '<select class="dscen" name="dscene">';
682
  $html .= '<option value="on" selected > Yes</option>';
683
  $html .= '<option value="off"> No</option>';
684
  $html .= '</select>';
685
  $html .= '</div>';
686
+
687
  }
688
  else {
689
+ $html .= '<div class="single-settings dscene">';
690
+ $html .= '<span>Set as default: </span>';
691
  $html .= '<select class="dscen" name="dscene">';
692
  $html .= '<option value="on"> Yes</option>';
693
  $html .= '<option value="off" selected > No</option>';
696
  }
697
  //==Set Default Scene end==//
698
  $html .= '<div class=scene-setting>';
699
+ $html .= '<label for="scene-id">Scene ID : </label>';
700
+ $html .= '<input type="text" name="scene-id" value="'.$scene_id.'" />';
701
  $html .= '</div>';
702
 
703
  $html .= '<div class=scene-setting>';
704
+ $html .= '<label for="scene-type">Scene Type : </label>';
705
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
706
  $html .= '</div>';
707
 
708
  $html .= '<div class=scene-setting>';
709
+ $html .= '<label for="scene-upload">Scene Upload: </label>';
710
  $html .= '<div class="form-group">';
711
+ $html .= '<img name ="scene-photo" src="'.$scene_photo.'"> <br/>';
712
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
713
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="'.$scene_photo.'">';
714
  $html .= '</div>';
715
  $html .= '</div>';
716
+ $html .= '</div>';
717
+
718
  if (!empty($pano_hotspots)) {
719
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
720
+
721
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
722
  $html .= '<ul>';
723
  $j = 1;
 
724
  foreach ($pano_hotspots as $pano_hotspot) {
725
+ if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
726
+ $html .= '<li class="active"><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'">Hotspot '.$j.'</span></li>';
 
727
  }
728
  else {
729
+ $html .= '<li><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'">Hotspot '.$j.'</span></li>';
730
  }
731
  $j++;
732
  }
733
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
734
  $html .= '</ul>';
735
  $html .= '</nav>';
736
+
737
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
738
+
739
  $h = 1;
 
740
  foreach ($pano_hotspots as $pano_hotspot) {
741
  $hotspot_title = '';
742
  $hotspot_title = $pano_hotspot['hotspot-title'];
755
  $hotspot_target_scene = '';
756
  $hotspot_target_scene = $pano_hotspot['hotspot-scene'];
757
  $hotspot_custom_class = '';
758
+ $hotspot_custom_class = $pano_hotspot['hotspot-customclass'];
759
+ if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
 
 
 
760
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
761
+
762
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">'.$h.'</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
763
+
764
  $html .= '<div class="wrapper">';
765
  $html .= '<div class="hotspot-setting">';
766
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
767
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
768
  $html .= '</div>';
769
 
770
  $html .= '<div class="hotspot-setting">';
771
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
772
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
 
773
  $html .= '</div>';
774
 
775
  $html .= '<div class="hotspot-setting">';
776
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
777
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
778
  $html .= '</div>';
779
 
780
+ $html .= '<div class="hotspot-setting">';
781
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
782
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
783
+ $html .= '</div>';
 
784
  $html .= '</div>';
785
+
786
  //=Hotspot type=//
787
  if ($hotspot_type == "info") {
788
+
789
  $html .= '<div class="hotspot-type hotspot-setting">';
790
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
791
  $html .= '<select name="hotspot-type">';
792
  $html .= '<option value="info" selected> Info</option>';
793
  $html .= '<option value="scene"> Scene</option>';
794
  $html .= '</select>';
795
 
796
  $html .= '<div class="hotspot-url">';
797
+ $html .= '<label for="hotspot-url"> URL: </label>';
798
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
799
  $html .= '</div>';
800
 
801
  $html .= '<div class="hotspot-content">';
802
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
803
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
804
  $html .= '</div>';
805
 
806
  $html .= '<div class="hotspot-hover">';
807
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
808
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
809
  $html .= '</div>';
810
 
811
  $html .= '<div class="hotspot-scene" style="display:none;" >';
812
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
813
+ $html .= '<input type="text" name="hotspot-scene"/>';
 
 
 
 
 
 
 
814
  $html .= '</div>';
815
 
816
  $html .= '</div>';
817
+
818
  }
819
  else {
820
+
821
  $html .= '<div class="hotspot-type hotspot-setting">';
822
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
823
+ $html .= '<select name="hotspot-type">';
824
  $html .= '<option value="info"> Info</option>';
825
  $html .= '<option value="scene" selected> Scene</option>';
826
  $html .= '</select>';
827
 
828
  $html .= '<div class="hotspot-url" style="display:none;">';
829
+ $html .= '<label for="hotspot-url"> URL: </label>';
830
  $html .= '<input type="url" name="hotspot-url" />';
831
  $html .= '</div>';
832
 
833
+ $html .= '<div class="hotspot-content" style="display:none;>';
834
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
835
  $html .= '<textarea name="hotspot-content"></textarea>';
836
  $html .= '</div>';
837
 
838
  $html .= '<div class="hotspot-hover">';
839
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
840
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
841
  $html .= '</div>';
842
 
 
 
 
 
 
 
 
843
  $html .= '<div class="hotspot-scene">';
844
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
845
+ $html .= '<input type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" />';
846
  $html .= '</div>';
847
 
848
  $html .= '</div>';
849
+
850
  }
851
  //=Hotspot type End=//
852
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
853
+ $html .= '</div>';
854
  }
855
  else {
856
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
857
+
858
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">'.$h.'</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
859
+
860
  $html .= '<div class="wrapper">';
861
  $html .= '<div class="hotspot-setting">';
862
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
863
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
864
  $html .= '</div>';
865
 
866
  $html .= '<div class="hotspot-setting">';
867
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
868
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
869
  $html .= '</div>';
870
 
871
  $html .= '<div class="hotspot-setting">';
872
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
873
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
874
  $html .= '</div>';
875
 
876
+ $html .= '<div class="hotspot-setting">';
877
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
878
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
879
+ $html .= '</div>';
 
880
  $html .= '</div>';
881
+
882
  //=Hotspot type=//
883
  if ($hotspot_type == "info") {
884
+
885
  $html .= '<div class="hotspot-type hotspot-setting">';
886
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
887
  $html .= '<select name="hotspot-type">';
888
  $html .= '<option value="info" selected> Info</option>';
889
  $html .= '<option value="scene"> Scene</option>';
890
  $html .= '</select>';
891
 
892
  $html .= '<div class="hotspot-url">';
893
+ $html .= '<label for="hotspot-url"> URL: </label>';
894
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
895
  $html .= '</div>';
896
 
897
  $html .= '<div class="hotspot-content">';
898
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
899
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
900
  $html .= '</div>';
901
 
902
  $html .= '<div class="hotspot-hover">';
903
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
904
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
905
  $html .= '</div>';
906
 
907
  $html .= '<div class="hotspot-scene" style="display:none;" >';
908
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
909
+ $html .= '<input type="text" name="hotspot-scene"/>';
 
 
 
 
 
 
 
910
  $html .= '</div>';
911
 
912
  $html .= '</div>';
913
+
914
  }
915
  else {
916
+
917
  $html .= '<div class="hotspot-type hotspot-setting">';
918
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
919
+ $html .= '<select name="hotspot-type">';
920
  $html .= '<option value="info"> Info</option>';
921
  $html .= '<option value="scene" selected> Scene</option>';
922
  $html .= '</select>';
923
 
924
  $html .= '<div class="hotspot-url" style="display:none;">';
925
+ $html .= '<label for="hotspot-url"> URL: </label>';
926
  $html .= '<input type="url" name="hotspot-url" />';
927
  $html .= '</div>';
928
 
929
+ $html .= '<div class="hotspot-content" style="display:none;>';
930
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
931
  $html .= '<textarea name="hotspot-content"></textarea>';
932
  $html .= '</div>';
933
 
934
  $html .= '<div class="hotspot-hover">';
935
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
936
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
937
  $html .= '</div>';
938
 
 
 
 
 
 
 
 
939
  $html .= '<div class="hotspot-scene">';
940
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
941
+ $html .= '<input type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" />';
942
  $html .= '</div>';
943
 
944
  $html .= '</div>';
945
+
946
  }
947
  //=Hotspot type End=//
948
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
949
  $html .= '</div>';
950
  }
951
  $h++;
952
  }
953
  $html .= '</div>';
954
+ $html .= '</div>';
955
  }
956
  else {
957
+ $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
958
+
959
+ $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
960
+ $html .= '<ul>';
961
+ $html .= '<li class="active"><span data-index="0" data-href="#scene-'.$s.'-hotspot-1">Hotspot 1</span></li>';
962
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
963
+ $html .= '</ul>';
964
+ $html .= '</nav>';
965
+
966
+ $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content>';
967
+
968
+ $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-1">';
969
+
970
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">1</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
971
+
972
+ $html .= '<div class="wrapper">';
973
+ $html .= '<div class="hotspot-setting">';
974
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
975
+ $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
976
+ $html .= '</div>';
977
+
978
+ $html .= '<div class="hotspot-setting">';
979
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
980
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch"/>';
981
+ $html .= '</div>';
982
+
983
+ $html .= '<div class="hotspot-setting">';
984
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
985
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw"/>';
986
+ $html .= '</div>';
987
+
988
+ $html .= '<div class="hotspot-setting">';
989
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
990
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
991
+ $html .= '</div>';
992
+ $html .= '</div>';
993
+
994
+ $html .= '<div class="hotspot-type hotspot-setting">';
995
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
996
+ $html .= '<select name="hotspot-type">';
997
+ $html .= '<option value="info" selected> Info</option>';
998
+ $html .= '<option value="scene"> Scene</option>';
999
+ $html .= '</select>';
1000
+
1001
+ $html .= '<div class="hotspot-url">';
1002
+ $html .= '<label for="hotspot-url"> URL: </label>';
1003
+ $html .= '<input type="url" name="hotspot-url" />';
1004
+ $html .= '</div>';
1005
+
1006
+ $html .= '<div class="hotspot-content">';
1007
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1008
+ $html .= '<textarea name="hotspot-content"></textarea>';
1009
+ $html .= '</div>';
1010
+
1011
+ $html .= '<div class="hotspot-hover">';
1012
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1013
+ $html .= '<textarea name="hotspot-hover"></textarea>';
1014
+ $html .= '</div>';
1015
+
1016
+ $html .= '<div class="hotspot-scene" style="display:none;" >';
1017
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1018
+ $html .= '<input type="text" name="hotspot-scene"/>';
1019
+ $html .= '</div>';
1020
+
1021
+ $html .= '</div>';
1022
+ //=Hotspot type End=//
1023
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
1024
+ $html .= '</div>';
1025
+
1026
+ $html .= '</div>';
1027
+ $html .= '</div>';
 
 
 
 
 
1028
  }
1029
+ $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="fa fa-trash-o"></i></button>';
1030
  $html .= '</div>';
1031
  }
1032
  else {
1033
  $html .= '<div data-repeater-item class="single-scene rex-pano-tab" data-title="1" id="scene-'.$s.'">';
1034
+
1035
  $html .= '<div class="scene-content">';
1036
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Scene <span class="scene-num">'.$s.'</span> Setting </h6>';
1037
 
1038
  //==Set Default Scene==//
1039
  if ($dscene == 'on') {
1040
+ $html .= '<div class="single-settings dscene">';
1041
+ $html .= '<span>Set as default: </span>';
1042
  $html .= '<select class="dscen" name="dscene">';
1043
  $html .= '<option value="on" selected > Yes</option>';
1044
  $html .= '<option value="off"> No</option>';
1045
  $html .= '</select>';
1046
  $html .= '</div>';
1047
+
1048
  }
1049
  else {
1050
+ $html .= '<div class="single-settings dscene">';
1051
+ $html .= '<span>Set as default: </span>';
1052
  $html .= '<select class="dscen" name="dscene">';
1053
  $html .= '<option value="on"> Yes</option>';
1054
  $html .= '<option value="off" selected> No</option>';
1058
  //==Set Default Scene end==//
1059
 
1060
  $html .= '<div class=scene-setting>';
1061
+ $html .= '<label for="scene-id">Scene ID : </label>';
1062
+ $html .= '<input type="text" name="scene-id" value="'.$scene_id.'" />';
1063
  $html .= '</div>';
1064
 
1065
  $html .= '<div class=scene-setting>';
1066
+ $html .= '<label for="scene-type">Scene Type : </label>';
1067
  $html .= '<input type="text" name="scene-type" value="equirectangular" disabled/>';
1068
  $html .= '</div>';
1069
 
1070
  $html .= '<div class=scene-setting>';
1071
+ $html .= '<label for="scene-upload">Scene Upload: </label>';
1072
  $html .= '<div class="form-group">';
1073
+ $html .= '<img name ="scene-photo" src="'.$scene_photo.'"> <br/>';
1074
  $html .= '<input type="button" class="scene-upload" data-info="" value="Upload"/>';
1075
  $html .= '<input type="hidden" name="scene-attachment-url" class="scene-attachment-url" value="'.$scene_photo.'">';
1076
  $html .= '</div>';
1077
  $html .= '</div>';
1078
+ $html .= '</div>';
1079
+
1080
  if (!empty($pano_hotspots)) {
1081
  $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
1082
+
1083
  $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
1084
  $html .= '<ul>';
1085
  $j = 1;
1086
  foreach ($pano_hotspots as $pano_hotspot) {
1087
  if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
1088
+ $html .= '<li class="active"><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'">Hotspot '.$j.'</span></li>';
1089
  }
1090
  else {
1091
+ $html .= '<li><span data-index="'.$j.'" data-href="#scene-'.$s.'-hotspot-'.$j.'">Hotspot '.$j.'</span></li>';
1092
  }
1093
  $j++;
1094
  }
1095
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
1096
  $html .= '</ul>';
1097
  $html .= '</nav>';
1098
+
1099
  $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content">';
1100
+
1101
  $h = 1;
1102
  foreach ($pano_hotspots as $pano_hotspot) {
1103
  $hotspot_title = '';
1117
  $hotspot_target_scene = '';
1118
  $hotspot_target_scene = $pano_hotspot['hotspot-scene'];
1119
  $hotspot_custom_class = '';
1120
+ $hotspot_custom_class = $pano_hotspot['hotspot-customclass'];
 
 
 
1121
  if ($pano_hotspot['hotspot-title'] == $pano_hotspots[0]['hotspot-title']) {
1122
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1123
+
1124
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">'.$h.'</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
1125
+
1126
  $html .= '<div class="wrapper">';
1127
  $html .= '<div class="hotspot-setting">';
1128
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
1129
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1130
  $html .= '</div>';
1131
 
1132
  $html .= '<div class="hotspot-setting">';
1133
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
1134
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1135
  $html .= '</div>';
1136
 
1137
  $html .= '<div class="hotspot-setting">';
1138
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
1139
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1140
  $html .= '</div>';
1141
 
1142
+ $html .= '<div class="hotspot-setting">';
1143
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
1144
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1145
+ $html .= '</div>';
 
1146
  $html .= '</div>';
1147
+
1148
  //=Hotspot type=//
1149
  if ($hotspot_type == "info") {
1150
+
1151
  $html .= '<div class="hotspot-type hotspot-setting">';
1152
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
1153
  $html .= '<select name="hotspot-type">';
1154
  $html .= '<option value="info" selected> Info</option>';
1155
  $html .= '<option value="scene"> Scene</option>';
1156
  $html .= '</select>';
1157
 
1158
  $html .= '<div class="hotspot-url">';
1159
+ $html .= '<label for="hotspot-url"> URL: </label>';
1160
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1161
  $html .= '</div>';
1162
 
1163
  $html .= '<div class="hotspot-content">';
1164
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1165
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1166
  $html .= '</div>';
1167
 
1168
  $html .= '<div class="hotspot-hover">';
1169
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1170
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1171
  $html .= '</div>';
1172
 
1173
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1174
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1175
+ $html .= '<input type="text" name="hotspot-scene"/>';
 
 
 
 
 
 
 
1176
  $html .= '</div>';
1177
 
1178
  $html .= '</div>';
1179
+
1180
  }
1181
  else {
1182
+
1183
  $html .= '<div class="hotspot-type hotspot-setting">';
1184
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
1185
+ $html .= '<select name="hotspot-type">';
1186
  $html .= '<option value="info"> Info</option>';
1187
  $html .= '<option value="scene" selected> Scene</option>';
1188
  $html .= '</select>';
1189
 
1190
  $html .= '<div class="hotspot-url" style="display:none;">';
1191
+ $html .= '<label for="hotspot-url"> URL: </label>';
1192
  $html .= '<input type="url" name="hotspot-url" />';
1193
  $html .= '</div>';
1194
 
1195
+ $html .= '<div class="hotspot-content" style="display:none;>';
1196
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1197
  $html .= '<textarea name="hotspot-content"></textarea>';
1198
  $html .= '</div>';
1199
 
1200
  $html .= '<div class="hotspot-hover">';
1201
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1202
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1203
  $html .= '</div>';
1204
 
 
 
 
 
 
 
 
1205
  $html .= '<div class="hotspot-scene">';
1206
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1207
+ $html .= '<input type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" />';
1208
  $html .= '</div>';
1209
 
1210
  $html .= '</div>';
1211
+
1212
  }
1213
  //=Hotspot type End=//
1214
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
1215
+ $html .= '</div>';
1216
  }
1217
  else {
1218
  $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab clearfix" id="scene-'.$s.'-hotspot-'.$h.'">';
1219
+
1220
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">'.$h.'</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
1221
+
1222
  $html .= '<div class="wrapper">';
1223
  $html .= '<div class="hotspot-setting">';
1224
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
1225
  $html .= '<input type="text" id="hotspot-title" name="hotspot-title" value="'.$hotspot_title.'" />';
1226
  $html .= '</div>';
1227
 
1228
  $html .= '<div class="hotspot-setting">';
1229
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
1230
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch" value="'.$hotspot_pitch.'" />';
1231
  $html .= '</div>';
1232
 
1233
  $html .= '<div class="hotspot-setting">';
1234
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
1235
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw" value="'.$hotspot_yaw.'" />';
1236
  $html .= '</div>';
1237
 
1238
+ $html .= '<div class="hotspot-setting">';
1239
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
1240
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass" value="'.$hotspot_custom_class.'"/>';
1241
+ $html .= '</div>';
 
1242
  $html .= '</div>';
1243
+
1244
  //=Hotspot type=//
1245
  if ($hotspot_type == "info") {
1246
+
1247
  $html .= '<div class="hotspot-type hotspot-setting">';
1248
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
1249
  $html .= '<select name="hotspot-type">';
1250
  $html .= '<option value="info" selected> Info</option>';
1251
  $html .= '<option value="scene"> Scene</option>';
1252
  $html .= '</select>';
1253
 
1254
  $html .= '<div class="hotspot-url">';
1255
+ $html .= '<label for="hotspot-url"> URL: </label>';
1256
  $html .= '<input type="url" name="hotspot-url" value="'.$hotspot_url.'" />';
1257
  $html .= '</div>';
1258
 
1259
  $html .= '<div class="hotspot-content">';
1260
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1261
  $html .= '<textarea name="hotspot-content">'.$hotspot_content.'</textarea>';
1262
  $html .= '</div>';
1263
 
1264
  $html .= '<div class="hotspot-hover">';
1265
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1266
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1267
  $html .= '</div>';
1268
 
1269
  $html .= '<div class="hotspot-scene" style="display:none;" >';
1270
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1271
+ $html .= '<input type="text" name="hotspot-scene"/>';
 
 
 
 
 
 
 
1272
  $html .= '</div>';
1273
 
1274
  $html .= '</div>';
1275
+
1276
  }
1277
  else {
1278
+
1279
  $html .= '<div class="hotspot-type hotspot-setting">';
1280
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
1281
+ $html .= '<select name="hotspot-type">';
1282
  $html .= '<option value="info"> Info</option>';
1283
  $html .= '<option value="scene" selected> Scene</option>';
1284
  $html .= '</select>';
1285
 
1286
  $html .= '<div class="hotspot-url" style="display:none;">';
1287
+ $html .= '<label for="hotspot-url"> URL: </label>';
1288
  $html .= '<input type="url" name="hotspot-url" />';
1289
  $html .= '</div>';
1290
 
1291
+ $html .= '<div class="hotspot-content" style="display:none;>';
1292
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1293
  $html .= '<textarea name="hotspot-content"></textarea>';
1294
  $html .= '</div>';
1295
 
1296
  $html .= '<div class="hotspot-hover">';
1297
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1298
  $html .= '<textarea name="hotspot-hover">'.$hotspot_hover.'</textarea>';
1299
  $html .= '</div>';
1300
 
 
 
 
 
 
 
 
1301
  $html .= '<div class="hotspot-scene">';
1302
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1303
+ $html .= '<input type="text" name="hotspot-scene" value="'.$hotspot_target_scene.'" />';
1304
  $html .= '</div>';
1305
 
1306
  $html .= '</div>';
1307
+
1308
  }
1309
  //=Hotspot type End=//
1310
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
1311
  $html .= '</div>';
1312
  }
1313
  $h++;
1314
  }
1315
  $html .= '</div>';
1316
+ $html .= '</div>';
1317
  }
1318
  else {
1319
+ $html .= '<div class="hotspot-setup rex-pano-sub-tabs" data-limit="'.$data_limit.'">';
1320
+
1321
+ $html .= '<nav class="rex-pano-tab-nav rex-pano-nav-menu hotspot-nav">';
1322
+ $html .= '<ul>';
1323
+ $html .= '<li class="active"><span data-index="1" data-href="#scene-'.$s.'-hotspot-1">Hotspot 1</span></li>';
1324
+ $html .= '<li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i> Add</span></li>';
1325
+ $html .= '</ul>';
1326
+ $html .= '</nav>';
1327
+
1328
+ $html .= '<div data-repeater-list="hotspot-list" class="rex-pano-tab-content>';
1329
+
1330
+ $html .= '<div data-repeater-item class="single-hotspot rex-pano-tab active clearfix" id="scene-'.$s.'-hotspot-1">';
1331
+
1332
+ $html .= '<h6 class="title"><i class="fa fa-cog"></i> Hotspot <span class="hotspot-num">1</span> Setting for <span>Scene <span class="scene-num">'.$s.'</span></span> </h6>';
1333
+
1334
+ $html .= '<div class="wrapper">';
1335
+ $html .= '<div class="hotspot-setting">';
1336
+ $html .= '<label for="hotspot-title">Hotspot ID : </label>';
1337
+ $html .= '<input type="text" id="hotspot-title" name="hotspot-title"/>';
1338
+ $html .= '</div>';
1339
+
1340
+ $html .= '<div class="hotspot-setting">';
1341
+ $html .= '<label for="hotspot-pitch"> Pitch: </label>';
1342
+ $html .= '<input type="text" id="hotspot-pitch" name="hotspot-pitch"/>';
1343
+ $html .= '</div>';
1344
+
1345
+ $html .= '<div class="hotspot-setting">';
1346
+ $html .= '<label for="hotspot-yaw"> Yaw: </label>';
1347
+ $html .= '<input type="text" id="hotspot-yaw" name="hotspot-yaw"/>';
1348
+ $html .= '</div>';
1349
+
1350
+ $html .= '<div class="hotspot-setting">';
1351
+ $html .= '<label for="hotspot-customclass">Hotspot custom class: </label>';
1352
+ $html .= '<input type="text" id="hotspot-customclass" name="hotspot-customclass"/>';
1353
+ $html .= '</div>';
1354
+ $html .= '</div>';
1355
+
1356
+ $html .= '<div class="hotspot-type hotspot-setting">';
1357
+ $html .= '<label for="hotspot-type">Hotspot-Type: </label>';
1358
+ $html .= '<select name="hotspot-type">';
1359
+ $html .= '<option value="info" selected> Info</option>';
1360
+ $html .= '<option value="scene"> Scene</option>';
1361
+ $html .= '</select>';
1362
+
1363
+ $html .= '<div class="hotspot-url">';
1364
+ $html .= '<label for="hotspot-url"> URL: </label>';
1365
+ $html .= '<input type="url" name="hotspot-url" />';
1366
+ $html .= '</div>';
1367
+
1368
+ $html .= '<div class="hotspot-content">';
1369
+ $html .= '<label for="hotspot-content"> On click Content: </label>';
1370
+ $html .= '<textarea name="hotspot-content"></textarea>';
1371
+ $html .= '</div>';
1372
+
1373
+ $html .= '<div class="hotspot-hover">';
1374
+ $html .= '<label for="hotspot-hover"> On hover Content: </label>';
1375
+ $html .= '<textarea name="hotspot-hover"></textarea>';
1376
+ $html .= '</div>';
1377
+
1378
+ $html .= '<div class="hotspot-scene" style="display:none;" >';
1379
+ $html .= '<label for="hotspot-scene"> Target Scene ID: </label>';
1380
+ $html .= '<input type="text" name="hotspot-scene"/>';
1381
+ $html .= '</div>';
1382
+
1383
+ $html .= '</div>';
1384
+ //=Hotspot type End=//
1385
+ $html .= '<button data-repeater-delete type="button" title="Delete Hotspot" class="delete-hotspot"><i class="fa fa-trash-o"></i></button>';
1386
+ $html .= '</div>';
1387
+
1388
+ $html .= '</div>';
1389
+ //$html .= '<input data-repeater-create type="button" value="Add Hotspot"/>';
1390
+ $html .= '</div>';
 
 
 
 
1391
  }
1392
+ $html .= '<button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="fa fa-trash-o"></i></button>';
1393
  $html .= '</div>';
1394
  }
1395
  $s++;
1396
  }
1397
  $html .= '</div>';
1398
+
1399
  $html .= '</div>';
1400
  }
1401
+
1402
  $html .= '<div class="preview-btn-wrapper">';
1403
  $html .= '<div class="preview-btn-area clearfix">';
1404
+ $html .= '<div id="error_occured"></div>';
1405
+ $html .= '<button id="panolenspreview">Preview</button>';
1406
  $html .= '</div>';
1407
  $html .= '</div>';
1408
  $html .='</div>';
1409
  //---end scenes tab----
1410
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1411
  $html .='</div>';
1412
  //---end rex-pano-tab-content----
1413
+
1414
  $html .='</div>';
1415
  //---end rex-pano-tabs---
1416
+ $html .= '</div>';
1417
+ echo $html;
 
1418
  }
1419
 
1420
  }
admin/class-wpvr-ajax.php CHANGED
@@ -30,14 +30,6 @@ class Wpvr_Ajax {
30
  $control = false;
31
  }
32
 
33
- $compass = sanitize_text_field($_POST['compass']);
34
- if ($compass == 'on') {
35
- $compass = true;
36
- }
37
- else {
38
- $compass = false;
39
- }
40
-
41
  $autoload = sanitize_text_field($_POST['autoload']);
42
  if ($autoload == 'on') {
43
  $autoload = true;
@@ -48,50 +40,21 @@ class Wpvr_Ajax {
48
 
49
  $default_scene = '';
50
  $default_scene = sanitize_text_field($_POST['defaultscene']);
51
-
52
- $preview = '';
53
- $preview = esc_url($_POST['preview']);
54
-
55
- $rotation = '';
56
- $rotation = sanitize_text_field($_POST['rotation']);
57
-
58
- $autorotation = '';
59
- $autorotation = sanitize_text_field($_POST['autorotation']);
60
- $autorotationinactivedelay = '';
61
- $autorotationinactivedelay = sanitize_text_field($_POST['autorotationinactivedelay']);
62
- $autorotationstopdelay = '';
63
- $autorotationstopdelay = sanitize_text_field($_POST['autorotationstopdelay']);
64
-
65
- if (!empty($autorotationinactivedelay) && !empty($autorotationstopdelay)) {
66
- wp_send_json_error('<p><span>Warning:</span> You can not apply both autorotation pause or stop delay. Please choose either autorotation inactive delay or autorotation stop delay</p>');
67
- die();
68
- }
69
 
70
  $scene_fade_duration = '';
71
  $scene_fade_duration = sanitize_text_field($_POST['scenefadeduration']);
72
 
73
  $panodata = $_POST['panodata'];
74
- $panolist = stripslashes($panodata);
75
- $panodata = (array)json_decode($panolist);
76
- $panolist = array();
77
- if(is_array($panodata["scene-list"])) {
78
- foreach ($panodata["scene-list"] as $scenes_data) {
79
- $temp_array = array();
80
- $temp_array = (array)$scenes_data;
81
- if ($temp_array['hotspot-list']) {
82
- $_hotspot_array = array();
83
- foreach ($temp_array['hotspot-list'] as $temp_hotspot) {
84
- $temp_hotspot = (array)$temp_hotspot;
85
- $_hotspot_array[] = $temp_hotspot;
86
- }
87
- }
88
- $temp_array['hotspot-list'] = $_hotspot_array;
89
- $panolist['scene-list'][] = $temp_array;
90
- }
91
- }
92
- $panodata = $panolist;
93
 
94
  //===Error Control and Validation===//
 
 
 
 
95
 
96
  if ($panodata["scene-list"] != "") {
97
  foreach ($panodata["scene-list"] as $scenes_val) {
@@ -100,148 +63,82 @@ class Wpvr_Ajax {
100
  if (!empty($scene_id_validate)) {
101
  $scene_id_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$scene_id_validate);
102
  if ($scene_id_validated != $scene_id_validate) {
103
- wp_send_json_error('<p><span>Warning:</span> The scene id can only contain letters and numbers where scene id: '.$scene_id_validate.'</p>');
104
- die();
105
- }
106
- if (empty($scenes_val["scene-attachment-url"])) {
107
- // var_dump($scenes_val["scene-attachment-url"]);
108
- wp_send_json_error('<p><span>Warning:</span> A scene image is required for every scene where scene id: '.$scene_id_validate.'</p>');
109
  die();
110
  }
 
111
 
112
- if (!empty($scenes_val["scene-pitch"])) {
113
- $validate_scene_pitch = $scenes_val["scene-pitch"];
114
- $validated_scene_pitch = preg_replace('/[^0-9.-]/','',$validate_scene_pitch);
115
- if ($validated_scene_pitch != $validate_scene_pitch) {
116
- wp_send_json_error('<p><span>Warning:</span> Default pitch value can only contain float numbers where scene id: '.$scene_id_validate.'</p>');
117
- die();
118
- }
119
- }
120
 
121
- if (!empty($scenes_val["scene-yaw"])) {
122
- $validate_scene_yaw = $scenes_val["scene-yaw"];
123
- $validated_scene_yaw = preg_replace('/[^0-9.-]/','',$validate_scene_yaw);
124
- if ($validated_scene_yaw != $validate_scene_yaw) {
125
- wp_send_json_error('<p><span>Warning:</span> Default yaw value can only contain float numbers where scene id: '.$scene_id_validate.'</p>');
126
- die();
127
- }
128
- }
129
 
130
- if (!empty($scenes_val["scene-zoom"])) {
131
- $validate_default_zoom = $scenes_val["scene-zoom"];
132
- $validated_default_zoom = preg_replace('/[^0-9-]/','',$validate_default_zoom);
133
- if ($validated_default_zoom != $validate_default_zoom) {
134
- wp_send_json_error('<p><span>Warning:</span> Default zoom value can only contain number in degree from 50 to 120 where scene id: '.$scene_id_validate.'</p>');
135
- die();
136
- }
137
- $default_zoom_value = (int)$scenes_val["scene-zoom"];
138
- if ($default_zoom_value > 120 || $default_zoom_value < 50) {
139
- wp_send_json_error('<p><span>Warning:</span> Default zoom value can only contain number in degree from 50 to 120 where scene id: '.$scene_id_validate.'</p>');
140
- die();
141
- }
142
- }
143
 
144
- if (!empty($scenes_val["scene-maxzoom"])) {
145
- $validate_max_zoom = $scenes_val["scene-maxzoom"];
146
- $validated_max_zoom = preg_replace('/[^0-9-]/','',$validate_max_zoom);
147
- if ($validated_max_zoom != $validate_max_zoom) {
148
- wp_send_json_error('<p><span>Warning:</span> Max zoom out value can only contain number in degree where scene id: '.$scene_id_validate.'</p>');
149
- die();
150
  }
151
- $max_zoom_value = (int)$scenes_val["scene-maxzoom"];
152
- if ($max_zoom_value > 120 ) {
153
- wp_send_json_error('<p><span>Warning:</span> Max zoom out value can only contain number in degree below 120 where scene id: '.$scene_id_validate.'</p>');
154
- die();
 
 
 
 
155
  }
156
- }
157
 
158
- if (!empty($scenes_val["scene-minzoom"])) {
159
- $validate_min_zoom = $scenes_val["scene-minzoom"];
160
- $validated_min_zoom = preg_replace('/[^0-9-]/','',$validate_min_zoom);
161
- if ($validated_min_zoom != $validate_min_zoom) {
162
- wp_send_json_error('<p><span>Warning:</span> Max zoom in value can only contain number in degree where scene id: '.$scene_id_validate.'</p>');
163
- die();
 
164
  }
165
- $min_zoom_value = (int)$scenes_val["scene-minzoom"];
166
- if ($min_zoom_value < 50 ) {
167
- wp_send_json_error('<p><span>Warning:</span> Max zoom in value can only contain number in degree above 50 where scene id: '.$scene_id_validate.'</p>');
168
- die();
 
 
 
 
169
  }
170
- }
171
-
172
- if ($scenes_val["hotspot-list"] != "") {
173
- foreach ($scenes_val["hotspot-list"] as $hotspot_val) {
174
-
175
- $hotspot_title_validate = $hotspot_val["hotspot-title"];
176
-
177
- if (!empty($hotspot_title_validate)) {
178
- $hotspot_title_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$hotspot_title_validate);
179
- if ($hotspot_title_validated != $hotspot_title_validate) {
180
- wp_send_json_error('<p><span>Warning:</span> Hotspot title can only contain letters and numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
181
- die();
182
- }
183
-
184
- $hotspot_pitch_validate = $hotspot_val["hotspot-pitch"];
185
- if (!empty($hotspot_pitch_validate)) {
186
- $hotspot_pitch_validated = preg_replace('/[^0-9.-]/','',$hotspot_pitch_validate);
187
- if ($hotspot_pitch_validated != $hotspot_pitch_validate) {
188
- wp_send_json_error('<p><span>Warning:</span> Hotspot pitch can only contain float numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
189
- die();
190
- }
191
- }
192
-
193
- $hotspot_yaw_validate = $hotspot_val["hotspot-yaw"];
194
- if (!empty($hotspot_yaw_validate)) {
195
- $hotspot_yaw_validated = preg_replace('/[^0-9.-]/','',$hotspot_yaw_validate);
196
- if ($hotspot_yaw_validated != $hotspot_yaw_validate) {
197
- wp_send_json_error('<p><span>Warning:</span> Hotspot yaw can only contain float numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
198
- die();
199
- }
200
- }
201
-
202
- if(is_plugin_active( 'wpvr-pro/wpvr-pro.php' )){
203
- $status = get_option( 'wpvr_edd_license_status' );
204
- if( $status !== false && $status == 'valid' ) {
205
- if ($hotspot_val["hotspot-customclass-pro"] != 'none' && !empty($hotspot_val["hotspot-customclass"])) {
206
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Custom icon class and custom icon both where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
207
- die();
208
- }
209
- }
210
- }
211
- $hotspot_type_validate = $hotspot_val["hotspot-type"];
212
- $hotspot_url_validate = $hotspot_val["hotspot-url"];
213
- if (!empty($hotspot_url_validate)) {
214
- $hotspot_url_validated = esc_url($hotspot_url_validate);
215
- if ($hotspot_url_validated != $hotspot_url_validate) {
216
- wp_send_json_error('<p><span>Warning:</span> Hotspot Url is invalid where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
217
- die();
218
- }
219
- }
220
- $hotspot_content_validate = $hotspot_val["hotspot-content"];
221
 
222
- $hotspot_scene_validate = $hotspot_val["hotspot-scene"];
223
 
224
- if ($hotspot_type_validate == "info") {
225
- if (!empty($hotspot_scene_validate)) {
226
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Target Scene ID on info type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
227
- die();
228
- }
229
- if (!empty($hotspot_url_validate) && !empty($hotspot_content_validate)) {
230
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Url and On click content both on same hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
231
- die();
232
- }
233
- }
234
 
235
- if ($hotspot_type_validate == "scene") {
236
- if (empty($hotspot_scene_validate)) {
237
- wp_send_json_error('<p><span>Warning:</span> Target scene id is required for scene type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
238
- die();
239
- }
240
- if (!empty($hotspot_url_validate) || !empty($hotspot_content_validate)) {
241
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Url or On click content on scene type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
242
- die();
243
- }
244
- }
245
  }
246
  }
247
  }
@@ -249,302 +146,58 @@ class Wpvr_Ajax {
249
  }
250
  }
251
  //===Error Control and Validation===//
252
- foreach ($panodata["scene-list"] as $panoscenes) {
253
- if (empty($panoscenes['scene-id']) && !empty($panoscenes['scene-attachment-url'])) {
254
- wp_send_json_error('<p><span>Warning:</span> You have added a scene image but empty scene id. Please add scene id and update </p>');
255
- die();
256
- }
257
- }
258
-
259
- $allsceneids = array();
260
-
261
- foreach ($panodata["scene-list"] as $panoscenes) {
262
- if (!empty($panoscenes['scene-id'])) {
263
- array_push($allsceneids, $panoscenes['scene-id']);
264
- }
265
- }
266
 
267
  foreach ($panodata["scene-list"] as $panoscenes) {
268
-
269
  if ($panoscenes['dscene'] == 'on') {
270
  $default_scene = $panoscenes['scene-id'];
271
  }
272
  }
273
  if (empty($default_scene)) {
274
- if ($allsceneids) {
275
- $default_scene = $allsceneids[0];
276
- }
277
- else {
278
- wp_send_json_error('<p><span>Warning:</span> No default scene selected and no scene id found to set as default. You need at least one scene to publish a tour </p>');
279
- die();
280
- }
281
- }
282
-
283
- $allsceneids_count = array_count_values($allsceneids);
284
- foreach ($allsceneids_count as $key => $value) {
285
- if ($value > 1) {
286
- wp_send_json_error('<p><span>Warning:</span> You can not use same scene id on multiple scene </p>');
287
- die();
288
- }
289
- }
290
-
291
- foreach ($panodata["scene-list"] as $panoscenes) {
292
- if (!empty($panoscenes['scene-id'])) {
293
- $allhotspot = array();
294
- foreach ($panoscenes["hotspot-list"] as $hotspot_val) {
295
- if (!empty($hotspot_val["hotspot-title"])) {
296
- array_push($allhotspot, $hotspot_val["hotspot-title"]);
297
- }
298
- }
299
- $allhotspotcount = array_count_values($allhotspot);
300
- foreach ($allhotspotcount as $key => $value) {
301
- if ($value > 1) {
302
- wp_send_json_error('<p><span>Warning:</span> You can not use same hotspot id on multiple hotspot for same scene </p>');
303
- die();
304
- }
305
- }
306
- }
307
  }
308
 
309
  $default_data = array();
310
- $default_data = array("firstScene"=>$default_scene,"sceneFadeDuration"=>$scene_fade_duration);
311
  $scene_data = array();
312
 
313
  foreach ($panodata["scene-list"] as $panoscenes) {
314
 
315
- if (!empty($panoscenes['scene-id'])) {
316
-
317
- $scene_ititle = '';
318
- $scene_ititle = sanitize_text_field($panoscenes["scene-ititle"]);
319
-
320
- $scene_author = '';
321
- $scene_author = sanitize_text_field($panoscenes["scene-author"]);
322
-
323
- $default_scene_pitch = null;
324
- $default_scene_pitch = (float)$panoscenes["scene-pitch"];
325
-
326
- $default_scene_yaw = null;
327
- $default_scene_yaw = (float)$panoscenes["scene-yaw"];
328
-
329
- $scene_max_pitch = '';
330
- $scene_max_pitch = (float)$panoscenes["scene-maxpitch"];
331
-
332
- $scene_min_pitch = '';
333
- $scene_min_pitch = (float)$panoscenes["scene-minpitch"];
334
-
335
- $scene_max_yaw = '';
336
- $scene_max_yaw = (float)$panoscenes["scene-maxyaw"];
337
-
338
- $scene_min_yaw = '';
339
- $scene_min_yaw = (float)$panoscenes["scene-minyaw"];
340
-
341
- $default_zoom = 100;
342
- $default_zoom = $panoscenes["scene-zoom"];
343
- if (!empty($default_zoom)) {
344
- $default_zoom = (int)$panoscenes["scene-zoom"];
345
- }
346
- else {
347
- $default_zoom = 100;
348
- }
349
-
350
- $max_zoom = 120;
351
- $max_zoom = $panoscenes["scene-maxzoom"];
352
- if (!empty($max_zoom)) {
353
- $max_zoom = (int)$panoscenes["scene-maxzoom"];
354
- }
355
- else {
356
- $max_zoom = 120;
357
- }
358
-
359
- $min_zoom = 50;
360
- $min_zoom = $panoscenes["scene-minzoom"];
361
- if (!empty($min_zoom)) {
362
- $min_zoom = (int)$panoscenes["scene-minzoom"];
363
- }
364
- else {
365
- $min_zoom = 50;
366
- }
367
-
368
- $hotspot_datas = $panoscenes["hotspot-list"];
369
- $hotspots = array();
370
- foreach ($hotspot_datas as $hotspot_data) {
371
-
372
- if (!empty($hotspot_data["hotspot-title"])) {
373
- $hotspot_info = array(
374
- "text"=>$hotspot_data["hotspot-title"],
375
- "pitch"=>$hotspot_data["hotspot-pitch"],
376
- "yaw"=>$hotspot_data["hotspot-yaw"],
377
- "type"=>$hotspot_data["hotspot-type"],
378
- "URL"=>$hotspot_data["hotspot-url"],
379
- "clickHandlerArgs"=>$hotspot_data["hotspot-content"],
380
- "createTooltipArgs"=>$hotspot_data["hotspot-hover"],
381
- "sceneId"=>$hotspot_data["hotspot-scene"],
382
- "targetPitch"=>(float)$hotspot_data["hotspot-scene-pitch"],
383
- "targetYaw"=>(float)$hotspot_data["hotspot-scene-yaw"]);
384
- array_push($hotspots, $hotspot_info);
385
- if (empty($hotspot_data["hotspot-scene"])) {
386
- unset($hotspot_info['targetPitch']);
387
- unset($hotspot_info['targetYaw']);
388
- }
389
- }
390
- }
391
-
392
- $scene_info = array();
393
- $scene_info = array("type"=>$panoscenes["scene-type"],"panorama"=>$panoscenes["scene-attachment-url"],"pitch"=>$default_scene_pitch,"maxPitch"=>$scene_max_pitch,"minPitch"=>$scene_min_pitch,"maxYaw"=>$scene_max_yaw,"minYaw"=>$scene_min_yaw,"yaw"=>$default_scene_yaw,"hfov"=>$default_zoom,"maxHfov"=>$max_zoom,"minHfov"=>$min_zoom,"title"=>$scene_ititle,"author"=>$scene_author,"hotSpots"=>$hotspots);
394
-
395
- if ($panoscenes["ptyscene"] == "off") {
396
- unset($scene_info['pitch']);
397
- unset($scene_info['yaw']);
398
- }
399
-
400
- if (empty($panoscenes["scene-ititle"])) {
401
- unset($scene_info['title']);
402
- }
403
- if (empty($panoscenes["scene-author"])) {
404
- unset($scene_info['author']);
405
- }
406
-
407
- if ($panoscenes["cvgscene"] == "off") {
408
- unset($scene_info['maxPitch']);
409
- unset($scene_info['minPitch']);
410
- }
411
- if (empty($panoscenes["scene-maxpitch"])) {
412
- unset($scene_info['maxPitch']);
413
- }
414
-
415
- if (empty($panoscenes["scene-minpitch"])) {
416
- unset($scene_info['minPitch']);
417
- }
418
-
419
- if ($panoscenes["chgscene"] == "off") {
420
- unset($scene_info['maxYaw']);
421
- unset($scene_info['minYaw']);
422
-
423
- }
424
- if (empty($panoscenes["scene-maxyaw"])) {
425
- unset($scene_info['maxYaw']);
426
- }
427
-
428
- if (empty($panoscenes["scene-minyaw"])) {
429
- unset($scene_info['minYaw']);
430
- }
431
-
432
- if ($panoscenes["czscene"] == "off") {
433
- unset($scene_info['hfov']);
434
- unset($scene_info['maxHfov']);
435
- unset($scene_info['minHfov']);
436
- }
437
-
438
- $scene_array = array();
439
- $scene_array = array(
440
- $panoscenes["scene-id"]=>$scene_info
441
- );
442
- $scene_data[$panoscenes["scene-id"]] = $scene_info;
443
- }
444
 
 
 
 
 
 
 
 
445
  }
446
 
447
  $pano_id_array = array();
448
- $pano_id_array = array("panoid"=>$panoid);
449
  $pano_response = array();
450
- $pano_response = array("autoLoad"=>$autoload,"showControls"=>$control,"compass"=>$compass,"preview"=>$preview,"autoRotate"=>$autorotation,"autoRotateInactivityDelay"=>$autorotationinactivedelay,"autoRotateStopDelay"=>$autorotationstopdelay,"default"=>$default_data,"scenes"=>$scene_data);
451
-
452
- if ($rotation == 'off') {
453
- unset($pano_response['autoRotate']);
454
- unset($pano_response['autoRotateInactivityDelay']);
455
- unset($pano_response['autoRotateStopDelay']);
456
- }
457
- if (empty($autorotation)) {
458
- unset($pano_response['autoRotate']);
459
- unset($pano_response['autoRotateInactivityDelay']);
460
- unset($pano_response['autoRotateStopDelay']);
461
- }
462
- if (empty($autorotationinactivedelay)) {
463
- unset($pano_response['autoRotateInactivityDelay']);
464
- }
465
- if (empty($autorotationstopdelay)) {
466
- unset($pano_response['autoRotateStopDelay']);
467
- }
468
  $response = array();
469
  $response = array($pano_id_array,$pano_response);
470
 
471
  wp_send_json_success( $response );
472
  }
473
 
474
- /**
475
- * Video Preview show ajax function
476
- */
477
- function wpvrvideo_preview() {
478
- $panoid ='';
479
- $postid = sanitize_text_field($_POST['postid']);
480
- $panoid = 'pano'.$postid;
481
- $randid = rand(1000, 1000000);
482
- $vidid = 'vid'.$randid;
483
- $videourl = sanitize_url($_POST['videourl']);
484
-
485
- $vidtype = '';
486
- if (strpos($videourl, 'youtube') > 0) {
487
- $vidtype = 'youtube';
488
- $explodeid = '';
489
- $explodeid = explode("=",$videourl);
490
- $foundid = '';
491
- $foundid = $explodeid[1];
492
- $html = '';
493
- $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/'.$foundid.'" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
494
-
495
- } elseif (strpos($videourl, 'youtu.be') > 0) {
496
- $vidtype = 'youtube';
497
- $explodeid = '';
498
- $explodeid = explode("/",$videourl);
499
- $foundid = '';
500
- $foundid = $explodeid[3];
501
- $html = '';
502
- $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/'.$foundid.'" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
503
-
504
- }
505
- elseif (strpos($videourl, 'vimeo') > 0) {
506
- $vidtype = 'vimeo';
507
- $explodeid = '';
508
- $explodeid = explode("/",$videourl);
509
- $foundid = '';
510
- $foundid = $explodeid[3];
511
- $html = '';
512
- $html .= '<iframe src="https://player.vimeo.com/video/'.$foundid.'" width="600" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
513
-
514
- } else {
515
- $vidtype = 'selfhost';
516
- $vidautoplay = '';
517
- $vidautoplay = sanitize_text_field($_POST['vidautoplay']);
518
- if ($vidautoplay == 'on') {
519
- $vidautoplay = 'autoplay';
520
- }
521
- else {
522
- $vidautoplay = '';
523
- }
524
-
525
- $vidcontrol = '';
526
- $vidcontrol = sanitize_text_field($_POST['vidcontrol']);
527
- if ($vidcontrol == 'on') {
528
- $vidcontrol = 'controls';
529
- }
530
- else {
531
- $vidcontrol = '';
532
- }
533
-
534
- $html = '';
535
- $html .= '<video id="'.$vidid.'" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="none" style="width:100%;height:400px;" poster="" >';
536
- $html .= '<source src="'.$videourl.'" type="video/mp4"/>';
537
- $html .= '<p class="vjs-no-js">';
538
- $html .= 'To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com html5-video-support/" target="_blank">supports HTML5 video</a>';
539
- $html .= '</p>';
540
- $html .= '</video>';
541
- }
542
-
543
- $response = array();
544
- $response = array(__( "panoid" )=>$panoid,__( "panodata" )=>$html,__( "vidid" )=>$vidid,__( "vidtype" )=>$vidtype);
545
- wp_send_json_success( $response );
546
- }
547
-
548
  function wpvr_save_data() {
549
  $panoid ='';
550
  $postid = sanitize_text_field($_POST['postid']);
@@ -554,90 +207,6 @@ class Wpvr_Ajax {
554
  }
555
  $panoid = 'pano'.$postid;
556
 
557
- $streetview = $_POST['streetview'];
558
- if ($streetview == 'on') {
559
- $streetviewurl = sanitize_url($_POST['streetviewurl']);
560
- if ($streetviewurl) {
561
- $html .= '<iframe src="'.$streetviewurl.'" width="600" height="400" frameborder="0" style="border:0;" allowfullscreen=""></iframe>';
562
- }
563
- $streetviewarray = array();
564
- $streetviewarray = array(__( "panoid" )=>$panoid,__( "streetviewdata" )=>$html,__( "streetviewurl" )=>$streetviewurl,__( "streetview" )=>$streetview);
565
- update_post_meta( $postid, 'panodata', $streetviewarray );
566
- die();
567
- }
568
-
569
- $pnovideo = $_POST['panovideo'];
570
- if ($pnovideo == "on") {
571
-
572
-
573
- $vidid = 'vid'.$postid;
574
- $videourl = sanitize_url($_POST['videourl']);
575
- $vidtype = '';
576
- if (strpos($videourl, 'youtube') > 0) {
577
- $vidtype = 'youtube';
578
- $explodeid = '';
579
- $explodeid = explode("=",$videourl);
580
- $foundid = '';
581
- $foundid = $explodeid[1];
582
- $html = '';
583
- $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/'.$foundid.'" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
584
-
585
- } elseif (strpos($videourl, 'youtu.be') > 0) {
586
- $vidtype = 'youtube';
587
- $explodeid = '';
588
- $explodeid = explode("/",$videourl);
589
- $foundid = '';
590
- $foundid = $explodeid[3];
591
- $html = '';
592
- $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/'.$foundid.'" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
593
-
594
- }
595
-
596
- elseif (strpos($videourl, 'vimeo') > 0) {
597
- $vidtype = 'vimeo';
598
- $explodeid = '';
599
- $explodeid = explode("/",$videourl);
600
- $foundid = '';
601
- $foundid = $explodeid[3];
602
- $html = '';
603
- $html .= '<iframe src="https://player.vimeo.com/video/'.$foundid.'" width="600" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
604
-
605
- } else {
606
- $vidtype = 'selfhost';
607
- $vidautoplay = '';
608
- $vidautoplay = sanitize_text_field($_POST['vidautoplay']);
609
- if ($vidautoplay == 'on') {
610
- $vidautoplay = 'autoplay';
611
- }
612
- else {
613
- $vidautoplay = '';
614
- }
615
-
616
- $vidcontrol = '';
617
- $vidcontrol = sanitize_text_field($_POST['vidcontrol']);
618
- if ($vidcontrol == 'on') {
619
- $vidcontrol = 'controls';
620
- }
621
- else {
622
- $vidcontrol = '';
623
- }
624
-
625
- $html = '';
626
- $html .= '<video id="'.$vidid.'" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="none" style="width:100%;height:100%;" poster="" >';
627
- $html .= '<source src="'.$videourl.'" type="video/mp4"/>';
628
- $html .= '<p class="vjs-no-js">';
629
- $html .= 'To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com html5-video-support/" target="_blank">supports HTML5 video</a>';
630
- $html .= '</p>';
631
- $html .= '</video>';
632
- }
633
-
634
- $videoarray = array();
635
- $videoarray = array(__( "panoid" )=>$panoid,__( "panoviddata" )=>$html,__( "vidid" )=>$vidid,__( "vidurl" )=>$videourl,__( "vidautoplay" )=>$vidautoplay,__( "vidcontrol" )=>$vidcontrol,__( "vidtype" )=>$vidtype);
636
- update_post_meta( $postid, 'panodata', $videoarray );
637
- die();
638
- }
639
-
640
-
641
  $control = sanitize_text_field($_POST['control']);
642
  if ($control == 'on') {
643
  $control = true;
@@ -646,36 +215,6 @@ class Wpvr_Ajax {
646
  $control = false;
647
  }
648
 
649
- //===Custom Control===//
650
- $custom_control = $_POST['customcontrol'];
651
-
652
- //===Custom Control End===//
653
-
654
- $vrgallery = sanitize_text_field($_POST['vrgallery']);
655
- if ($vrgallery == 'on') {
656
- $vrgallery = true;
657
- }
658
- else {
659
- $vrgallery = false;
660
- }
661
-
662
- $gyro = sanitize_text_field($_POST['gyro']);
663
-
664
- if ($gyro == 'on') {
665
- $gyro = true;
666
- }
667
- else {
668
- $gyro = false;
669
- }
670
-
671
- $compass = sanitize_text_field($_POST['compass']);
672
- if ($compass == 'on') {
673
- $compass = true;
674
- }
675
- else {
676
- $compass = false;
677
- }
678
-
679
  $autoload = sanitize_text_field($_POST['autoload']);
680
  if ($autoload == 'on') {
681
  $autoload = true;
@@ -686,216 +225,111 @@ class Wpvr_Ajax {
686
 
687
  $default_scene = '';
688
 
689
- $preview = '';
690
- $preview = esc_url($_POST['preview']);
691
-
692
- $rotation = '';
693
- $rotation = sanitize_text_field($_POST['rotation']);
694
-
695
- $autorotation = '';
696
- $autorotation = sanitize_text_field($_POST['autorotation']);
697
- $autorotationinactivedelay = '';
698
- $autorotationinactivedelay = sanitize_text_field($_POST['autorotationinactivedelay']);
699
- $autorotationstopdelay = '';
700
- $autorotationstopdelay = sanitize_text_field($_POST['autorotationstopdelay']);
701
-
702
- if (!empty($autorotationinactivedelay) && !empty($autorotationstopdelay)) {
703
- wp_send_json_error('<p><span>Warning:</span> You can not apply both autorotation pause or stop delay. Please choose either autorotation inactive delay or autorotation stop delay</p>');
704
- die();
705
- }
706
-
707
- //===Company Logo===//
708
- $cpLogoSwitch = 'off';
709
- $cpLogoSwitch = $_POST['cpLogoSwitch'];
710
- $cpLogoImg = '';
711
- $cpLogoImg = $_POST['cpLogoImg'];
712
- $cpLogoContent = '';
713
- $cpLogoContent = sanitize_text_field($_POST['cpLogoContent']);
714
- //===Company Logo===//
715
-
716
-
717
  $scene_fade_duration = '';
718
  $scene_fade_duration = $_POST['scenefadeduration'];
719
 
720
  $panodata = $_POST['panodata'];
721
- $panolist = stripslashes($panodata);
722
- $panodata = (array)json_decode($panolist);
723
- $panolist = array();
724
- if(is_array($panodata["scene-list"])) {
725
- foreach ($panodata["scene-list"] as $scenes_data) {
726
- $temp_array = array();
727
- $temp_array = (array)$scenes_data;
728
- if ($temp_array['hotspot-list']) {
729
- $_hotspot_array = array();
730
- foreach ($temp_array['hotspot-list'] as $temp_hotspot) {
731
- $temp_hotspot = (array)$temp_hotspot;
732
- $_hotspot_array[] = $temp_hotspot;
733
- }
734
- }
735
- $temp_array['hotspot-list'] = $_hotspot_array;
736
- $panolist['scene-list'][] = $temp_array;
737
- }
738
- }
739
- $panodata = $panolist;
740
 
741
  //===Error Control and Validation===//
 
 
 
 
742
 
743
  if ($panodata["scene-list"] != "") {
744
  foreach ($panodata["scene-list"] as $scenes_val) {
745
-
746
  $scene_id_validate = $scenes_val["scene-id"];
747
  if (!empty($scene_id_validate)) {
748
  $scene_id_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$scene_id_validate);
749
  if ($scene_id_validated != $scene_id_validate) {
750
- wp_send_json_error('<p><span>Warning:</span> The scene id can only contain letters and numbers where scene id: '.$scene_id_validate.'</p>');
751
  die();
752
  }
 
753
 
754
- if (empty($scenes_val["scene-attachment-url"])) {
755
- wp_send_json_error('<p><span>Warning:</span> A scene image is required for every scene where scene id: '.$scene_id_validate.'</p>');
756
- die();
757
- }
758
 
759
- if (!empty($scenes_val["scene-pitch"])) {
760
- $validate_scene_pitch = $scenes_val["scene-pitch"];
761
- $validated_scene_pitch = preg_replace('/[^0-9.-]/','',$validate_scene_pitch);
762
- if ($validated_scene_pitch != $validate_scene_pitch) {
763
- wp_send_json_error('<p><span>Warning:</span> Default pitch value can only contain float numbers where scene id: '.$scene_id_validate.'</p>');
764
- die();
765
- }
766
- }
767
 
768
- if (!empty($scenes_val["scene-yaw"])) {
769
- $validate_scene_yaw = $scenes_val["scene-yaw"];
770
- $validated_scene_yaw = preg_replace('/[^0-9.-]/','',$validate_scene_yaw);
771
- if ($validated_scene_yaw != $validate_scene_yaw) {
772
- wp_send_json_error('<p><span>Warning:</span> Default yaw value can only contain float numbers where scene id: '.$scene_id_validate.'</p>');
773
  die();
774
  }
775
- }
776
 
777
- if (!empty($scenes_val["scene-zoom"])) {
778
- $validate_default_zoom = $scenes_val["scene-zoom"];
779
- $validated_default_zoom = preg_replace('/[^0-9-]/','',$validate_default_zoom);
780
- if ($validated_default_zoom != $validate_default_zoom) {
781
- wp_send_json_error('<p><span>Warning:</span> Default zoom value can only contain number in degree from 50 to 120 where scene id: '.$scene_id_validate.'</p>');
782
- die();
783
- }
784
- $default_zoom_value = (int)$scenes_val["scene-zoom"];
785
- if ($default_zoom_value > 120 || $default_zoom_value < 50) {
786
- wp_send_json_error('<p><span>Warning:</span> Default zoom value can only contain number in degree from 50 to 120 where scene id: '.$scene_id_validate.'</p>');
787
- die();
788
  }
789
- }
790
 
791
- if (!empty($scenes_val["scene-maxzoom"])) {
792
- $validate_max_zoom = $scenes_val["scene-maxzoom"];
793
- $validated_max_zoom = preg_replace('/[^0-9-]/','',$validate_max_zoom);
794
- if ($validated_max_zoom != $validate_max_zoom) {
795
- wp_send_json_error('<p><span>Warning:</span> Max zoom out value can only contain number in degree where scene id: '.$scene_id_validate.'</p>');
796
  die();
797
  }
798
- $max_zoom_value = (int)$scenes_val["scene-maxzoom"];
799
- if ($max_zoom_value > 120 ) {
800
- wp_send_json_error('<p><span>Warning:</span> Max zoom out value can only contain number in degree below 120 where scene id: '.$scene_id_validate.'</p>');
801
- die();
 
 
802
  }
803
- }
804
 
805
- if (!empty($scenes_val["scene-minzoom"])) {
806
- $validate_min_zoom = $scenes_val["scene-minzoom"];
807
- $validated_min_zoom = preg_replace('/[^0-9-]/','',$validate_min_zoom);
808
- if ($validated_min_zoom != $validate_min_zoom) {
809
- wp_send_json_error('<p><span>Warning:</span> Max zoom in value can only contain number in degree where scene id: '.$scene_id_validate.'</p>');
810
- die();
811
  }
812
- $min_zoom_value = (int)$scenes_val["scene-minzoom"];
813
- if ($min_zoom_value < 50 ) {
814
- wp_send_json_error('<p><span>Warning:</span> Max zoom in value can only contain number in degree above 50 where scene id: '.$scene_id_validate.'</p>');
815
- die();
 
 
816
  }
817
- }
818
-
819
- if ($scenes_val["hotspot-list"] != "") {
820
- foreach ($scenes_val["hotspot-list"] as $hotspot_val) {
821
-
822
- $hotspot_title_validate = $hotspot_val["hotspot-title"];
823
-
824
- if (!empty($hotspot_title_validate)) {
825
- $hotspot_title_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$hotspot_title_validate);
826
- if ($hotspot_title_validated != $hotspot_title_validate) {
827
- wp_send_json_error('<p><span>Warning:</span> Hotspot title can only contain letters and numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
828
- die();
829
- }
830
- $hotspot_pitch_validate = $hotspot_val["hotspot-pitch"];
831
- if (empty($hotspot_pitch_validate)) {
832
- wp_send_json_error('<p><span>Warning:</span> Hotspot pitch is required for every hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
833
- die();
834
- }
835
- if (!empty($hotspot_pitch_validate)) {
836
- $hotspot_pitch_validated = preg_replace('/[^0-9.-]/','',$hotspot_pitch_validate);
837
- if ($hotspot_pitch_validated != $hotspot_pitch_validate) {
838
- wp_send_json_error('<p><span>Warning:</span> Hotspot pitch can only contain float numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
839
- die();
840
- }
841
- }
842
-
843
- $hotspot_yaw_validate = $hotspot_val["hotspot-yaw"];
844
- if (empty($hotspot_yaw_validate)) {
845
- wp_send_json_error('<p><span>Warning:</span> Hotspot yaw is required for every hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
846
- die();
847
- }
848
- if (!empty($hotspot_yaw_validate)) {
849
- $hotspot_yaw_validated = preg_replace('/[^0-9.-]/','',$hotspot_yaw_validate);
850
- if ($hotspot_yaw_validated != $hotspot_yaw_validate) {
851
- wp_send_json_error('<p><span>Warning:</span> Hotspot yaw can only contain float numbers where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
852
- die();
853
- }
854
- }
855
-
856
- if(is_plugin_active( 'wpvr-pro/wpvr-pro.php' )){
857
- $status = get_option( 'wpvr_edd_license_status' );
858
- if( $status !== false && $status == 'valid' ) {
859
- if ($hotspot_val["hotspot-customclass-pro"] != 'none' && !empty($hotspot_val["hotspot-customclass"])) {
860
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Custom icon class and custom icon both where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
861
- die();
862
- }
863
- }
864
- }
865
- $hotspot_type_validate = $hotspot_val["hotspot-type"];
866
- $hotspot_url_validate = $hotspot_val["hotspot-url"];
867
- if (!empty($hotspot_url_validate)) {
868
- $hotspot_url_validated = esc_url($hotspot_url_validate);
869
- if ($hotspot_url_validated != $hotspot_url_validate) {
870
- wp_send_json_error('<p><span>Warning:</span> Hotspot Url is invalid where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
871
- die();
872
- }
873
- }
874
- $hotspot_content_validate = $hotspot_val["hotspot-content"];
875
 
876
- $hotspot_scene_validate = $hotspot_val["hotspot-scene"];
877
 
878
- if ($hotspot_type_validate == "info") {
879
- if (!empty($hotspot_scene_validate)) {
880
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Target Scene ID on info type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
881
- die();
882
- }
883
- if (!empty($hotspot_url_validate) && !empty($hotspot_content_validate)) {
884
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Url and On click content both on same hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
885
- die();
886
- }
887
- }
888
 
889
- if ($hotspot_type_validate == "scene") {
890
- if (empty($hotspot_scene_validate)) {
891
- wp_send_json_error('<p><span>Warning:</span> Target scene id is required for scene type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
892
- die();
893
- }
894
- if (!empty($hotspot_url_validate) || !empty($hotspot_content_validate)) {
895
- wp_send_json_error('<p><span>Warning:</span> Don\'t add Url or On click content on scene type hotspot where scene id: '.$scene_id_validate.' and hotspot id : '.$hotspot_title_validate.'</p>');
896
- die();
897
- }
898
- }
899
  }
900
  }
901
  }
@@ -903,230 +337,18 @@ class Wpvr_Ajax {
903
  }
904
  }
905
  //===Error Control and Validation===//
906
-
907
- foreach ($panodata["scene-list"] as $panoscenes) {
908
- if (empty($panoscenes['scene-id']) && !empty($panoscenes['scene-attachment-url'])) {
909
- wp_send_json_error('<p><span>Warning:</span> You have added a scene image but empty scene id. Please add scene id and update </p>');
910
- die();
911
- }
912
- }
913
-
914
- $allsceneids = array();
915
-
916
- foreach ($panodata["scene-list"] as $panoscenes) {
917
- if (!empty($panoscenes['scene-id'])) {
918
- array_push($allsceneids, $panoscenes['scene-id']);
919
- }
920
- }
921
-
922
  foreach ($panodata["scene-list"] as $panoscenes) {
923
-
924
  if ($panoscenes['dscene'] == 'on') {
925
  $default_scene = $panoscenes['scene-id'];
926
  }
927
  }
928
  if (empty($default_scene)) {
929
- if ($allsceneids) {
930
- $default_scene = $allsceneids[0];
931
- }
932
- else {
933
- wp_send_json_error('<p><span>Warning:</span> No default scene selected and no scene id found to set as default. You need at least one scene to publish a tour </p>');
934
- die();
935
- }
936
- }
937
-
938
- $allsceneids_count = array_count_values($allsceneids);
939
- foreach ($allsceneids_count as $key => $value) {
940
- if ($value > 1) {
941
- wp_send_json_error('<p><span>Warning:</span> You can not use same scene id on multiple scene </p>');
942
- die();
943
- }
944
- }
945
-
946
- foreach ($panodata["scene-list"] as $panoscenes) {
947
- if (!empty($panoscenes['scene-id'])) {
948
- $allhotspot = array();
949
- foreach ($panoscenes["hotspot-list"] as $hotspot_val) {
950
- if (!empty($hotspot_val["hotspot-title"])) {
951
- array_push($allhotspot, $hotspot_val["hotspot-title"]);
952
- }
953
- }
954
- $allhotspotcount = array_count_values($allhotspot);
955
- foreach ($allhotspotcount as $key => $value) {
956
- if ($value > 1) {
957
- wp_send_json_error('<p><span>Warning:</span> You can not use same hotspot id on multiple hotspot for same scene </p>');
958
- die();
959
- }
960
- }
961
- }
962
- }
963
-
964
- $panolength = count($panodata["scene-list"]);
965
- for ($i=0; $i < $panolength; $i++) {
966
- if (empty($panodata["scene-list"][$i]['scene-id'])) {
967
- unset($panodata["scene-list"][$i]);
968
- }
969
- else {
970
- $panohotspotlength = count($panodata["scene-list"][$i]['hotspot-list']);
971
- for ($j=0; $j < $panohotspotlength; $j++) {
972
- if (empty($panodata["scene-list"][$i]['hotspot-list'][$j]['hotspot-title'])) {
973
- unset($panodata["scene-list"][$i]['hotspot-list'][$j]);
974
- }
975
- }
976
- }
977
  }
978
-
979
  $pano_array = array();
980
- $pano_array = array(__( "panoid" )=>$panoid,__( "autoLoad" )=>$autoload,__( "showControls" )=>$control,__( "cpLogoSwitch" )=>$cpLogoSwitch,__( "cpLogoImg" )=>$cpLogoImg,__( "cpLogoContent" )=>$cpLogoContent,__( "vrgallery" )=>$vrgallery,__( "customcontrol" )=>$custom_control,__( "gyro" )=>$gyro,__( "compass" )=>$compass,__( "autoRotate" )=>$autorotation,__( "autoRotateInactivityDelay" )=>$autorotationinactivedelay,__( "autoRotateStopDelay" )=>$autorotationstopdelay,__( "preview" )=>$preview,__( "defaultscene" )=>$default_scene,__( "scenefadeduration" )=>$scene_fade_duration,__( "panodata" )=>$panodata);
981
-
982
- if ($rotation == 'off') {
983
- unset($pano_array['autoRotate']);
984
- unset($pano_array['autoRotateInactivityDelay']);
985
- unset($pano_array['autoRotateStopDelay']);
986
- }
987
- if (empty($autorotation)) {
988
- unset($pano_array['autoRotate']);
989
- unset($pano_array['autoRotateInactivityDelay']);
990
- unset($pano_array['autoRotateStopDelay']);
991
- }
992
- if (empty($autorotationinactivedelay)) {
993
- unset($pano_array['autoRotateInactivityDelay']);
994
- }
995
- if (empty($autorotationstopdelay)) {
996
- unset($pano_array['autoRotateStopDelay']);
997
- }
998
-
999
  update_post_meta( $postid, 'panodata', $pano_array );
1000
  die();
1001
  }
1002
-
1003
- function wpvr_file_import() {
1004
- set_time_limit(20000000000000000);
1005
- wpvr_delete_temp_file();
1006
- if ($_POST['fileurl']) {
1007
- WP_Filesystem();
1008
- $file_save_url = wp_upload_dir();
1009
- $fileurl = $_POST['fileurl'];
1010
- $attachment_id = $_POST['data_id'];
1011
- $zip_file_path = get_attached_file( $attachment_id );
1012
- $unzipfile = unzip_file($zip_file_path,$file_save_url['basedir'].'/wpvr/temp/');
1013
-
1014
- if ( is_wp_error( $unzipfile ) ) {
1015
- wpvr_delete_temp_file();
1016
- wp_send_json_error('Failed to unzip file');
1017
- }
1018
- $result = glob($file_save_url["basedir"].'/wpvr/temp/*.json');
1019
- if (!$result) {
1020
- wpvr_delete_temp_file();
1021
- wp_send_json_error('Tour json file not found');
1022
- }
1023
- $tour_json = $result[0];
1024
- $arrContextOptions=array(
1025
- "ssl"=>array(
1026
- "verify_peer"=>false,
1027
- "verify_peer_name"=>false,
1028
- ),
1029
- );
1030
- $getfile = file_get_contents($tour_json, false, stream_context_create($arrContextOptions));
1031
- $file_content = json_decode($getfile, true);
1032
-
1033
- $new_title = $file_content['title'];
1034
- $new_data = $file_content['data'];
1035
- $new_post_id = wp_insert_post( array(
1036
- 'post_title' => $new_title,
1037
- 'post_type' => 'wpvr_item',
1038
- 'post_status' => 'publish',
1039
- ) );
1040
- if ($new_post_id) {
1041
- if ($new_data['panoid']) {
1042
- $new_data['panoid'] = 'pano'.$new_post_id;
1043
- }
1044
- if ($new_data['preview']) {
1045
- $preview_url = $file_save_url['baseurl'].'/wpvr/temp/scene_preview.jpg';
1046
- $media_get = wpvr_handle_media_import($preview_url, $new_post_id);
1047
- if ($media_get['status'] == 'error') {
1048
- wp_delete_post($new_post_id, true);
1049
- wpvr_delete_temp_file();
1050
- wp_send_json_error($media_get['message']);
1051
- }
1052
- elseif ($media_get['status'] == 'success') {
1053
- $new_data['preview'] = $media_get['message'];
1054
- }
1055
- else {
1056
- wp_delete_post($new_post_id, true);
1057
- wpvr_delete_temp_file();
1058
- wp_send_json_error('Media transfer process failed');
1059
- }
1060
- }
1061
- if ($new_data['panodata']) {
1062
-
1063
- if ($new_data['panodata']["scene-list"]) {
1064
-
1065
- foreach ($new_data['panodata']["scene-list"] as $key => $panoscenes) {
1066
- if ($panoscenes["scene-attachment-url"]) {
1067
- $scene_id = $panoscenes['scene-id'];
1068
- $url = $file_save_url['baseurl'].'/wpvr/temp/'.$scene_id.'.jpg';
1069
- $media_get = wpvr_handle_media_import($url, $new_post_id);
1070
- if ($media_get['status'] == 'error') {
1071
- wp_delete_post($new_post_id, true);
1072
- wpvr_delete_temp_file();
1073
- wp_send_json_error($media_get['message']);
1074
- }
1075
- elseif ($media_get['status'] == 'success') {
1076
- $new_data['panodata']["scene-list"][$key]['scene-attachment-url'] = $media_get['message'];
1077
- }
1078
- else {
1079
- wp_delete_post($new_post_id, true);
1080
- wpvr_delete_temp_file();
1081
- wp_send_json_error('Media transfer process failed');
1082
- }
1083
- }
1084
- }
1085
- }
1086
- update_post_meta( $new_post_id, 'panodata', $new_data );
1087
- wpvr_delete_temp_file();
1088
- }
1089
- }
1090
- }
1091
- else {
1092
- wpvr_delete_temp_file();
1093
- wp_send_json_error('No file found to import');
1094
- }
1095
- die();
1096
- }
1097
-
1098
- /**
1099
- * Video Preview show ajax function
1100
- */
1101
- function wpvrstreetview_preview() {
1102
- $panoid ='';
1103
- $postid = sanitize_text_field($_POST['postid']);
1104
- $panoid = 'pano'.$postid;
1105
- $randid = rand(1000, 1000000);
1106
- $streetviewid = 'streetview'.$randid;
1107
- $streetviewurl = $_POST['streetview'];
1108
- if ($streetviewurl) {
1109
- $html .= '<iframe src="'.$streetviewurl.'" width="600" height="400" frameborder="0" style="border:0;" allowfullscreen=""></iframe>';
1110
- }
1111
-
1112
- $response = array();
1113
- $response = array(__( "panoid" )=>$panoid,__( "panodata" )=>$html,__( "streetview" )=>$streetviewid);
1114
- wp_send_json_success( $response );
1115
- }
1116
-
1117
- /**
1118
- * WPVR BF DISSMISS
1119
- */
1120
- function wpvr_bf_dismiss() {
1121
- $current_time = time();
1122
- $date_now = date("Y-m-d", $current_time);
1123
- if( $date_now == '2019-11-28' ) {
1124
- update_option('wpvr_bf_notice', 'close');
1125
- }
1126
- else {
1127
- update_option('wpvr_bf_notice', 'off');
1128
- }
1129
- wp_send_json_success( 'off' );
1130
- die();
1131
- }
1132
  }
30
  $control = false;
31
  }
32
 
 
 
 
 
 
 
 
 
33
  $autoload = sanitize_text_field($_POST['autoload']);
34
  if ($autoload == 'on') {
35
  $autoload = true;
40
 
41
  $default_scene = '';
42
  $default_scene = sanitize_text_field($_POST['defaultscene']);
43
+ // if (empty($default_scene)) {
44
+ // wp_send_json_error('<p><span>Warning:</span> Default scene id required. Go to general setting\'s tab & check.</p>');
45
+ // die();
46
+ // }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  $scene_fade_duration = '';
49
  $scene_fade_duration = sanitize_text_field($_POST['scenefadeduration']);
50
 
51
  $panodata = $_POST['panodata'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  //===Error Control and Validation===//
54
+ if (!wpvr_in_array_r($default_scene, $panodata)) {
55
+ wp_send_json_error('<p><span>Warning:</span> Default scene id is invalid. Go to general setting\'s tab & check.</p>');
56
+ die();
57
+ }
58
 
59
  if ($panodata["scene-list"] != "") {
60
  foreach ($panodata["scene-list"] as $scenes_val) {
63
  if (!empty($scene_id_validate)) {
64
  $scene_id_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$scene_id_validate);
65
  if ($scene_id_validated != $scene_id_validate) {
66
+ wp_send_json_error('<p><span>Warning:</span> The scene id can only contain letters and numbers</p>');
 
 
 
 
 
67
  die();
68
  }
69
+ }
70
 
71
+ if (empty($scene_id_validate)) {
72
+ wp_send_json_error('<p><span>Warning:</span> Scene Id is required for every scene.</p>');
73
+ die();
74
+ }
 
 
 
 
75
 
76
+ if (empty($scenes_val["scene-attachment-url"])) {
77
+ wp_send_json_error('<p><span>Warning:</span> A scene image is required for every scene.</p>');
78
+ die();
79
+ }
 
 
 
 
80
 
81
+ if ($scenes_val["hotspot-list"] != "") {
82
+ foreach ($scenes_val["hotspot-list"] as $hotspot_val) {
83
+ $hotspot_title_validate = $hotspot_val["hotspot-title"];
 
 
 
 
 
 
 
 
 
 
84
 
85
+ if (!empty($hotspot_title_validate)) {
86
+ $hotspot_title_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$hotspot_title_validate);
87
+ if ($hotspot_title_validated != $hotspot_title_validate) {
88
+ wp_send_json_error('<p><span>Warning:</span> Hotspot title can only contain letters and numbers</p>');
89
+ die();
90
+ }
91
  }
92
+
93
+ $hotspot_pitch_validate = $hotspot_val["hotspot-pitch"];
94
+ if (!empty($hotspot_pitch_validate)) {
95
+ $hotspot_pitch_validated = preg_replace('/[^0-9.-]/','',$hotspot_pitch_validate);
96
+ if ($hotspot_pitch_validated != $hotspot_pitch_validate) {
97
+ wp_send_json_error('<p><span>Warning:</span> Hotspot pitch can only contain float numbers</p>');
98
+ die();
99
+ }
100
  }
 
101
 
102
+ $hotspot_yaw_validate = $hotspot_val["hotspot-yaw"];
103
+ if (!empty($hotspot_yaw_validate)) {
104
+ $hotspot_yaw_validated = preg_replace('/[^0-9.-]/','',$hotspot_yaw_validate);
105
+ if ($hotspot_yaw_validated != $hotspot_yaw_validate) {
106
+ wp_send_json_error('<p><span>Warning:</span> Hotspot yaw can only contain float numbers</p>');
107
+ die();
108
+ }
109
  }
110
+ $hotspot_type_validate = $hotspot_val["hotspot-type"];
111
+ $hotspot_url_validate = $hotspot_val["hotspot-url"];
112
+ if (!empty($hotspot_url_validate)) {
113
+ $hotspot_url_validated = esc_url($hotspot_url_validate);
114
+ if ($hotspot_url_validated != $hotspot_url_validate) {
115
+ wp_send_json_error('<p><span>Warning:</span> Hotspot Url is invalid</p>');
116
+ die();
117
+ }
118
  }
119
+ $hotspot_content_validate = $hotspot_val["hotspot-content"];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
+ $hotspot_scene_validate = $hotspot_val["hotspot-scene"];
122
 
123
+ if ($hotspot_type_validate == "info") {
124
+ if (!empty($hotspot_scene_validate)) {
125
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Target Scene ID on info type hotspot</p>');
126
+ die();
127
+ }
128
+ if (!empty($hotspot_url_validate) && !empty($hotspot_content_validate)) {
129
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Url and On click content both on same hotspot.</p>');
130
+ die();
131
+ }
132
+ }
133
 
134
+ if ($hotspot_type_validate == "scene") {
135
+ if (empty($hotspot_scene_validate)) {
136
+ wp_send_json_error('<p><span>Warning:</span> Target scene id is required for scene type hotspot.</p>');
137
+ die();
138
+ }
139
+ if (!empty($hotspot_url_validate) || !empty($hotspot_content_validate)) {
140
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Url or On click content on scene type hotspot.</p>');
141
+ die();
 
 
142
  }
143
  }
144
  }
146
  }
147
  }
148
  //===Error Control and Validation===//
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
 
150
  foreach ($panodata["scene-list"] as $panoscenes) {
 
151
  if ($panoscenes['dscene'] == 'on') {
152
  $default_scene = $panoscenes['scene-id'];
153
  }
154
  }
155
  if (empty($default_scene)) {
156
+ wp_send_json_error('<p><span>Warning:</span> Default scene is required. Set a scene as deafualt to load it by deafult.</p>');
157
+ die();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  }
159
 
160
  $default_data = array();
161
+ $default_data = array(__( "firstScene" )=>$default_scene,__( "sceneFadeDuration" )=>$scene_fade_duration);
162
  $scene_data = array();
163
 
164
  foreach ($panodata["scene-list"] as $panoscenes) {
165
 
166
+ $hotspot_datas = $panoscenes["hotspot-list"];
167
+ $hotspots = array();
168
+ foreach ($hotspot_datas as $hotspot_data) {
169
+
170
+ $hotspot_info = array(
171
+ __( "text" )=>$hotspot_data["hotspot-title"],
172
+ __( "pitch" )=>$hotspot_data["hotspot-pitch"],
173
+ __( "yaw" )=>$hotspot_data["hotspot-yaw"],
174
+ __( "type" )=>$hotspot_data["hotspot-type"],
175
+ __( "URL" )=>$hotspot_data["hotspot-url"],
176
+ __( "clickHandlerArgs" )=>$hotspot_data["hotspot-content"],
177
+ __( "createTooltipArgs" )=>$hotspot_data["hotspot-hover"],
178
+ __( "sceneId" )=>$hotspot_data["hotspot-scene"]);
179
+ array_push($hotspots, $hotspot_info);
180
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
 
182
+ $scene_info = array();
183
+ $scene_info = array(__( "type" )=>$panoscenes["scene-type"],__( "panorama" )=>$panoscenes["scene-attachment-url"],__( "hotSpots" )=>$hotspots);
184
+ $scene_array = array();
185
+ $scene_array = array(
186
+ __($panoscenes["scene-id"])=>$scene_info
187
+ );
188
+ $scene_data[$panoscenes["scene-id"]] = $scene_info;
189
  }
190
 
191
  $pano_id_array = array();
192
+ $pano_id_array = array(__( "panoid" )=>$panoid);
193
  $pano_response = array();
194
+ $pano_response = array(__( "autoLoad" )=>$autoload,__( "showControls" )=>$control,__( "default" )=>$default_data,__( "scenes" )=>$scene_data);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  $response = array();
196
  $response = array($pano_id_array,$pano_response);
197
 
198
  wp_send_json_success( $response );
199
  }
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  function wpvr_save_data() {
202
  $panoid ='';
203
  $postid = sanitize_text_field($_POST['postid']);
207
  }
208
  $panoid = 'pano'.$postid;
209
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  $control = sanitize_text_field($_POST['control']);
211
  if ($control == 'on') {
212
  $control = true;
215
  $control = false;
216
  }
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  $autoload = sanitize_text_field($_POST['autoload']);
219
  if ($autoload == 'on') {
220
  $autoload = true;
225
 
226
  $default_scene = '';
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  $scene_fade_duration = '';
229
  $scene_fade_duration = $_POST['scenefadeduration'];
230
 
231
  $panodata = $_POST['panodata'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
  //===Error Control and Validation===//
234
+ if (!wpvr_in_array_r($default_scene, $panodata)) {
235
+ wp_send_json_error('<p><span>Warning:</span> Default scene id is invalid. Go to general setting\'s tab & check.</p>');
236
+ die();
237
+ }
238
 
239
  if ($panodata["scene-list"] != "") {
240
  foreach ($panodata["scene-list"] as $scenes_val) {
 
241
  $scene_id_validate = $scenes_val["scene-id"];
242
  if (!empty($scene_id_validate)) {
243
  $scene_id_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$scene_id_validate);
244
  if ($scene_id_validated != $scene_id_validate) {
245
+ wp_send_json_error('<p><span>Warning:</span> The scene id can only contain letters and numbers.</p>');
246
  die();
247
  }
248
+ }
249
 
250
+ if (empty($scene_id_validate)) {
251
+ wp_send_json_error('<p>Scene Id is required</p>');
252
+ die();
253
+ }
254
 
255
+ if (empty($scenes_val["scene-attachment-url"])) {
256
+ wp_send_json_error('<p><span>Warning:</span> A scene image is required for every scene.</p>');
257
+ die();
258
+ }
 
 
 
 
259
 
260
+ if ($scenes_val["hotspot-list"] != "") {
261
+ foreach ($scenes_val["hotspot-list"] as $hotspot_val) {
262
+ $hotspot_title_validate = $hotspot_val["hotspot-title"];
263
+ if (empty($hotspot_title_validate)) {
264
+ wp_send_json_error('<p><span>Warning:</span> Hotspot title is required for every hotspot.</p>');
265
  die();
266
  }
 
267
 
268
+ if (!empty($hotspot_title_validate)) {
269
+ $hotspot_title_validated = preg_replace('/[^0-9a-zA-Z_]/',"",$hotspot_title_validate);
270
+ if ($hotspot_title_validated != $hotspot_title_validate) {
271
+ wp_send_json_error('<p><span>Warning:</span> Hotspot title can only contain letters and numbers.</p>');
272
+ die();
273
+ }
 
 
 
 
 
274
  }
 
275
 
276
+ $hotspot_pitch_validate = $hotspot_val["hotspot-pitch"];
277
+ if (empty($hotspot_pitch_validate)) {
278
+ wp_send_json_error('<p><span>Warning:</span> Hotspot pitch is required for every hotspot.</p>');
 
 
279
  die();
280
  }
281
+ if (!empty($hotspot_pitch_validate)) {
282
+ $hotspot_pitch_validated = preg_replace('/[^0-9.-]/','',$hotspot_pitch_validate);
283
+ if ($hotspot_pitch_validated != $hotspot_pitch_validate) {
284
+ wp_send_json_error('<p><span>Warning:</span> Hotspot pitch can only contain float numbers.</p>');
285
+ die();
286
+ }
287
  }
 
288
 
289
+ $hotspot_yaw_validate = $hotspot_val["hotspot-yaw"];
290
+ if (empty($hotspot_yaw_validate)) {
291
+ wp_send_json_error('<p><span>Warning:</span> Hotspot yaw is required for every hotspot.</p>');
292
+ die();
 
 
293
  }
294
+ if (!empty($hotspot_yaw_validate)) {
295
+ $hotspot_yaw_validated = preg_replace('/[^0-9.-]/','',$hotspot_yaw_validate);
296
+ if ($hotspot_yaw_validated != $hotspot_yaw_validate) {
297
+ wp_send_json_error('<p><span>Warning:</span> Hotspot yaw can only contain float numbers.</p>');
298
+ die();
299
+ }
300
  }
301
+ $hotspot_type_validate = $hotspot_val["hotspot-type"];
302
+ $hotspot_url_validate = $hotspot_val["hotspot-url"];
303
+ if (!empty($hotspot_url_validate)) {
304
+ $hotspot_url_validated = esc_url($hotspot_url_validate);
305
+ if ($hotspot_url_validated != $hotspot_url_validate) {
306
+ wp_send_json_error('<p><span>Warning:</span> Hotspot Url is invalid.</p>');
307
+ die();
308
+ }
309
+ }
310
+ $hotspot_content_validate = $hotspot_val["hotspot-content"];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
 
312
+ $hotspot_scene_validate = $hotspot_val["hotspot-scene"];
313
 
314
+ if ($hotspot_type_validate == "info") {
315
+ if (!empty($hotspot_scene_validate)) {
316
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Target Scene ID on info type hotspot.</p>');
317
+ die();
318
+ }
319
+ if (!empty($hotspot_url_validate) && !empty($hotspot_content_validate)) {
320
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Url and On click content both on same hotspot.</p>');
321
+ die();
322
+ }
323
+ }
324
 
325
+ if ($hotspot_type_validate == "scene") {
326
+ if (empty($hotspot_scene_validate)) {
327
+ wp_send_json_error('<p><span>Warning:</span> Targer scene id is required for scene type hotspot.</p>');
328
+ die();
329
+ }
330
+ if (!empty($hotspot_url_validate) || !empty($hotspot_content_validate)) {
331
+ wp_send_json_error('<p><span>Warning:</span> Don\'t add Url or On click content on scene type hotspot.</p>');
332
+ die();
 
 
333
  }
334
  }
335
  }
337
  }
338
  }
339
  //===Error Control and Validation===//
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  foreach ($panodata["scene-list"] as $panoscenes) {
 
341
  if ($panoscenes['dscene'] == 'on') {
342
  $default_scene = $panoscenes['scene-id'];
343
  }
344
  }
345
  if (empty($default_scene)) {
346
+ wp_send_json_error('<p><span>Warning:</span> Default scene is required. Set a scene as deafualt to load it by deafult.</p>');
347
+ die();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
 
349
  $pano_array = array();
350
+ $pano_array = array(__( "panoid" )=>$panoid,__( "autoLoad" )=>$autoload,__( "showControls" )=>$control,__( "defaultscene" )=>$default_scene,__( "scenefadeduration" )=>$scene_fade_duration,__( "panodata" )=>$panodata);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  update_post_meta( $postid, 'panodata', $pano_array );
352
  die();
353
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  }
admin/class-wpvr-icon.php DELETED
@@ -1,1019 +0,0 @@
1
- <?php
2
- if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
3
- /**
4
- * The fontawesome functionality of the plugin.
5
- *
6
- * @link http://rextheme.com/
7
- * @since 1.0.0
8
- *
9
- * @package Wpvr
10
- * @subpackage Wpvr/admin
11
- */
12
-
13
- class Wpvr_fontawesome_icons {
14
-
15
- public $icon;
16
-
17
- /**
18
- * Admin icon setup is specified in this area.
19
- */
20
-
21
- public function __construct() {
22
-
23
- $this->icon = array (
24
- 'none' => __( 'None', 'wpvr' ),
25
- 'fab fa-500px' => __( '500px', 'wpvr' ),
26
- 'fab fa-accessible-icon' => __( 'accessible-icon', 'wpvr' ),
27
- 'fab fa-accusoft' => __( 'accusoft', 'wpvr' ),
28
- 'fas fa-address-book' => __( 'address-book', 'wpvr' ),
29
- 'far fa-address-book' => __( 'address-book', 'wpvr' ),
30
- 'fas fa-address-card' => __( 'address-card', 'wpvr' ),
31
- 'far fa-address-card' => __( 'address-card', 'wpvr' ),
32
- 'fas fa-adjust' => __( 'adjust', 'wpvr' ),
33
- 'fab fa-adn' => __( 'adn', 'wpvr' ),
34
- 'fab fa-adversal' => __( 'adversal', 'wpvr' ),
35
- 'fab fa-affiliatetheme' => __( 'affiliatetheme', 'wpvr' ),
36
- 'fab fa-algolia' => __( 'algolia', 'wpvr' ),
37
- 'fas fa-align-center' => __( 'align-center', 'wpvr' ),
38
- 'fas fa-align-justify' => __( 'align-justify', 'wpvr' ),
39
- 'fas fa-align-left' => __( 'align-left', 'wpvr' ),
40
- 'fas fa-align-right' => __( 'align-right', 'wpvr' ),
41
- 'fas fa-allergies' => __( 'allergies', 'wpvr' ),
42
- 'fab fa-amazon' => __( 'amazon', 'wpvr' ),
43
- 'fab fa-amazon-pay' => __( 'amazon-pay', 'wpvr' ),
44
- 'fas fa-ambulance' => __( 'ambulance', 'wpvr' ),
45
- 'fas fa-american-sign-language-interpreting' => __( 'american-sign-language-interpreting', 'wpvr' ),
46
- 'fab fa-amilia' => __( 'amilia', 'wpvr' ),
47
- 'fas fa-anchor' => __( 'anchor', 'wpvr' ),
48
- 'fab fa-android' => __( 'android', 'wpvr' ),
49
- 'fab fa-angellist' => __( 'angellist', 'wpvr' ),
50
- 'fas fa-angle-double-down' => __( 'angle-double-down', 'wpvr' ),
51
- 'fas fa-angle-double-left' => __( 'angle-double-left', 'wpvr' ),
52
- 'fas fa-angle-double-right' => __( 'angle-double-right', 'wpvr' ),
53
- 'fas fa-angle-double-up' => __( 'angle-double-up', 'wpvr' ),
54
- 'fas fa-angle-down' => __( 'angle-down', 'wpvr' ),
55
- 'fas fa-angle-left' => __( 'angle-left', 'wpvr' ),
56
- 'fas fa-angle-right' => __( 'angle-right', 'wpvr' ),
57
- 'fas fa-angle-up' => __( 'angle-up', 'wpvr' ),
58
- 'fab fa-angrycreative' => __( 'angrycreative', 'wpvr' ),
59
- 'fab fa-angular' => __( 'angular', 'wpvr' ),
60
- 'fab fa-app-store' => __( 'app-store', 'wpvr' ),
61
- 'fab fa-app-store-ios' => __( 'app-store-ios', 'wpvr' ),
62
- 'fab fa-apper' => __( 'apper', 'wpvr' ),
63
- 'fab fa-apple' => __( 'apple', 'wpvr' ),
64
- 'fab fa-apple-pay' => __( 'apple-pay', 'wpvr' ),
65
- 'fas fa-archive' => __( 'archive', 'wpvr' ),
66
- 'fas fa-arrow-alt-circle-down' => __( 'arrow-alt-circle-down', 'wpvr' ),
67
- 'far fa-arrow-alt-circle-down' => __( 'arrow-alt-circle-down', 'wpvr' ),
68
- 'fas fa-arrow-alt-circle-left' => __( 'arrow-alt-circle-left', 'wpvr' ),
69
- 'far fa-arrow-alt-circle-left' => __( 'arrow-alt-circle-left', 'wpvr' ),
70
- 'fas fa-arrow-alt-circle-right' => __( 'arrow-alt-circle-right', 'wpvr' ),
71
- 'far fa-arrow-alt-circle-right' => __( 'arrow-alt-circle-right', 'wpvr' ),
72
- 'fas fa-arrow-alt-circle-up' => __( 'arrow-alt-circle-up', 'wpvr' ),
73
- 'far fa-arrow-alt-circle-up' => __( 'arrow-alt-circle-up', 'wpvr' ),
74
- 'fas fa-arrow-circle-down' => __( 'arrow-circle-down', 'wpvr' ),
75
- 'fas fa-arrow-circle-left' => __( 'arrow-circle-left', 'wpvr' ),
76
- 'fas fa-arrow-circle-right' => __( 'arrow-circle-right', 'wpvr' ),
77
- 'fas fa-arrow-circle-up' => __( 'arrow-circle-up', 'wpvr' ),
78
- 'fas fa-arrow-down' => __( 'arrow-down', 'wpvr' ),
79
- 'fas fa-arrow-left' => __( 'arrow-left', 'wpvr' ),
80
- 'fas fa-arrow-right' => __( 'arrow-right', 'wpvr' ),
81
- 'fas fa-arrow-up' => __( 'arrow-up', 'wpvr' ),
82
- 'fas fa-arrows-alt' => __( 'arrows-alt', 'wpvr' ),
83
- 'fas fa-arrows-alt-h' => __( 'arrows-alt-h', 'wpvr' ),
84
- 'fas fa-arrows-alt-v' => __( 'arrows-alt-v', 'wpvr' ),
85
- 'fas fa-assistive-listening-systems' => __( 'assistive-listening-systems', 'wpvr' ),
86
- 'fas fa-asterisk' => __( 'asterisk', 'wpvr' ),
87
- 'fab fa-asymmetrik' => __( 'asymmetrik', 'wpvr' ),
88
- 'fas fa-at' => __( 'at', 'wpvr' ),
89
- 'fab fa-audible' => __( 'audible', 'wpvr' ),
90
- 'fas fa-audio-description' => __( 'audio-description', 'wpvr' ),
91
- 'fab fa-autoprefixer' => __( 'autoprefixer', 'wpvr' ),
92
- 'fab fa-avianex' => __( 'avianex', 'wpvr' ),
93
- 'fab fa-aviato' => __( 'aviato', 'wpvr' ),
94
- 'fab fa-aws' => __( 'aws', 'wpvr' ),
95
- 'fas fa-backward' => __( 'backward', 'wpvr' ),
96
- 'fas fa-balance-scale' => __( 'balance-scale', 'wpvr' ),
97
- 'fas fa-ban' => __( 'ban', 'wpvr' ),
98
- 'fas fa-band-aid' => __( 'band-aid', 'wpvr' ),
99
- 'fab fa-bandcamp' => __( 'bandcamp', 'wpvr' ),
100
- 'fas fa-barcode' => __( 'barcode', 'wpvr' ),
101
- 'fas fa-bars' => __( 'bars', 'wpvr' ),
102
- 'fas fa-baseball-ball' => __( 'baseball-ball', 'wpvr' ),
103
- 'fas fa-basketball-ball' => __( 'basketball-ball', 'wpvr' ),
104
- 'fas fa-bath' => __( 'bath', 'wpvr' ),
105
- 'fas fa-battery-empty' => __( 'battery-empty', 'wpvr' ),
106
- 'fas fa-battery-full' => __( 'battery-full', 'wpvr' ),
107
- 'fas fa-battery-half' => __( 'battery-half', 'wpvr' ),
108
- 'fas fa-battery-quarter' => __( 'battery-quarter', 'wpvr' ),
109
- 'fas fa-battery-three-quarters' => __( 'battery-three-quarters', 'wpvr' ),
110
- 'fas fa-bed' => __( 'bed', 'wpvr' ),
111
- 'fas fa-beer' => __( 'beer', 'wpvr' ),
112
- 'fab fa-behance' => __( 'behance', 'wpvr' ),
113
- 'fab fa-behance-square' => __( 'behance-square', 'wpvr' ),
114
- 'fas fa-bell' => __( 'bell', 'wpvr' ),
115
- 'far fa-bell' => __( 'bell', 'wpvr' ),
116
- 'fas fa-bell-slash' => __( 'bell-slash', 'wpvr' ),
117
- 'far fa-bell-slash' => __( 'bell-slash', 'wpvr' ),
118
- 'fas fa-bicycle' => __( 'bicycle', 'wpvr' ),
119
- 'fab fa-bimobject' => __( 'bimobject', 'wpvr' ),
120
- 'fas fa-binoculars' => __( 'binoculars', 'wpvr' ),
121
- 'fas fa-birthday-cake' => __( 'birthday-cake', 'wpvr' ),
122
- 'fab fa-bitbucket' => __( 'bitbucket', 'wpvr' ),
123
- 'fab fa-bitcoin' => __( 'bitcoin', 'wpvr' ),
124
- 'fab fa-bity' => __( 'bity', 'wpvr' ),
125
- 'fab fa-black-tie' => __( 'black-tie', 'wpvr' ),
126
- 'fab fa-blackberry' => __( 'blackberry', 'wpvr' ),
127
- 'fas fa-blind' => __( 'blind', 'wpvr' ),
128
- 'fab fa-blogger' => __( 'blogger', 'wpvr' ),
129
- 'fab fa-blogger-b' => __( 'blogger-b', 'wpvr' ),
130
- 'fab fa-bluetooth' => __( 'bluetooth', 'wpvr' ),
131
- 'fab fa-bluetooth-b' => __( 'bluetooth-b', 'wpvr' ),
132
- 'fas fa-bold' => __( 'bold', 'wpvr' ),
133
- 'fas fa-bolt' => __( 'bolt', 'wpvr' ),
134
- 'fas fa-bomb' => __( 'bomb', 'wpvr' ),
135
- 'fas fa-book' => __( 'book', 'wpvr' ),
136
- 'fas fa-bookmark' => __( 'bookmark', 'wpvr' ),
137
- 'far fa-bookmark' => __( 'bookmark', 'wpvr' ),
138
- 'fas fa-bowling-ball' => __( 'bowling-ball', 'wpvr' ),
139
- 'fas fa-box' => __( 'box', 'wpvr' ),
140
- 'fas fa-box-open' => __( 'box-open', 'wpvr' ),
141
- 'fas fa-boxes' => __( 'boxes', 'wpvr' ),
142
- 'fas fa-braille' => __( 'braille', 'wpvr' ),
143
- 'fas fa-briefcase' => __( 'briefcase', 'wpvr' ),
144
- 'fas fa-briefcase-medical' => __( 'briefcase-medical', 'wpvr' ),
145
- 'fab fa-btc' => __( 'btc', 'wpvr' ),
146
- 'fas fa-bug' => __( 'bug', 'wpvr' ),
147
- 'fas fa-building' => __( 'building', 'wpvr' ),
148
- 'far fa-building' => __( 'building', 'wpvr' ),
149
- 'fas fa-bullhorn' => __( 'bullhorn', 'wpvr' ),
150
- 'fas fa-bullseye' => __( 'bullseye', 'wpvr' ),
151
- 'fas fa-burn' => __( 'burn', 'wpvr' ),
152
- 'fab fa-buromobelexperte' => __( 'buromobelexperte', 'wpvr' ),
153
- 'fas fa-bus' => __( 'bus', 'wpvr' ),
154
- 'fab fa-buysellads' => __( 'buysellads', 'wpvr' ),
155
- 'fas fa-calculator' => __( 'calculator', 'wpvr' ),
156
- 'fas fa-calendar' => __( 'calendar', 'wpvr' ),
157
- 'far fa-calendar' => __( 'calendar', 'wpvr' ),
158
- 'fas fa-calendar-alt' => __( 'calendar-alt', 'wpvr' ),
159
- 'far fa-calendar-alt' => __( 'calendar-alt', 'wpvr' ),
160
- 'fas fa-calendar-check' => __( 'calendar-check', 'wpvr' ),
161
- 'far fa-calendar-check' => __( 'calendar-check', 'wpvr' ),
162
- 'fas fa-calendar-minus' => __( 'calendar-minus', 'wpvr' ),
163
- 'far fa-calendar-minus' => __( 'calendar-minus', 'wpvr' ),
164
- 'fas fa-calendar-plus' => __( 'calendar-plus', 'wpvr' ),
165
- 'far fa-calendar-plus' => __( 'calendar-plus', 'wpvr' ),
166
- 'fas fa-calendar-times' => __( 'calendar-times', 'wpvr' ),
167
- 'far fa-calendar-times' => __( 'calendar-times', 'wpvr' ),
168
- 'fas fa-camera' => __( 'camera', 'wpvr' ),
169
- 'fas fa-camera-retro' => __( 'camera-retro', 'wpvr' ),
170
- 'fas fa-capsules' => __( 'capsules', 'wpvr' ),
171
- 'fas fa-car' => __( 'car', 'wpvr' ),
172
- 'fas fa-caret-down' => __( 'caret-down', 'wpvr' ),
173
- 'fas fa-caret-left' => __( 'caret-left', 'wpvr' ),
174
- 'fas fa-caret-right' => __( 'caret-right', 'wpvr' ),
175
- 'fas fa-caret-square-down' => __( 'caret-square-down', 'wpvr' ),
176
- 'far fa-caret-square-down' => __( 'caret-square-down', 'wpvr' ),
177
- 'fas fa-caret-square-left' => __( 'caret-square-left', 'wpvr' ),
178
- 'far fa-caret-square-left' => __( 'caret-square-left', 'wpvr' ),
179
- 'fas fa-caret-square-right' => __( 'caret-square-right', 'wpvr' ),
180
- 'far fa-caret-square-right' => __( 'caret-square-right', 'wpvr' ),
181
- 'fas fa-caret-square-up' => __( 'caret-square-up', 'wpvr' ),
182
- 'far fa-caret-square-up' => __( 'caret-square-up', 'wpvr' ),
183
- 'fas fa-caret-up' => __( 'caret-up', 'wpvr' ),
184
- 'fas fa-cart-arrow-down' => __( 'cart-arrow-down', 'wpvr' ),
185
- 'fas fa-cart-plus' => __( 'cart-plus', 'wpvr' ),
186
- 'fab fa-cc-amazon-pay' => __( 'cc-amazon-pay', 'wpvr' ),
187
- 'fab fa-cc-amex' => __( 'cc-amex', 'wpvr' ),
188
- 'fab fa-cc-apple-pay' => __( 'cc-apple-pay', 'wpvr' ),
189
- 'fab fa-cc-diners-club' => __( 'cc-diners-club', 'wpvr' ),
190
- 'fab fa-cc-discover' => __( 'cc-discover', 'wpvr' ),
191
- 'fab fa-cc-jcb' => __( 'cc-jcb', 'wpvr' ),
192
- 'fab fa-cc-mastercard' => __( 'cc-mastercard', 'wpvr' ),
193
- 'fab fa-cc-paypal' => __( 'cc-paypal', 'wpvr' ),
194
- 'fab fa-cc-stripe' => __( 'cc-stripe', 'wpvr' ),
195
- 'fab fa-cc-visa' => __( 'cc-visa', 'wpvr' ),
196
- 'fab fa-centercode' => __( 'centercode', 'wpvr' ),
197
- 'fas fa-certificate' => __( 'certificate', 'wpvr' ),
198
- 'fas fa-chart-area' => __( 'chart-area', 'wpvr' ),
199
- 'fas fa-chart-bar' => __( 'chart-bar', 'wpvr' ),
200
- 'far fa-chart-bar' => __( 'chart-bar', 'wpvr' ),
201
- 'fas fa-chart-line' => __( 'chart-line', 'wpvr' ),
202
- 'fas fa-chart-pie' => __( 'chart-pie', 'wpvr' ),
203
- 'fas fa-check' => __( 'check', 'wpvr' ),
204
- 'fas fa-check-circle' => __( 'check-circle', 'wpvr' ),
205
- 'far fa-check-circle' => __( 'check-circle', 'wpvr' ),
206
- 'fas fa-check-square' => __( 'check-square', 'wpvr' ),
207
- 'far fa-check-square' => __( 'check-square', 'wpvr' ),
208
- 'fas fa-chess' => __( 'chess', 'wpvr' ),
209
- 'fas fa-chess-bishop' => __( 'chess-bishop', 'wpvr' ),
210
- 'fas fa-chess-board' => __( 'chess-board', 'wpvr' ),
211
- 'fas fa-chess-king' => __( 'chess-king', 'wpvr' ),
212
- 'fas fa-chess-knight' => __( 'chess-knight', 'wpvr' ),
213
- 'fas fa-chess-pawn' => __( 'chess-pawn', 'wpvr' ),
214
- 'fas fa-chess-queen' => __( 'chess-queen', 'wpvr' ),
215
- 'fas fa-chess-rook' => __( 'chess-rook', 'wpvr' ),
216
- 'fas fa-chevron-circle-down' => __( 'chevron-circle-down', 'wpvr' ),
217
- 'fas fa-chevron-circle-left' => __( 'chevron-circle-left', 'wpvr' ),
218
- 'fas fa-chevron-circle-right' => __( 'chevron-circle-right', 'wpvr' ),
219
- 'fas fa-chevron-circle-up' => __( 'chevron-circle-up', 'wpvr' ),
220
- 'fas fa-chevron-down' => __( 'chevron-down', 'wpvr' ),
221
- 'fas fa-chevron-left' => __( 'chevron-left', 'wpvr' ),
222
- 'fas fa-chevron-right' => __( 'chevron-right', 'wpvr' ),
223
- 'fas fa-chevron-up' => __( 'chevron-up', 'wpvr' ),
224
- 'fas fa-child' => __( 'child', 'wpvr' ),
225
- 'fab fa-chrome' => __( 'chrome', 'wpvr' ),
226
- 'fas fa-circle' => __( 'circle', 'wpvr' ),
227
- 'far fa-circle' => __( 'circle', 'wpvr' ),
228
- 'fas fa-circle-notch' => __( 'circle-notch', 'wpvr' ),
229
- 'fas fa-clipboard' => __( 'clipboard', 'wpvr' ),
230
- 'far fa-clipboard' => __( 'clipboard', 'wpvr' ),
231
- 'fas fa-clipboard-check' => __( 'clipboard-check', 'wpvr' ),
232
- 'fas fa-clipboard-list' => __( 'clipboard-list', 'wpvr' ),
233
- 'fas fa-clock' => __( 'clock', 'wpvr' ),
234
- 'far fa-clock' => __( 'clock', 'wpvr' ),
235
- 'fas fa-clone' => __( 'clone', 'wpvr' ),
236
- 'far fa-clone' => __( 'clone', 'wpvr' ),
237
- 'fas fa-closed-captioning' => __( 'closed-captioning', 'wpvr' ),
238
- 'far fa-closed-captioning' => __( 'closed-captioning', 'wpvr' ),
239
- 'fas fa-cloud' => __( 'cloud', 'wpvr' ),
240
- 'fas fa-cloud-download-alt' => __( 'cloud-download-alt', 'wpvr' ),
241
- 'fas fa-cloud-upload-alt' => __( 'cloud-upload-alt', 'wpvr' ),
242
- 'fab fa-cloudscale' => __( 'cloudscale', 'wpvr' ),
243
- 'fab fa-cloudsmith' => __( 'cloudsmith', 'wpvr' ),
244
- 'fab fa-cloudversify' => __( 'cloudversify', 'wpvr' ),
245
- 'fas fa-code' => __( 'code', 'wpvr' ),
246
- 'fas fa-code-branch' => __( 'code-branch', 'wpvr' ),
247
- 'fab fa-codepen' => __( 'codepen', 'wpvr' ),
248
- 'fab fa-codiepie' => __( 'codiepie', 'wpvr' ),
249
- 'fas fa-coffee' => __( 'coffee', 'wpvr' ),
250
- 'fas fa-cog' => __( 'cog', 'wpvr' ),
251
- 'fas fa-cogs' => __( 'cogs', 'wpvr' ),
252
- 'fas fa-columns' => __( 'columns', 'wpvr' ),
253
- 'fas fa-comment' => __( 'comment', 'wpvr' ),
254
- 'far fa-comment' => __( 'comment', 'wpvr' ),
255
- 'fas fa-comment-alt' => __( 'comment-alt', 'wpvr' ),
256
- 'far fa-comment-alt' => __( 'comment-alt', 'wpvr' ),
257
- 'fas fa-comment-dots' => __( 'comment-dots', 'wpvr' ),
258
- 'fas fa-comment-slash' => __( 'comment-slash', 'wpvr' ),
259
- 'fas fa-comments' => __( 'comments', 'wpvr' ),
260
- 'far fa-comments' => __( 'comments', 'wpvr' ),
261
- 'fas fa-compass' => __( 'compass', 'wpvr' ),
262
- 'far fa-compass' => __( 'compass', 'wpvr' ),
263
- 'fas fa-compress' => __( 'compress', 'wpvr' ),
264
- 'fab fa-connectdevelop' => __( 'connectdevelop', 'wpvr' ),
265
- 'fab fa-contao' => __( 'contao', 'wpvr' ),
266
- 'fas fa-copy' => __( 'copy', 'wpvr' ),
267
- 'far fa-copy' => __( 'copy', 'wpvr' ),
268
- 'fas fa-copyright' => __( 'copyright', 'wpvr' ),
269
- 'far fa-copyright' => __( 'copyright', 'wpvr' ),
270
- 'fas fa-couch' => __( 'couch', 'wpvr' ),
271
- 'fab fa-cpanel' => __( 'cpanel', 'wpvr' ),
272
- 'fab fa-creative-commons' => __( 'creative-commons', 'wpvr' ),
273
- 'fas fa-credit-card' => __( 'credit-card', 'wpvr' ),
274
- 'far fa-credit-card' => __( 'credit-card', 'wpvr' ),
275
- 'fas fa-crop' => __( 'crop', 'wpvr' ),
276
- 'fas fa-crosshairs' => __( 'crosshairs', 'wpvr' ),
277
- 'fab fa-css3' => __( 'css3', 'wpvr' ),
278
- 'fab fa-css3-alt' => __( 'css3-alt', 'wpvr' ),
279
- 'fas fa-cube' => __( 'cube', 'wpvr' ),
280
- 'fas fa-cubes' => __( 'cubes', 'wpvr' ),
281
- 'fas fa-cut' => __( 'cut', 'wpvr' ),
282
- 'fab fa-cuttlefish' => __( 'cuttlefish', 'wpvr' ),
283
- 'fab fa-d-and-d' => __( 'd-and-d', 'wpvr' ),
284
- 'fab fa-dashcube' => __( 'dashcube', 'wpvr' ),
285
- 'fas fa-database' => __( 'database', 'wpvr' ),
286
- 'fas fa-deaf' => __( 'deaf', 'wpvr' ),
287
- 'fab fa-delicious' => __( 'delicious', 'wpvr' ),
288
- 'fab fa-deploydog' => __( 'deploydog', 'wpvr' ),
289
- 'fab fa-deskpro' => __( 'deskpro', 'wpvr' ),
290
- 'fas fa-desktop' => __( 'desktop', 'wpvr' ),
291
- 'fab fa-deviantart' => __( 'deviantart', 'wpvr' ),
292
- 'fas fa-diagnoses' => __( 'diagnoses', 'wpvr' ),
293
- 'fab fa-digg' => __( 'digg', 'wpvr' ),
294
- 'fab fa-digital-ocean' => __( 'digital-ocean', 'wpvr' ),
295
- 'fab fa-discord' => __( 'discord', 'wpvr' ),
296
- 'fab fa-discourse' => __( 'discourse', 'wpvr' ),
297
- 'fas fa-dna' => __( 'dna', 'wpvr' ),
298
- 'fab fa-dochub' => __( 'dochub', 'wpvr' ),
299
- 'fab fa-docker' => __( 'docker', 'wpvr' ),
300
- 'fas fa-dollar-sign' => __( 'dollar-sign', 'wpvr' ),
301
- 'fas fa-dolly' => __( 'dolly', 'wpvr' ),
302
- 'fas fa-dolly-flatbed' => __( 'dolly-flatbed', 'wpvr' ),
303
- 'fas fa-donate' => __( 'donate', 'wpvr' ),
304
- 'fas fa-dot-circle' => __( 'dot-circle', 'wpvr' ),
305
- 'far fa-dot-circle' => __( 'dot-circle', 'wpvr' ),
306
- 'fas fa-dove' => __( 'dove', 'wpvr' ),
307
- 'fas fa-download' => __( 'download', 'wpvr' ),
308
- 'fab fa-draft2digital' => __( 'draft2digital', 'wpvr' ),
309
- 'fab fa-dribbble' => __( 'dribbble', 'wpvr' ),
310
- 'fab fa-dribbble-square' => __( 'dribbble-square', 'wpvr' ),
311
- 'fab fa-dropbox' => __( 'dropbox', 'wpvr' ),
312
- 'fab fa-drupal' => __( 'drupal', 'wpvr' ),
313
- 'fab fa-dyalog' => __( 'dyalog', 'wpvr' ),
314
- 'fab fa-earlybirds' => __( 'earlybirds', 'wpvr' ),
315
- 'fab fa-edge' => __( 'edge', 'wpvr' ),
316
- 'fas fa-edit' => __( 'edit', 'wpvr' ),
317
- 'far fa-edit' => __( 'edit', 'wpvr' ),
318
- 'fas fa-eject' => __( 'eject', 'wpvr' ),
319
- 'fab fa-elementor' => __( 'elementor', 'wpvr' ),
320
- 'fas fa-ellipsis-h' => __( 'ellipsis-h', 'wpvr' ),
321
- 'fas fa-ellipsis-v' => __( 'ellipsis-v', 'wpvr' ),
322
- 'fab fa-ember' => __( 'ember', 'wpvr' ),
323
- 'fab fa-empire' => __( 'empire', 'wpvr' ),
324
- 'fas fa-envelope' => __( 'envelope', 'wpvr' ),
325
- 'far fa-envelope' => __( 'envelope', 'wpvr' ),
326
- 'fas fa-envelope-open' => __( 'envelope-open', 'wpvr' ),
327
- 'far fa-envelope-open' => __( 'envelope-open', 'wpvr' ),
328
- 'fas fa-envelope-square' => __( 'envelope-square', 'wpvr' ),
329
- 'fab fa-envira' => __( 'envira', 'wpvr' ),
330
- 'fas fa-eraser' => __( 'eraser', 'wpvr' ),
331
- 'fab fa-erlang' => __( 'erlang', 'wpvr' ),
332
- 'fab fa-ethereum' => __( 'ethereum', 'wpvr' ),
333
- 'fab fa-etsy' => __( 'etsy', 'wpvr' ),
334
- 'fas fa-euro-sign' => __( 'euro-sign', 'wpvr' ),
335
- 'fas fa-exchange-alt' => __( 'exchange-alt', 'wpvr' ),
336
- 'fas fa-exclamation' => __( 'exclamation', 'wpvr' ),
337
- 'fas fa-exclamation-circle' => __( 'exclamation-circle', 'wpvr' ),
338
- 'fas fa-exclamation-triangle' => __( 'exclamation-triangle', 'wpvr' ),
339
- 'fas fa-expand' => __( 'expand', 'wpvr' ),
340
- 'fas fa-expand-arrows-alt' => __( 'expand-arrows-alt', 'wpvr' ),
341
- 'fab fa-expeditedssl' => __( 'expeditedssl', 'wpvr' ),
342
- 'fas fa-external-link-alt' => __( 'external-link-alt', 'wpvr' ),
343
- 'fas fa-external-link-square-alt' => __( 'external-link-square-alt', 'wpvr' ),
344
- 'fas fa-eye' => __( 'eye', 'wpvr' ),
345
- 'fas fa-eye-dropper' => __( 'eye-dropper', 'wpvr' ),
346
- 'fas fa-eye-slash' => __( 'eye-slash', 'wpvr' ),
347
- 'far fa-eye-slash' => __( 'eye-slash', 'wpvr' ),
348
- 'fab fa-facebook' => __( 'facebook', 'wpvr' ),
349
- 'fab fa-facebook-f' => __( 'facebook-f', 'wpvr' ),
350
- 'fab fa-facebook-messenger' => __( 'facebook-messenger', 'wpvr' ),
351
- 'fab fa-facebook-square' => __( 'facebook-square', 'wpvr' ),
352
- 'fas fa-fast-backward' => __( 'fast-backward', 'wpvr' ),
353
- 'fas fa-fast-forward' => __( 'fast-forward', 'wpvr' ),
354
- 'fas fa-fax' => __( 'fax', 'wpvr' ),
355
- 'fas fa-female' => __( 'female', 'wpvr' ),
356
- 'fas fa-fighter-jet' => __( 'fighter-jet', 'wpvr' ),
357
- 'fas fa-file' => __( 'file', 'wpvr' ),
358
- 'far fa-file' => __( 'file', 'wpvr' ),
359
- 'fas fa-file-alt' => __( 'file-alt', 'wpvr' ),
360
- 'far fa-file-alt' => __( 'file-alt', 'wpvr' ),
361
- 'fas fa-file-archive' => __( 'file-archive', 'wpvr' ),
362
- 'far fa-file-archive' => __( 'file-archive', 'wpvr' ),
363
- 'fas fa-file-audio' => __( 'file-audio', 'wpvr' ),
364
- 'far fa-file-audio' => __( 'file-audio', 'wpvr' ),
365
- 'fas fa-file-code' => __( 'file-code', 'wpvr' ),
366
- 'far fa-file-code' => __( 'file-code', 'wpvr' ),
367
- 'fas fa-file-excel' => __( 'file-excel', 'wpvr' ),
368
- 'far fa-file-excel' => __( 'file-excel', 'wpvr' ),
369
- 'fas fa-file-image' => __( 'file-image', 'wpvr' ),
370
- 'far fa-file-image' => __( 'file-image', 'wpvr' ),
371
- 'fas fa-file-medical' => __( 'file-medical', 'wpvr' ),
372
- 'fas fa-file-medical-alt' => __( 'file-medical-alt', 'wpvr' ),
373
- 'fas fa-file-pdf' => __( 'file-pdf', 'wpvr' ),
374
- 'far fa-file-pdf' => __( 'file-pdf', 'wpvr' ),
375
- 'fas fa-file-powerpoint' => __( 'file-powerpoint', 'wpvr' ),
376
- 'far fa-file-powerpoint' => __( 'file-powerpoint', 'wpvr' ),
377
- 'fas fa-file-video' => __( 'file-video', 'wpvr' ),
378
- 'far fa-file-video' => __( 'file-video', 'wpvr' ),
379
- 'fas fa-file-word' => __( 'file-word', 'wpvr' ),
380
- 'far fa-file-word' => __( 'file-word', 'wpvr' ),
381
- 'fas fa-film' => __( 'film', 'wpvr' ),
382
- 'fas fa-filter' => __( 'filter', 'wpvr' ),
383
- 'fas fa-fire' => __( 'fire', 'wpvr' ),
384
- 'fas fa-fire-extinguisher' => __( 'fire-extinguisher', 'wpvr' ),
385
- 'fab fa-firefox' => __( 'firefox', 'wpvr' ),
386
- 'fas fa-first-aid' => __( 'first-aid', 'wpvr' ),
387
- 'fab fa-first-order' => __( 'first-order', 'wpvr' ),
388
- 'fab fa-firstdraft' => __( 'firstdraft', 'wpvr' ),
389
- 'fas fa-flag' => __( 'flag', 'wpvr' ),
390
- 'far fa-flag' => __( 'flag', 'wpvr' ),
391
- 'fas fa-flag-checkered' => __( 'flag-checkered', 'wpvr' ),
392
- 'fas fa-flask' => __( 'flask', 'wpvr' ),
393
- 'fab fa-flickr' => __( 'flickr', 'wpvr' ),
394
- 'fab fa-flipboard' => __( 'flipboard', 'wpvr' ),
395
- 'fab fa-fly' => __( 'fly', 'wpvr' ),
396
- 'fas fa-folder' => __( 'folder', 'wpvr' ),
397
- 'far fa-folder' => __( 'folder', 'wpvr' ),
398
- 'fas fa-folder-open' => __( 'folder-open', 'wpvr' ),
399
- 'far fa-folder-open' => __( 'folder-open', 'wpvr' ),
400
- 'fas fa-font' => __( 'font', 'wpvr' ),
401
- 'fab fa-font-awesome' => __( 'font-awesome', 'wpvr' ),
402
- 'fab fa-font-awesome-alt' => __( 'font-awesome-alt', 'wpvr' ),
403
- 'fab fa-font-awesome-flag' => __( 'font-awesome-flag', 'wpvr' ),
404
- 'fab fa-fonticons' => __( 'fonticons', 'wpvr' ),
405
- 'fab fa-fonticons-fi' => __( 'fonticons-fi', 'wpvr' ),
406
- 'fas fa-football-ball' => __( 'football-ball', 'wpvr' ),
407
- 'fab fa-fort-awesome' => __( 'fort-awesome', 'wpvr' ),
408
- 'fab fa-fort-awesome-alt' => __( 'fort-awesome-alt', 'wpvr' ),
409
- 'fab fa-forumbee' => __( 'forumbee', 'wpvr' ),
410
- 'fas fa-forward' => __( 'forward', 'wpvr' ),
411
- 'fab fa-foursquare' => __( 'foursquare', 'wpvr' ),
412
- 'fab fa-free-code-camp' => __( 'free-code-camp', 'wpvr' ),
413
- 'fab fa-freebsd' => __( 'freebsd', 'wpvr' ),
414
- 'fas fa-frown' => __( 'frown', 'wpvr' ),
415
- 'far fa-frown' => __( 'frown', 'wpvr' ),
416
- 'fas fa-futbol' => __( 'futbol', 'wpvr' ),
417
- 'far fa-futbol' => __( 'futbol', 'wpvr' ),
418
- 'fas fa-gamepad' => __( 'gamepad', 'wpvr' ),
419
- 'fas fa-gavel' => __( 'gavel', 'wpvr' ),
420
- 'fas fa-gem' => __( 'gem', 'wpvr' ),
421
- 'far fa-gem' => __( 'gem', 'wpvr' ),
422
- 'fas fa-genderless' => __( 'genderless', 'wpvr' ),
423
- 'fab fa-get-pocket' => __( 'get-pocket', 'wpvr' ),
424
- 'fab fa-gg' => __( 'gg', 'wpvr' ),
425
- 'fab fa-gg-circle' => __( 'gg-circle', 'wpvr' ),
426
- 'fas fa-gift' => __( 'gift', 'wpvr' ),
427
- 'fab fa-git' => __( 'git', 'wpvr' ),
428
- 'fab fa-git-square' => __( 'git-square', 'wpvr' ),
429
- 'fab fa-github' => __( 'github', 'wpvr' ),
430
- 'fab fa-github-alt' => __( 'github-alt', 'wpvr' ),
431
- 'fab fa-github-square' => __( 'github-square', 'wpvr' ),
432
- 'fab fa-gitkraken' => __( 'gitkraken', 'wpvr' ),
433
- 'fab fa-gitlab' => __( 'gitlab', 'wpvr' ),
434
- 'fab fa-gitter' => __( 'gitter', 'wpvr' ),
435
- 'fas fa-glass-martini' => __( 'glass-martini', 'wpvr' ),
436
- 'fab fa-glide' => __( 'glide', 'wpvr' ),
437
- 'fab fa-glide-g' => __( 'glide-g', 'wpvr' ),
438
- 'fas fa-globe' => __( 'globe', 'wpvr' ),
439
- 'fab fa-gofore' => __( 'gofore', 'wpvr' ),
440
- 'fas fa-golf-ball' => __( 'golf-ball', 'wpvr' ),
441
- 'fab fa-goodreads' => __( 'goodreads', 'wpvr' ),
442
- 'fab fa-goodreads-g' => __( 'goodreads-g', 'wpvr' ),
443
- 'fab fa-google' => __( 'google', 'wpvr' ),
444
- 'fab fa-google-drive' => __( 'google-drive', 'wpvr' ),
445
- 'fab fa-google-play' => __( 'google-play', 'wpvr' ),
446
- 'fab fa-google-plus' => __( 'google-plus', 'wpvr' ),
447
- 'fab fa-google-plus-g' => __( 'google-plus-g', 'wpvr' ),
448
- 'fab fa-google-plus-square' => __( 'google-plus-square', 'wpvr' ),
449
- 'fab fa-google-wallet' => __( 'google-wallet', 'wpvr' ),
450
- 'fas fa-graduation-cap' => __( 'graduation-cap', 'wpvr' ),
451
- 'fab fa-gratipay' => __( 'gratipay', 'wpvr' ),
452
- 'fab fa-grav' => __( 'grav', 'wpvr' ),
453
- 'fab fa-gripfire' => __( 'gripfire', 'wpvr' ),
454
- 'fab fa-grunt' => __( 'grunt', 'wpvr' ),
455
- 'fab fa-gulp' => __( 'gulp', 'wpvr' ),
456
- 'fas fa-h-square' => __( 'h-square', 'wpvr' ),
457
- 'fab fa-hacker-news' => __( 'hacker-news', 'wpvr' ),
458
- 'fab fa-hacker-news-square' => __( 'hacker-news-square', 'wpvr' ),
459
- 'fas fa-hand-holding' => __( 'hand-holding', 'wpvr' ),
460
- 'fas fa-hand-holding-heart' => __( 'hand-holding-heart', 'wpvr' ),
461
- 'fas fa-hand-holding-usd' => __( 'hand-holding-usd', 'wpvr' ),
462
- 'fas fa-hand-lizard' => __( 'hand-lizard', 'wpvr' ),
463
- 'far fa-hand-lizard' => __( 'hand-lizard', 'wpvr' ),
464
- 'fas fa-hand-paper' => __( 'hand-paper', 'wpvr' ),
465
- 'far fa-hand-paper' => __( 'hand-paper', 'wpvr' ),
466
- 'fas fa-hand-peace' => __( 'hand-peace', 'wpvr' ),
467
- 'far fa-hand-peace' => __( 'hand-peace', 'wpvr' ),
468
- 'fas fa-hand-point-down' => __( 'hand-point-down', 'wpvr' ),
469
- 'far fa-hand-point-down' => __( 'hand-point-down', 'wpvr' ),
470
- 'fas fa-hand-point-left' => __( 'hand-point-left', 'wpvr' ),
471
- 'far fa-hand-point-left' => __( 'hand-point-left', 'wpvr' ),
472
- 'fas fa-hand-point-right' => __( 'hand-point-right', 'wpvr' ),
473
- 'far fa-hand-point-right' => __( 'hand-point-right', 'wpvr' ),
474
- 'fas fa-hand-point-up' => __( 'hand-point-up', 'wpvr' ),
475
- 'far fa-hand-point-up' => __( 'hand-point-up', 'wpvr' ),
476
- 'fas fa-hand-pointer' => __( 'hand-pointer', 'wpvr' ),
477
- 'far fa-hand-pointer' => __( 'hand-pointer', 'wpvr' ),
478
- 'fas fa-hand-rock' => __( 'hand-rock', 'wpvr' ),
479
- 'far fa-hand-rock' => __( 'hand-rock', 'wpvr' ),
480
- 'fas fa-hand-scissors' => __( 'hand-scissors', 'wpvr' ),
481
- 'far fa-hand-scissors' => __( 'hand-scissors', 'wpvr' ),
482
- 'fas fa-hand-spock' => __( 'hand-spock', 'wpvr' ),
483
- 'far fa-hand-spock' => __( 'hand-spock', 'wpvr' ),
484
- 'fas fa-hands' => __( 'hands', 'wpvr' ),
485
- 'fas fa-hands-helping' => __( 'hands-helping', 'wpvr' ),
486
- 'fas fa-handshake' => __( 'handshake', 'wpvr' ),
487
- 'far fa-handshake' => __( 'handshake', 'wpvr' ),
488
- 'fas fa-hashtag' => __( 'hashtag', 'wpvr' ),
489
- 'fas fa-hdd' => __( 'hdd', 'wpvr' ),
490
- 'far fa-hdd' => __( 'hdd', 'wpvr' ),
491
- 'fas fa-heading' => __( 'heading', 'wpvr' ),
492
- 'fas fa-headphones' => __( 'headphones', 'wpvr' ),
493
- 'fas fa-heart' => __( 'heart', 'wpvr' ),
494
- 'far fa-heart' => __( 'heart', 'wpvr' ),
495
- 'fas fa-heartbeat' => __( 'heartbeat', 'wpvr' ),
496
- 'fab fa-hips' => __( 'hips', 'wpvr' ),
497
- 'fab fa-hire-a-helper' => __( 'hire-a-helper', 'wpvr' ),
498
- 'fas fa-history' => __( 'history', 'wpvr' ),
499
- 'fas fa-hockey-puck' => __( 'hockey-puck', 'wpvr' ),
500
- 'fas fa-home' => __( 'home', 'wpvr' ),
501
- 'fab fa-hooli' => __( 'hooli', 'wpvr' ),
502
- 'fas fa-hospital' => __( 'hospital', 'wpvr' ),
503
- 'far fa-hospital' => __( 'hospital', 'wpvr' ),
504
- 'fas fa-hospital-alt' => __( 'hospital-alt', 'wpvr' ),
505
- 'fas fa-hospital-symbol' => __( 'hospital-symbol', 'wpvr' ),
506
- 'fab fa-hotjar' => __( 'hotjar', 'wpvr' ),
507
- 'fas fa-hourglass' => __( 'hourglass', 'wpvr' ),
508
- 'far fa-hourglass' => __( 'hourglass', 'wpvr' ),
509
- 'fas fa-hourglass-end' => __( 'hourglass-end', 'wpvr' ),
510
- 'fas fa-hourglass-half' => __( 'hourglass-half', 'wpvr' ),
511
- 'fas fa-hourglass-start' => __( 'hourglass-start', 'wpvr' ),
512
- 'fab fa-houzz' => __( 'houzz', 'wpvr' ),
513
- 'fab fa-html5' => __( 'html5', 'wpvr' ),
514
- 'fab fa-hubspot' => __( 'hubspot', 'wpvr' ),
515
- 'fas fa-i-cursor' => __( 'i-cursor', 'wpvr' ),
516
- 'fas fa-id-badge' => __( 'id-badge', 'wpvr' ),
517
- 'far fa-id-badge' => __( 'id-badge', 'wpvr' ),
518
- 'fas fa-id-card' => __( 'id-card', 'wpvr' ),
519
- 'far fa-id-card' => __( 'id-card', 'wpvr' ),
520
- 'fas fa-id-card-alt' => __( 'id-card-alt', 'wpvr' ),
521
- 'fas fa-image' => __( 'image', 'wpvr' ),
522
- 'far fa-image' => __( 'image', 'wpvr' ),
523
- 'fas fa-images' => __( 'images', 'wpvr' ),
524
- 'far fa-images' => __( 'images', 'wpvr' ),
525
- 'fab fa-imdb' => __( 'imdb', 'wpvr' ),
526
- 'fas fa-inbox' => __( 'inbox', 'wpvr' ),
527
- 'fas fa-indent' => __( 'indent', 'wpvr' ),
528
- 'fas fa-industry' => __( 'industry', 'wpvr' ),
529
- 'fas fa-info' => __( 'info', 'wpvr' ),
530
- 'fas fa-info-circle' => __( 'info-circle', 'wpvr' ),
531
- 'fab fa-instagram' => __( 'instagram', 'wpvr' ),
532
- 'fab fa-internet-explorer' => __( 'internet-explorer', 'wpvr' ),
533
- 'fab fa-ioxhost' => __( 'ioxhost', 'wpvr' ),
534
- 'fas fa-italic' => __( 'italic', 'wpvr' ),
535
- 'fab fa-itunes' => __( 'itunes', 'wpvr' ),
536
- 'fab fa-itunes-note' => __( 'itunes-note', 'wpvr' ),
537
- 'fab fa-java' => __( 'java', 'wpvr' ),
538
- 'fab fa-jenkins' => __( 'jenkins', 'wpvr' ),
539
- 'fab fa-joget' => __( 'joget', 'wpvr' ),
540
- 'fab fa-joomla' => __( 'joomla', 'wpvr' ),
541
- 'fab fa-js' => __( 'js', 'wpvr' ),
542
- 'fab fa-js-square' => __( 'js-square', 'wpvr' ),
543
- 'fab fa-jsfiddle' => __( 'jsfiddle', 'wpvr' ),
544
- 'fas fa-key' => __( 'key', 'wpvr' ),
545
- 'fas fa-keyboard' => __( 'keyboard', 'wpvr' ),
546
- 'far fa-keyboard' => __( 'keyboard', 'wpvr' ),
547
- 'fab fa-keycdn' => __( 'keycdn', 'wpvr' ),
548
- 'fab fa-kickstarter' => __( 'kickstarter', 'wpvr' ),
549
- 'fab fa-kickstarter-k' => __( 'kickstarter-k', 'wpvr' ),
550
- 'fab fa-korvue' => __( 'korvue', 'wpvr' ),
551
- 'fas fa-language' => __( 'language', 'wpvr' ),
552
- 'fas fa-laptop' => __( 'laptop', 'wpvr' ),
553
- 'fab fa-laravel' => __( 'laravel', 'wpvr' ),
554
- 'fab fa-lastfm' => __( 'lastfm', 'wpvr' ),
555
- 'fab fa-lastfm-square' => __( 'lastfm-square', 'wpvr' ),
556
- 'fas fa-leaf' => __( 'leaf', 'wpvr' ),
557
- 'fab fa-leanpub' => __( 'leanpub', 'wpvr' ),
558
- 'fas fa-lemon' => __( 'lemon', 'wpvr' ),
559
- 'far fa-lemon' => __( 'lemon', 'wpvr' ),
560
- 'fab fa-less' => __( 'less', 'wpvr' ),
561
- 'fas fa-level-down-alt' => __( 'level-down-alt', 'wpvr' ),
562
- 'fas fa-level-up-alt' => __( 'level-up-alt', 'wpvr' ),
563
- 'fas fa-life-ring' => __( 'life-ring', 'wpvr' ),
564
- 'far fa-life-ring' => __( 'life-ring', 'wpvr' ),
565
- 'fas fa-lightbulb' => __( 'lightbulb', 'wpvr' ),
566
- 'far fa-lightbulb' => __( 'lightbulb', 'wpvr' ),
567
- 'fab fa-line' => __( 'line', 'wpvr' ),
568
- 'fas fa-link' => __( 'link', 'wpvr' ),
569
- 'fab fa-linkedin' => __( 'linkedin', 'wpvr' ),
570
- 'fab fa-linkedin-in' => __( 'linkedin-in', 'wpvr' ),
571
- 'fab fa-linode' => __( 'linode', 'wpvr' ),
572
- 'fab fa-linux' => __( 'linux', 'wpvr' ),
573
- 'fas fa-lira-sign' => __( 'lira-sign', 'wpvr' ),
574
- 'fas fa-list' => __( 'list', 'wpvr' ),
575
- 'fas fa-list-alt' => __( 'list-alt', 'wpvr' ),
576
- 'far fa-list-alt' => __( 'list-alt', 'wpvr' ),
577
- 'fas fa-list-ol' => __( 'list-ol', 'wpvr' ),
578
- 'fas fa-list-ul' => __( 'list-ul', 'wpvr' ),
579
- 'fas fa-location-arrow' => __( 'location-arrow', 'wpvr' ),
580
- 'fas fa-lock' => __( 'lock', 'wpvr' ),
581
- 'fas fa-lock-open' => __( 'lock-open', 'wpvr' ),
582
- 'fas fa-long-arrow-alt-down' => __( 'long-arrow-alt-down', 'wpvr' ),
583
- 'fas fa-long-arrow-alt-left' => __( 'long-arrow-alt-left', 'wpvr' ),
584
- 'fas fa-long-arrow-alt-right' => __( 'long-arrow-alt-right', 'wpvr' ),
585
- 'fas fa-long-arrow-alt-up' => __( 'long-arrow-alt-up', 'wpvr' ),
586
- 'fas fa-low-vision' => __( 'low-vision', 'wpvr' ),
587
- 'fab fa-lyft' => __( 'lyft', 'wpvr' ),
588
- 'fab fa-magento' => __( 'magento', 'wpvr' ),
589
- 'fas fa-magic' => __( 'magic', 'wpvr' ),
590
- 'fas fa-magnet' => __( 'magnet', 'wpvr' ),
591
- 'fas fa-male' => __( 'male', 'wpvr' ),
592
- 'fas fa-map' => __( 'map', 'wpvr' ),
593
- 'far fa-map' => __( 'map', 'wpvr' ),
594
- 'fas fa-map-marker' => __( 'map-marker', 'wpvr' ),
595
- 'fas fa-map-marker-alt' => __( 'map-marker-alt', 'wpvr' ),
596
- 'fas fa-map-pin' => __( 'map-pin', 'wpvr' ),
597
- 'fas fa-map-signs' => __( 'map-signs', 'wpvr' ),
598
- 'fas fa-mars' => __( 'mars', 'wpvr' ),
599
- 'fas fa-mars-double' => __( 'mars-double', 'wpvr' ),
600
- 'fas fa-mars-stroke' => __( 'mars-stroke', 'wpvr' ),
601
- 'fas fa-mars-stroke-h' => __( 'mars-stroke-h', 'wpvr' ),
602
- 'fas fa-mars-stroke-v' => __( 'mars-stroke-v', 'wpvr' ),
603
- 'fab fa-maxcdn' => __( 'maxcdn', 'wpvr' ),
604
- 'fab fa-medapps' => __( 'medapps', 'wpvr' ),
605
- 'fab fa-medium' => __( 'medium', 'wpvr' ),
606
- 'fab fa-medium-m' => __( 'medium-m', 'wpvr' ),
607
- 'fas fa-medkit' => __( 'medkit', 'wpvr' ),
608
- 'fab fa-medrt' => __( 'medrt', 'wpvr' ),
609
- 'fab fa-meetup' => __( 'meetup', 'wpvr' ),
610
- 'fas fa-meh' => __( 'meh', 'wpvr' ),
611
- 'far fa-meh' => __( 'meh', 'wpvr' ),
612
- 'fas fa-mercury' => __( 'mercury', 'wpvr' ),
613
- 'fas fa-microchip' => __( 'microchip', 'wpvr' ),
614
- 'fas fa-microphone' => __( 'microphone', 'wpvr' ),
615
- 'fas fa-microphone-slash' => __( 'microphone-slash', 'wpvr' ),
616
- 'fab fa-microsoft' => __( 'microsoft', 'wpvr' ),
617
- 'fas fa-minus' => __( 'minus', 'wpvr' ),
618
- 'fas fa-minus-circle' => __( 'minus-circle', 'wpvr' ),
619
- 'fas fa-minus-square' => __( 'minus-square', 'wpvr' ),
620
- 'far fa-minus-square' => __( 'minus-square', 'wpvr' ),
621
- 'fab fa-mix' => __( 'mix', 'wpvr' ),
622
- 'fab fa-mixcloud' => __( 'mixcloud', 'wpvr' ),
623
- 'fab fa-mizuni' => __( 'mizuni', 'wpvr' ),
624
- 'fas fa-mobile' => __( 'mobile', 'wpvr' ),
625
- 'fas fa-mobile-alt' => __( 'mobile-alt', 'wpvr' ),
626
- 'fab fa-modx' => __( 'modx', 'wpvr' ),
627
- 'fab fa-monero' => __( 'monero', 'wpvr' ),
628
- 'fas fa-money-bill-alt' => __( 'money-bill-alt', 'wpvr' ),
629
- 'far fa-money-bill-alt' => __( 'money-bill-alt', 'wpvr' ),
630
- 'fas fa-moon' => __( 'moon', 'wpvr' ),
631
- 'far fa-moon' => __( 'moon', 'wpvr' ),
632
- 'fas fa-motorcycle' => __( 'motorcycle', 'wpvr' ),
633
- 'fas fa-mouse-pointer' => __( 'mouse-pointer', 'wpvr' ),
634
- 'fas fa-music' => __( 'music', 'wpvr' ),
635
- 'fab fa-napster' => __( 'napster', 'wpvr' ),
636
- 'fas fa-neuter' => __( 'neuter', 'wpvr' ),
637
- 'fas fa-newspaper' => __( 'newspaper', 'wpvr' ),
638
- 'far fa-newspaper' => __( 'newspaper', 'wpvr' ),
639
- 'fab fa-nintendo-switch' => __( 'nintendo-switch', 'wpvr' ),
640
- 'fab fa-node' => __( 'node', 'wpvr' ),
641
- 'fab fa-node-js' => __( 'node-js', 'wpvr' ),
642
- 'fas fa-notes-medical' => __( 'notes-medical', 'wpvr' ),
643
- 'fab fa-npm' => __( 'npm', 'wpvr' ),
644
- 'fab fa-ns8' => __( 'ns8', 'wpvr' ),
645
- 'fab fa-nutritionix' => __( 'nutritionix', 'wpvr' ),
646
- 'fas fa-object-group' => __( 'object-group', 'wpvr' ),
647
- 'far fa-object-group' => __( 'object-group', 'wpvr' ),
648
- 'fas fa-object-ungroup' => __( 'object-ungroup', 'wpvr' ),
649
- 'far fa-object-ungroup' => __( 'object-ungroup', 'wpvr' ),
650
- 'fab fa-odnoklassniki' => __( 'odnoklassniki', 'wpvr' ),
651
- 'fab fa-odnoklassniki-square' => __( 'odnoklassniki-square', 'wpvr' ),
652
- 'fab fa-opencart' => __( 'opencart', 'wpvr' ),
653
- 'fab fa-openid' => __( 'openid', 'wpvr' ),
654
- 'fab fa-opera' => __( 'opera', 'wpvr' ),
655
- 'fab fa-optin-monster' => __( 'optin-monster', 'wpvr' ),
656
- 'fab fa-osi' => __( 'osi', 'wpvr' ),
657
- 'fas fa-outdent' => __( 'outdent', 'wpvr' ),
658
- 'fab fa-page4' => __( 'page4', 'wpvr' ),
659
- 'fab fa-pagelines' => __( 'pagelines', 'wpvr' ),
660
- 'fas fa-paint-brush' => __( 'paint-brush', 'wpvr' ),
661
- 'fab fa-palfed' => __( 'palfed', 'wpvr' ),
662
- 'fas fa-pallet' => __( 'pallet', 'wpvr' ),
663
- 'fas fa-paper-plane' => __( 'paper-plane', 'wpvr' ),
664
- 'far fa-paper-plane' => __( 'paper-plane', 'wpvr' ),
665
- 'fas fa-paperclip' => __( 'paperclip', 'wpvr' ),
666
- 'fas fa-parachute-box' => __( 'parachute-box', 'wpvr' ),
667
- 'fas fa-paragraph' => __( 'paragraph', 'wpvr' ),
668
- 'fas fa-paste' => __( 'paste', 'wpvr' ),
669
- 'fab fa-patreon' => __( 'patreon', 'wpvr' ),
670
- 'fas fa-pause' => __( 'pause', 'wpvr' ),
671
- 'fas fa-pause-circle' => __( 'pause-circle', 'wpvr' ),
672
- 'far fa-pause-circle' => __( 'pause-circle', 'wpvr' ),
673
- 'fas fa-paw' => __( 'paw', 'wpvr' ),
674
- 'fab fa-paypal' => __( 'paypal', 'wpvr' ),
675
- 'fas fa-pen-square' => __( 'pen-square', 'wpvr' ),
676
- 'fas fa-pencil-alt' => __( 'pencil-alt', 'wpvr' ),
677
- 'fas fa-people-carry' => __( 'people-carry', 'wpvr' ),
678
- 'fas fa-percent' => __( 'percent', 'wpvr' ),
679
- 'fab fa-periscope' => __( 'periscope', 'wpvr' ),
680
- 'fab fa-phabricator' => __( 'phabricator', 'wpvr' ),
681
- 'fab fa-phoenix-framework' => __( 'phoenix-framework', 'wpvr' ),
682
- 'fas fa-phone' => __( 'phone', 'wpvr' ),
683
- 'fas fa-phone-slash' => __( 'phone-slash', 'wpvr' ),
684
- 'fas fa-phone-square' => __( 'phone-square', 'wpvr' ),
685
- 'fas fa-phone-volume' => __( 'phone-volume', 'wpvr' ),
686
- 'fab fa-php' => __( 'php', 'wpvr' ),
687
- 'fab fa-pied-piper' => __( 'pied-piper', 'wpvr' ),
688
- 'fab fa-pied-piper-alt' => __( 'pied-piper-alt', 'wpvr' ),
689
- 'fab fa-pied-piper-hat' => __( 'pied-piper-hat', 'wpvr' ),
690
- 'fab fa-pied-piper-pp' => __( 'pied-piper-pp', 'wpvr' ),
691
- 'fas fa-piggy-bank' => __( 'piggy-bank', 'wpvr' ),
692
- 'fas fa-pills' => __( 'pills', 'wpvr' ),
693
- 'fab fa-pinterest' => __( 'pinterest', 'wpvr' ),
694
- 'fab fa-pinterest-p' => __( 'pinterest-p', 'wpvr' ),
695
- 'fab fa-pinterest-square' => __( 'pinterest-square', 'wpvr' ),
696
- 'fas fa-plane' => __( 'plane', 'wpvr' ),
697
- 'fas fa-play' => __( 'play', 'wpvr' ),
698
- 'fas fa-play-circle' => __( 'play-circle', 'wpvr' ),
699
- 'far fa-play-circle' => __( 'play-circle', 'wpvr' ),
700
- 'fab fa-playstation' => __( 'playstation', 'wpvr' ),
701
- 'fas fa-plug' => __( 'plug', 'wpvr' ),
702
- 'fas fa-plus' => __( 'plus', 'wpvr' ),
703
- 'fas fa-plus-circle' => __( 'plus-circle', 'wpvr' ),
704
- 'fas fa-plus-square' => __( 'plus-square', 'wpvr' ),
705
- 'far fa-plus-square' => __( 'plus-square', 'wpvr' ),
706
- 'fas fa-podcast' => __( 'podcast', 'wpvr' ),
707
- 'fas fa-poo' => __( 'poo', 'wpvr' ),
708
- 'fas fa-pound-sign' => __( 'pound-sign', 'wpvr' ),
709
- 'fas fa-power-off' => __( 'power-off', 'wpvr' ),
710
- 'fas fa-prescription-bottle' => __( 'prescription-bottle', 'wpvr' ),
711
- 'fas fa-prescription-bottle-alt' => __( 'prescription-bottle-alt', 'wpvr' ),
712
- 'fas fa-print' => __( 'print', 'wpvr' ),
713
- 'fas fa-procedures' => __( 'procedures', 'wpvr' ),
714
- 'fab fa-product-hunt' => __( 'product-hunt', 'wpvr' ),
715
- 'fab fa-pushed' => __( 'pushed', 'wpvr' ),
716
- 'fas fa-puzzle-piece' => __( 'puzzle-piece', 'wpvr' ),
717
- 'fab fa-python' => __( 'python', 'wpvr' ),
718
- 'fab fa-qq' => __( 'qq', 'wpvr' ),
719
- 'fas fa-qrcode' => __( 'qrcode', 'wpvr' ),
720
- 'fas fa-question' => __( 'question', 'wpvr' ),
721
- 'fas fa-question-circle' => __( 'question-circle', 'wpvr' ),
722
- 'far fa-question-circle' => __( 'question-circle', 'wpvr' ),
723
- 'fas fa-quidditch' => __( 'quidditch', 'wpvr' ),
724
- 'fab fa-quinscape' => __( 'quinscape', 'wpvr' ),
725
- 'fab fa-quora' => __( 'quora', 'wpvr' ),
726
- 'fas fa-quote-left' => __( 'quote-left', 'wpvr' ),
727
- 'fas fa-quote-right' => __( 'quote-right', 'wpvr' ),
728
- 'fas fa-random' => __( 'random', 'wpvr' ),
729
- 'fab fa-ravelry' => __( 'ravelry', 'wpvr' ),
730
- 'fab fa-react' => __( 'react', 'wpvr' ),
731
- 'fab fa-readme' => __( 'readme', 'wpvr' ),
732
- 'fab fa-rebel' => __( 'rebel', 'wpvr' ),
733
- 'fas fa-recycle' => __( 'recycle', 'wpvr' ),
734
- 'fab fa-red-river' => __( 'red-river', 'wpvr' ),
735
- 'fab fa-reddit' => __( 'reddit', 'wpvr' ),
736
- 'fab fa-reddit-alien' => __( 'reddit-alien', 'wpvr' ),
737
- 'fab fa-reddit-square' => __( 'reddit-square', 'wpvr' ),
738
- 'fas fa-redo' => __( 'redo', 'wpvr' ),
739
- 'fas fa-redo-alt' => __( 'redo-alt', 'wpvr' ),
740
- 'fas fa-registered' => __( 'registered', 'wpvr' ),
741
- 'far fa-registered' => __( 'registered', 'wpvr' ),
742
- 'fab fa-rendact' => __( 'rendact', 'wpvr' ),
743
- 'fab fa-renren' => __( 'renren', 'wpvr' ),
744
- 'fas fa-reply' => __( 'reply', 'wpvr' ),
745
- 'fas fa-reply-all' => __( 'reply-all', 'wpvr' ),
746
- 'fab fa-replyd' => __( 'replyd', 'wpvr' ),
747
- 'fab fa-resolving' => __( 'resolving', 'wpvr' ),
748
- 'fas fa-retweet' => __( 'retweet', 'wpvr' ),
749
- 'fas fa-ribbon' => __( 'ribbon', 'wpvr' ),
750
- 'fas fa-road' => __( 'road', 'wpvr' ),
751
- 'fas fa-rocket' => __( 'rocket', 'wpvr' ),
752
- 'fab fa-rocketchat' => __( 'rocketchat', 'wpvr' ),
753
- 'fab fa-rockrms' => __( 'rockrms', 'wpvr' ),
754
- 'fas fa-rss' => __( 'rss', 'wpvr' ),
755
- 'fas fa-rss-square' => __( 'rss-square', 'wpvr' ),
756
- 'fas fa-ruble-sign' => __( 'ruble-sign', 'wpvr' ),
757
- 'fas fa-rupee-sign' => __( 'rupee-sign', 'wpvr' ),
758
- 'fab fa-safari' => __( 'safari', 'wpvr' ),
759
- 'fab fa-sass' => __( 'sass', 'wpvr' ),
760
- 'fas fa-save' => __( 'save', 'wpvr' ),
761
- 'far fa-save' => __( 'save', 'wpvr' ),
762
- 'fab fa-schlix' => __( 'schlix', 'wpvr' ),
763
- 'fab fa-scribd' => __( 'scribd', 'wpvr' ),
764
- 'fas fa-search' => __( 'search', 'wpvr' ),
765
- 'fas fa-search-minus' => __( 'search-minus', 'wpvr' ),
766
- 'fas fa-search-plus' => __( 'search-plus', 'wpvr' ),
767
- 'fab fa-searchengin' => __( 'searchengin', 'wpvr' ),
768
- 'fas fa-seedling' => __( 'seedling', 'wpvr' ),
769
- 'fab fa-sellcast' => __( 'sellcast', 'wpvr' ),
770
- 'fab fa-sellsy' => __( 'sellsy', 'wpvr' ),
771
- 'fas fa-server' => __( 'server', 'wpvr' ),
772
- 'fab fa-servicestack' => __( 'servicestack', 'wpvr' ),
773
- 'fas fa-share' => __( 'share', 'wpvr' ),
774
- 'fas fa-share-alt' => __( 'share-alt', 'wpvr' ),
775
- 'fas fa-share-alt-square' => __( 'share-alt-square', 'wpvr' ),
776
- 'fas fa-share-square' => __( 'share-square', 'wpvr' ),
777
- 'far fa-share-square' => __( 'share-square', 'wpvr' ),
778
- 'fas fa-shekel-sign' => __( 'shekel-sign', 'wpvr' ),
779
- 'fas fa-shield-alt' => __( 'shield-alt', 'wpvr' ),
780
- 'fas fa-ship' => __( 'ship', 'wpvr' ),
781
- 'fas fa-shipping-fast' => __( 'shipping-fast', 'wpvr' ),
782
- 'fab fa-shirtsinbulk' => __( 'shirtsinbulk', 'wpvr' ),
783
- 'fas fa-shopping-bag' => __( 'shopping-bag', 'wpvr' ),
784
- 'fas fa-shopping-basket' => __( 'shopping-basket', 'wpvr' ),
785
- 'fas fa-shopping-cart' => __( 'shopping-cart', 'wpvr' ),
786
- 'fas fa-shower' => __( 'shower', 'wpvr' ),
787
- 'fas fa-sign' => __( 'sign', 'wpvr' ),
788
- 'fas fa-sign-in-alt' => __( 'sign-in-alt', 'wpvr' ),
789
- 'fas fa-sign-language' => __( 'sign-language', 'wpvr' ),
790
- 'fas fa-sign-out-alt' => __( 'sign-out-alt', 'wpvr' ),
791
- 'fas fa-signal' => __( 'signal', 'wpvr' ),
792
- 'fab fa-simplybuilt' => __( 'simplybuilt', 'wpvr' ),
793
- 'fab fa-sistrix' => __( 'sistrix', 'wpvr' ),
794
- 'fas fa-sitemap' => __( 'sitemap', 'wpvr' ),
795
- 'fab fa-skyatlas' => __( 'skyatlas', 'wpvr' ),
796
- 'fab fa-skype' => __( 'skype', 'wpvr' ),
797
- 'fab fa-slack' => __( 'slack', 'wpvr' ),
798
- 'fab fa-slack-hash' => __( 'slack-hash', 'wpvr' ),
799
- 'fas fa-sliders-h' => __( 'sliders-h', 'wpvr' ),
800
- 'fab fa-slideshare' => __( 'slideshare', 'wpvr' ),
801
- 'fas fa-smile' => __( 'smile', 'wpvr' ),
802
- 'far fa-smile' => __( 'smile', 'wpvr' ),
803
- 'fas fa-smoking' => __( 'smoking', 'wpvr' ),
804
- 'fab fa-snapchat' => __( 'snapchat', 'wpvr' ),
805
- 'fab fa-snapchat-ghost' => __( 'snapchat-ghost', 'wpvr' ),
806
- 'fab fa-snapchat-square' => __( 'snapchat-square', 'wpvr' ),
807
- 'fas fa-snowflake' => __( 'snowflake', 'wpvr' ),
808
- 'far fa-snowflake' => __( 'snowflake', 'wpvr' ),
809
- 'fas fa-sort' => __( 'sort', 'wpvr' ),
810
- 'fas fa-sort-alpha-down' => __( 'sort-alpha-down', 'wpvr' ),
811
- 'fas fa-sort-alpha-up' => __( 'sort-alpha-up', 'wpvr' ),
812
- 'fas fa-sort-amount-down' => __( 'sort-amount-down', 'wpvr' ),
813
- 'fas fa-sort-amount-up' => __( 'sort-amount-up', 'wpvr' ),
814
- 'fas fa-sort-down' => __( 'sort-down', 'wpvr' ),
815
- 'fas fa-sort-numeric-down' => __( 'sort-numeric-down', 'wpvr' ),
816
- 'fas fa-sort-numeric-up' => __( 'sort-numeric-up', 'wpvr' ),
817
- 'fas fa-sort-up' => __( 'sort-up', 'wpvr' ),
818
- 'fab fa-soundcloud' => __( 'soundcloud', 'wpvr' ),
819
- 'fas fa-space-shuttle' => __( 'space-shuttle', 'wpvr' ),
820
- 'fab fa-speakap' => __( 'speakap', 'wpvr' ),
821
- 'fas fa-spinner' => __( 'spinner', 'wpvr' ),
822
- 'fab fa-spotify' => __( 'spotify', 'wpvr' ),
823
- 'fas fa-square' => __( 'square', 'wpvr' ),
824
- 'far fa-square' => __( 'square', 'wpvr' ),
825
- 'fas fa-square-full' => __( 'square-full', 'wpvr' ),
826
- 'fab fa-stack-exchange' => __( 'stack-exchange', 'wpvr' ),
827
- 'fab fa-stack-overflow' => __( 'stack-overflow', 'wpvr' ),
828
- 'fas fa-star' => __( 'star', 'wpvr' ),
829
- 'far fa-star' => __( 'star', 'wpvr' ),
830
- 'fas fa-star-half' => __( 'star-half', 'wpvr' ),
831
- 'far fa-star-half' => __( 'star-half', 'wpvr' ),
832
- 'fab fa-staylinked' => __( 'staylinked', 'wpvr' ),
833
- 'fab fa-steam' => __( 'steam', 'wpvr' ),
834
- 'fab fa-steam-square' => __( 'steam-square', 'wpvr' ),
835
- 'fab fa-steam-symbol' => __( 'steam-symbol', 'wpvr' ),
836
- 'fas fa-step-backward' => __( 'step-backward', 'wpvr' ),
837
- 'fas fa-step-forward' => __( 'step-forward', 'wpvr' ),
838
- 'fas fa-stethoscope' => __( 'stethoscope', 'wpvr' ),
839
- 'fab fa-sticker-mule' => __( 'sticker-mule', 'wpvr' ),
840
- 'fas fa-sticky-note' => __( 'sticky-note', 'wpvr' ),
841
- 'far fa-sticky-note' => __( 'sticky-note', 'wpvr' ),
842
- 'fas fa-stop' => __( 'stop', 'wpvr' ),
843
- 'fas fa-stop-circle' => __( 'stop-circle', 'wpvr' ),
844
- 'far fa-stop-circle' => __( 'stop-circle', 'wpvr' ),
845
- 'fas fa-stopwatch' => __( 'stopwatch', 'wpvr' ),
846
- 'fab fa-strava' => __( 'strava', 'wpvr' ),
847
- 'fas fa-street-view' => __( 'street-view', 'wpvr' ),
848
- 'fas fa-strikethrough' => __( 'strikethrough', 'wpvr' ),
849
- 'fab fa-stripe' => __( 'stripe', 'wpvr' ),
850
- 'fab fa-stripe-s' => __( 'stripe-s', 'wpvr' ),
851
- 'fab fa-studiovinari' => __( 'studiovinari', 'wpvr' ),
852
- 'fab fa-stumbleupon' => __( 'stumbleupon', 'wpvr' ),
853
- 'fab fa-stumbleupon-circle' => __( 'stumbleupon-circle', 'wpvr' ),
854
- 'fas fa-subscript' => __( 'subscript', 'wpvr' ),
855
- 'fas fa-subway' => __( 'subway', 'wpvr' ),
856
- 'fas fa-suitcase' => __( 'suitcase', 'wpvr' ),
857
- 'fas fa-sun' => __( 'sun', 'wpvr' ),
858
- 'far fa-sun' => __( 'sun', 'wpvr' ),
859
- 'fab fa-superpowers' => __( 'superpowers', 'wpvr' ),
860
- 'fas fa-superscript' => __( 'superscript', 'wpvr' ),
861
- 'fab fa-supple' => __( 'supple', 'wpvr' ),
862
- 'fas fa-sync' => __( 'sync', 'wpvr' ),
863
- 'fas fa-sync-alt' => __( 'sync-alt', 'wpvr' ),
864
- 'fas fa-syringe' => __( 'syringe', 'wpvr' ),
865
- 'fas fa-table' => __( 'table', 'wpvr' ),
866
- 'fas fa-table-tennis' => __( 'table-tennis', 'wpvr' ),
867
- 'fas fa-tablet' => __( 'tablet', 'wpvr' ),
868
- 'fas fa-tablet-alt' => __( 'tablet-alt', 'wpvr' ),
869
- 'fas fa-tablets' => __( 'tablets', 'wpvr' ),
870
- 'fas fa-tachometer-alt' => __( 'tachometer-alt', 'wpvr' ),
871
- 'fas fa-tag' => __( 'tag', 'wpvr' ),
872
- 'fas fa-tags' => __( 'tags', 'wpvr' ),
873
- 'fas fa-tape' => __( 'tape', 'wpvr' ),
874
- 'fas fa-tasks' => __( 'tasks', 'wpvr' ),
875
- 'fas fa-taxi' => __( 'taxi', 'wpvr' ),
876
- 'fab fa-telegram' => __( 'telegram', 'wpvr' ),
877
- 'fab fa-telegram-plane' => __( 'telegram-plane', 'wpvr' ),
878
- 'fab fa-tencent-weibo' => __( 'tencent-weibo', 'wpvr' ),
879
- 'fas fa-terminal' => __( 'terminal', 'wpvr' ),
880
- 'fas fa-text-height' => __( 'text-height', 'wpvr' ),
881
- 'fas fa-text-width' => __( 'text-width', 'wpvr' ),
882
- 'fas fa-th' => __( 'th', 'wpvr' ),
883
- 'fas fa-th-large' => __( 'th-large', 'wpvr' ),
884
- 'fas fa-th-list' => __( 'th-list', 'wpvr' ),
885
- 'fab fa-themeisle' => __( 'themeisle', 'wpvr' ),
886
- 'fas fa-thermometer' => __( 'thermometer', 'wpvr' ),
887
- 'fas fa-thermometer-empty' => __( 'thermometer-empty', 'wpvr' ),
888
- 'fas fa-thermometer-full' => __( 'thermometer-full', 'wpvr' ),
889
- 'fas fa-thermometer-half' => __( 'thermometer-half', 'wpvr' ),
890
- 'fas fa-thermometer-quarter' => __( 'thermometer-quarter', 'wpvr' ),
891
- 'fas fa-thermometer-three-quarters' => __( 'thermometer-three-quarters', 'wpvr' ),
892
- 'fas fa-thumbs-down' => __( 'thumbs-down', 'wpvr' ),
893
- 'far fa-thumbs-down' => __( 'thumbs-down', 'wpvr' ),
894
- 'fas fa-thumbs-up' => __( 'thumbs-up', 'wpvr' ),
895
- 'far fa-thumbs-up' => __( 'thumbs-up', 'wpvr' ),
896
- 'fas fa-thumbtack' => __( 'thumbtack', 'wpvr' ),
897
- 'fas fa-ticket-alt' => __( 'ticket-alt', 'wpvr' ),
898
- 'fas fa-times' => __( 'times', 'wpvr' ),
899
- 'fas fa-times-circle' => __( 'times-circle', 'wpvr' ),
900
- 'far fa-times-circle' => __( 'times-circle', 'wpvr' ),
901
- 'fas fa-tint' => __( 'tint', 'wpvr' ),
902
- 'fas fa-toggle-off' => __( 'toggle-off', 'wpvr' ),
903
- 'fas fa-toggle-on' => __( 'toggle-on', 'wpvr' ),
904
- 'fas fa-trademark' => __( 'trademark', 'wpvr' ),
905
- 'fas fa-train' => __( 'train', 'wpvr' ),
906
- 'fas fa-transgender' => __( 'transgender', 'wpvr' ),
907
- 'fas fa-transgender-alt' => __( 'transgender-alt', 'wpvr' ),
908
- 'fas fa-trash' => __( 'trash', 'wpvr' ),
909
- 'fas fa-trash-alt' => __( 'trash-alt', 'wpvr' ),
910
- 'far fa-trash-alt' => __( 'trash-alt', 'wpvr' ),
911
- 'fas fa-tree' => __( 'tree', 'wpvr' ),
912
- 'fab fa-trello' => __( 'trello', 'wpvr' ),
913
- 'fab fa-tripadvisor' => __( 'tripadvisor', 'wpvr' ),
914
- 'fas fa-trophy' => __( 'trophy', 'wpvr' ),
915
- 'fas fa-truck' => __( 'truck', 'wpvr' ),
916
- 'fas fa-truck-loading' => __( 'truck-loading', 'wpvr' ),
917
- 'fas fa-truck-moving' => __( 'truck-moving', 'wpvr' ),
918
- 'fas fa-tty' => __( 'tty', 'wpvr' ),
919
- 'fab fa-tumblr' => __( 'tumblr', 'wpvr' ),
920
- 'fab fa-tumblr-square' => __( 'tumblr-square', 'wpvr' ),
921
- 'fas fa-tv' => __( 'tv', 'wpvr' ),
922
- 'fab fa-twitch' => __( 'twitch', 'wpvr' ),
923
- 'fab fa-twitter' => __( 'twitter', 'wpvr' ),
924
- 'fab fa-twitter-square' => __( 'twitter-square', 'wpvr' ),
925
- 'fab fa-typo3' => __( 'typo3', 'wpvr' ),
926
- 'fab fa-uber' => __( 'uber', 'wpvr' ),
927
- 'fab fa-uikit' => __( 'uikit', 'wpvr' ),
928
- 'fas fa-umbrella' => __( 'umbrella', 'wpvr' ),
929
- 'fas fa-underline' => __( 'underline', 'wpvr' ),
930
- 'fas fa-undo' => __( 'undo', 'wpvr' ),
931
- 'fas fa-undo-alt' => __( 'undo-alt', 'wpvr' ),
932
- 'fab fa-uniregistry' => __( 'uniregistry', 'wpvr' ),
933
- 'fas fa-universal-access' => __( 'universal-access', 'wpvr' ),
934
- 'fas fa-university' => __( 'university', 'wpvr' ),
935
- 'fas fa-unlink' => __( 'unlink', 'wpvr' ),
936
- 'fas fa-unlock' => __( 'unlock', 'wpvr' ),
937
- 'fas fa-unlock-alt' => __( 'unlock-alt', 'wpvr' ),
938
- 'fab fa-untappd' => __( 'untappd', 'wpvr' ),
939
- 'fas fa-upload' => __( 'upload', 'wpvr' ),
940
- 'fab fa-usb' => __( 'usb', 'wpvr' ),
941
- 'fas fa-user' => __( 'user', 'wpvr' ),
942
- 'far fa-user' => __( 'user', 'wpvr' ),
943
- 'fas fa-user-circle' => __( 'user-circle', 'wpvr' ),
944
- 'far fa-user-circle' => __( 'user-circle', 'wpvr' ),
945
- 'fas fa-user-md' => __( 'user-md', 'wpvr' ),
946
- 'fas fa-user-plus' => __( 'user-plus', 'wpvr' ),
947
- 'fas fa-user-secret' => __( 'user-secret', 'wpvr' ),
948
- 'fas fa-user-times' => __( 'user-times', 'wpvr' ),
949
- 'fas fa-users' => __( 'users', 'wpvr' ),
950
- 'fab fa-ussunnah' => __( 'ussunnah', 'wpvr' ),
951
- 'fas fa-utensil-spoon' => __( 'utensil-spoon', 'wpvr' ),
952
- 'fas fa-utensils' => __( 'utensils', 'wpvr' ),
953
- 'fab fa-vaadin' => __( 'vaadin', 'wpvr' ),
954
- 'fas fa-venus' => __( 'venus', 'wpvr' ),
955
- 'fas fa-venus-double' => __( 'venus-double', 'wpvr' ),
956
- 'fas fa-venus-mars' => __( 'venus-mars', 'wpvr' ),
957
- 'fab fa-viacoin' => __( 'viacoin', 'wpvr' ),
958
- 'fab fa-viadeo' => __( 'viadeo', 'wpvr' ),
959
- 'fab fa-viadeo-square' => __( 'viadeo-square', 'wpvr' ),
960
- 'fas fa-vial' => __( 'vial', 'wpvr' ),
961
- 'fas fa-vials' => __( 'vials', 'wpvr' ),
962
- 'fab fa-viber' => __( 'viber', 'wpvr' ),
963
- 'fas fa-video' => __( 'video', 'wpvr' ),
964
- 'fas fa-video-slash' => __( 'video-slash', 'wpvr' ),
965
- 'fab fa-vimeo' => __( 'vimeo', 'wpvr' ),
966
- 'fab fa-vimeo-square' => __( 'vimeo-square', 'wpvr' ),
967
- 'fab fa-vimeo-v' => __( 'vimeo-v', 'wpvr' ),
968
- 'fab fa-vine' => __( 'vine', 'wpvr' ),
969
- 'fab fa-vk' => __( 'vk', 'wpvr' ),
970
- 'fab fa-vnv' => __( 'vnv', 'wpvr' ),
971
- 'fas fa-volleyball-ball' => __( 'volleyball-ball', 'wpvr' ),
972
- 'fas fa-volume-down' => __( 'volume-down', 'wpvr' ),
973
- 'fas fa-volume-off' => __( 'volume-off', 'wpvr' ),
974
- 'fas fa-volume-up' => __( 'volume-up', 'wpvr' ),
975
- 'fab fa-vuejs' => __( 'vuejs', 'wpvr' ),
976
- 'fas fa-warehouse' => __( 'warehouse', 'wpvr' ),
977
- 'fab fa-weibo' => __( 'weibo', 'wpvr' ),
978
- 'fas fa-weight' => __( 'weight', 'wpvr' ),
979
- 'fab fa-weixin' => __( 'weixin', 'wpvr' ),
980
- 'fab fa-whatsapp' => __( 'whatsapp', 'wpvr' ),
981
- 'fab fa-whatsapp-square' => __( 'whatsapp-square', 'wpvr' ),
982
- 'fas fa-wheelchair' => __( 'wheelchair', 'wpvr' ),
983
- 'fab fa-whmcs' => __( 'whmcs', 'wpvr' ),
984
- 'fas fa-wifi' => __( 'wifi', 'wpvr' ),
985
- 'fab fa-wikipedia-w' => __( 'wikipedia-w', 'wpvr' ),
986
- 'fas fa-window-close' => __( 'window-close', 'wpvr' ),
987
- 'far fa-window-close' => __( 'window-close', 'wpvr' ),
988
- 'fas fa-window-maximize' => __( 'window-maximize', 'wpvr' ),
989
- 'far fa-window-maximize' => __( 'window-maximize', 'wpvr' ),
990
- 'fas fa-window-minimize' => __( 'window-minimize', 'wpvr' ),
991
- 'far fa-window-minimize' => __( 'window-minimize', 'wpvr' ),
992
- 'fas fa-window-restore' => __( 'window-restore', 'wpvr' ),
993
- 'far fa-window-restore' => __( 'window-restore', 'wpvr' ),
994
- 'fab fa-windows' => __( 'windows', 'wpvr' ),
995
- 'fas fa-wine-glass' => __( 'wine-glass', 'wpvr' ),
996
- 'fas fa-won-sign' => __( 'won-sign', 'wpvr' ),
997
- 'fab fa-wordpress' => __( 'wordpress', 'wpvr' ),
998
- 'fab fa-wordpress-simple' => __( 'wordpress-simple', 'wpvr' ),
999
- 'fab fa-wpbeginner' => __( 'wpbeginner', 'wpvr' ),
1000
- 'fab fa-wpexplorer' => __( 'wpexplorer', 'wpvr' ),
1001
- 'fab fa-wpforms' => __( 'wpforms', 'wpvr' ),
1002
- 'fas fa-wrench' => __( 'wrench', 'wpvr' ),
1003
- 'fas fa-x-ray' => __( 'x-ray', 'wpvr' ),
1004
- 'fab fa-xbox' => __( 'xbox', 'wpvr' ),
1005
- 'fab fa-xing' => __( 'xing', 'wpvr' ),
1006
- 'fab fa-xing-square' => __( 'xing-square', 'wpvr' ),
1007
- 'fab fa-y-combinator' => __( 'y-combinator', 'wpvr' ),
1008
- 'fab fa-yahoo' => __( 'yahoo', 'wpvr' ),
1009
- 'fab fa-yandex' => __( 'yandex', 'wpvr' ),
1010
- 'fab fa-yandex-international' => __( 'yandex-international', 'wpvr' ),
1011
- 'fab fa-yelp' => __( 'yelp', 'wpvr' ),
1012
- 'fas fa-yen-sign' => __( 'yen-sign', 'wpvr' ),
1013
- 'fab fa-yoast' => __( 'yoast', 'wpvr' ),
1014
- 'fab fa-youtube' => __( 'youtube', 'wpvr' ),
1015
- 'fab fa-youtube-square' => __( 'youtube-square', 'wpvr' ),
1016
- );
1017
- }
1018
- }
1019
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/css/font-awesome.min.css CHANGED
File without changes
admin/css/iconpicker.ttf DELETED
Binary file
admin/css/iconpicker.woff DELETED
Binary file
admin/css/jquery.fonticonpicker.grey.min.css DELETED
@@ -1,2 +0,0 @@
1
- /* Grey Theme file for fontIconPicker {@link https://github.com/micc83/fontIconPicker} */
2
- .fip-grey.icons-selector{font-size:16px}.fip-grey.icons-selector .selector{border:1px solid #EDEDED;background-color:#fff}.fip-grey.icons-selector .selector-button{background-color:#F4F4F4;border-left:1px solid #E1E1E1}.fip-grey.icons-selector .selector-button:hover{background-color:#f1f1f1}.fip-grey.icons-selector .selector-button:hover i{color:#999}.fip-grey.icons-selector .selector-button i{color:#aaa;text-shadow:0 1px 0 #FFF}.fip-grey.icons-selector .selected-icon i{color:#404040}.fip-grey.icons-selector .selector-popup{-moz-box-shadow:0 1px 1px rgba(0,0,0,.04);-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);border:1px solid #E5E5E5}.fip-grey.icons-selector .selector-category select,.fip-grey.icons-selector .selector-search input[type=text]{border:1px solid #EDEDED;color:#404040;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none;outline:0}.fip-grey.icons-selector input::-webkit-input-placeholder{color:#ddd}.fip-grey.icons-selector input:-moz-placeholder{color:#ddd}.fip-grey.icons-selector input::-moz-placeholder{color:#ddd}.fip-grey.icons-selector input:-ms-input-placeholder{color:#ddd!important}.fip-grey.icons-selector .selector-search i{color:#eee}.fip-grey.icons-selector .fip-icons-container{background-color:#fff;border:1px solid #EDEDED}.fip-grey.icons-selector .fip-icons-container .loading{color:#eee}.fip-grey.icons-selector .fip-box{border:1px solid #EFEFEF}.fip-grey.icons-selector .fip-box:hover{background-color:#f6f6f6}.fip-grey.icons-selector .selector-footer,.fip-grey.icons-selector .selector-footer i{color:#ddd}.fip-grey.icons-selector .selector-arrows i:hover{color:#777}.fip-grey.icons-selector span.current-icon,.fip-grey.icons-selector span.current-icon:hover{background-color:#2EA2CC;color:#fff;border:1px solid #298CBA}.fip-grey.icons-selector .icons-picker-error i:before{color:#eee}
 
 
admin/css/jquery.fonticonpicker.min.css DELETED
@@ -1,2 +0,0 @@
1
- /* fontIconPicker main CSS file {@link https://github.com/micc83/fontIconPicker} */
2
- .icons-selector *{margin:0;padding:0;border:0;vertical-align:baseline;}.icons-selector,.icons-selector *,.icons-selector :after,.icons-selector :before,.icons-selector:after,.icons-selector:before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.icons-selector{display:inline-block;vertical-align:middle;text-align:left}.icons-selector .selector{width:100px;height:40px}.icons-selector .selector-button{width:39px;height:100%;display:block;text-align:center;cursor:pointer;float:left}.icons-selector .selector-button i{line-height:38px;text-align:center}.icons-selector .selected-icon{display:block;width:60px;height:100%;float:left;text-align:center}.icons-selector .selected-icon i{line-height:40px;font-size:18px;cursor:default}.icons-selector .selector-popup{position:absolute;z-index:10000;background-color:#fefefe;padding:5px;height:auto;width:342px;margin-top:-1px}.icons-selector .selector-category select,.icons-selector .selector-search input[type=text]{border:0;line-height:20px;padding:10px 2.5%;width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin-bottom:5px;font-size:12px;display:block}.icons-selector .selector-category select{height:40px}.icons-selector .selector-category select option{padding:10px}.icons-selector input::-webkit-input-placeholder{text-transform:uppercase}.icons-selector input:-moz-placeholder{text-transform:uppercase}.icons-selector input::-moz-placeholder{text-transform:uppercase}.icons-selector input:-ms-input-placeholder{text-transform:uppercase}.icons-selector .selector-search{position:relative}.icons-selector .selector-search i{position:absolute;right:10px;top:7px}.icons-selector .fip-icons-container{width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;padding:5px}.icons-selector .fip-icons-container .loading{font-size:24px;margin:0 auto;padding:20px 0;text-align:center;width:100%}.icons-selector .fip-box{display:inline-block;margin:2px;width:60px;line-height:42px;text-align:center;cursor:pointer;vertical-align:top;height:40px}.icons-selector .selector-footer{line-height:12px;padding:5px 5px 0;text-align:center}.icons-selector .selector-footer,.icons-selector .selector-footer i{font-size:14px}.icons-selector .selector-arrows{float:right}.icons-selector .selector-pages{font-size:11px;float:left}.icons-selector .selector-arrows i{cursor:pointer}.icons-selector .selector-footer em{font-style:italic}.icons-selector .icons-picker-error i:before{color:#eee}@font-face{font-family:iconpicker;src:url(iconpicker.eot?90190138);src:url(iconpicker.eot?90190138#iefix) format('embedded-opentype'),url(iconpicker.woff?90190138) format('woff'),url(iconpicker.ttf?90190138) format('truetype'),url(iconpicker.svg?90190138#iconpicker) format('svg');font-weight:400;font-style:normal}.icons-selector [class*=" fip-icon-"]:before,.icons-selector [class^=fip-icon-]:before{font-family:iconpicker;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em}.icons-selector .fip-icon-search:before{content:'\e812';cursor:default}.icons-selector .fip-icon-cancel:before{content:'\e814';cursor:pointer}.icons-selector .fip-icon-block:before{content:'\e84e';color:#fed0d0}.icons-selector .fip-icon-down-dir:before{content:'\e800'}.icons-selector .fip-icon-up-dir:before{content:'\e813'}.icons-selector .fip-icon-left-dir:before{content:'\e801'}.icons-selector .fip-icon-right-dir:before{content:'\e802'}.icons-selector .fip-icon-spin3:before{content:'\e815'}.icons-selector .fip-icon-spin3{-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;display:inline-block}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-o-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@-ms-keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spin{0%{-moz-transform:rotate(0deg);-o-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-moz-transform:rotate(359deg);-o-transform:rotate(359deg);-webkit-transform:rotate(359deg);transform:rotate(359deg)}}
 
 
admin/css/materialize.css CHANGED
File without changes
admin/css/materialize.min.css CHANGED
File without changes
admin/css/owl.carousel.css DELETED
@@ -1,186 +0,0 @@
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
- .vrowl-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
- .vrowl-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
- .vrowl-carousel .owl-stage:after {
23
- content: ".";
24
- display: block;
25
- clear: both;
26
- visibility: hidden;
27
- line-height: 0;
28
- height: 0; }
29
- .vrowl-carousel .owl-stage-outer {
30
- position: relative;
31
- overflow: hidden;
32
- /* fix for flashing background */
33
- -webkit-transform: translate3d(0px, 0px, 0px); }
34
- .vrowl-carousel .owl-wrapper,
35
- .vrowl-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
- .vrowl-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
- .vrowl-carousel .owl-item img {
50
- display: block;
51
- width: 100%; }
52
- .vrowl-carousel .owl-nav.disabled,
53
- .vrowl-carousel .owl-dots.disabled {
54
- display: none; }
55
- .vrowl-carousel .owl-nav .owl-prev,
56
- .vrowl-carousel .owl-nav .owl-next,
57
- .vrowl-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
- .vrowl-carousel .owl-nav button.owl-prev,
65
- .vrowl-carousel .owl-nav button.owl-next,
66
- .vrowl-carousel button.owl-dot {
67
- background: none;
68
- color: inherit;
69
- border: none;
70
- padding: 0 !important;
71
- font: inherit; }
72
- .vrowl-carousel.owl-loaded {
73
- display: block; }
74
- .vrowl-carousel.owl-loading {
75
- opacity: 0;
76
- display: block; }
77
- .vrowl-carousel.owl-hidden {
78
- opacity: 0; }
79
- .vrowl-carousel.owl-refresh .owl-item {
80
- visibility: hidden; }
81
- .vrowl-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
- .vrowl-carousel.owl-grab {
89
- cursor: move;
90
- cursor: grab; }
91
- .vrowl-carousel.owl-rtl {
92
- direction: rtl; }
93
- .vrowl-carousel.owl-rtl .owl-item {
94
- float: right; }
95
-
96
- /* No Js */
97
- .no-js .vrowl-carousel {
98
- display: block; }
99
-
100
- /*
101
- * Owl Carousel - Animate Plugin
102
- */
103
- .vrowl-carousel .animated {
104
- animation-duration: 1000ms;
105
- animation-fill-mode: both; }
106
-
107
- .vrowl-carousel .owl-animated-in {
108
- z-index: 0; }
109
-
110
- .vrowl-carousel .owl-animated-out {
111
- z-index: 1; }
112
-
113
- .vrowl-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
- .vrowl-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
- .vrowl-carousel .owl-item .owl-lazy {
137
- opacity: 0;
138
- transition: opacity 400ms ease; }
139
- .vrowl-carousel .owl-item .owl-lazy[src^=""], .vrowl-carousel .owl-item .owl-lazy:not([src]) {
140
- max-height: 0; }
141
- .vrowl-carousel .owl-item img.owl-lazy {
142
- transform-style: preserve-3d; }
143
-
144
- /*
145
- * Owl Carousel - Video Plugin
146
- */
147
- .vrowl-carousel .owl-video-wrapper {
148
- position: relative;
149
- height: 100%;
150
- background: #000; }
151
-
152
- .vrowl-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
- .vrowl-carousel .owl-video-play-icon:hover {
167
- -ms-transform: scale(1.3, 1.3);
168
- transform: scale(1.3, 1.3); }
169
-
170
- .vrowl-carousel .owl-video-playing .owl-video-tn,
171
- .vrowl-carousel .owl-video-playing .owl-video-play-icon {
172
- display: none; }
173
-
174
- .vrowl-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
- .vrowl-carousel .owl-video-frame {
183
- position: relative;
184
- z-index: 1;
185
- height: 100%;
186
- width: 100%; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/css/owl.theme.default.css DELETED
@@ -1,50 +0,0 @@
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,194 +3,7 @@
3
  * included in this file.
4
  */
5
 
6
-
7
-
8
- /* Absolute Center Spinner */
9
- .wpvr-loading {
10
- position: fixed;
11
- z-index: 999;
12
- height: 2em;
13
- width: 2em;
14
- overflow: visible;
15
- margin: auto;
16
- top: 0;
17
- left: 0;
18
- bottom: 0;
19
- right: 0;
20
- }
21
-
22
- /* Transparent Overlay */
23
- .wpvr-loading:before {
24
- content: '';
25
- display: block;
26
- position: fixed;
27
- top: 0;
28
- left: 0;
29
- width: 100%;
30
- height: 100%;
31
- background-color: rgba(0,0,0,0.3);
32
- }
33
-
34
- /* :not(:required) hides these rules from IE9 and below */
35
- .wpvr-loading:not(:required) {
36
- /* hide "loading..." text */
37
- font: 0/0 a;
38
- color: transparent;
39
- text-shadow: none;
40
- background-color: transparent;
41
- border: 0;
42
- }
43
-
44
- .wpvr-loading:not(:required):after {
45
- content: '';
46
- display: block;
47
- font-size: 10px;
48
- width: 1em;
49
- height: 1em;
50
- margin-top: -0.5em;
51
- -webkit-animation: spinner 1500ms infinite linear;
52
- -moz-animation: spinner 1500ms infinite linear;
53
- -ms-animation: spinner 1500ms infinite linear;
54
- -o-animation: spinner 1500ms infinite linear;
55
- animation: spinner 1500ms infinite linear;
56
- border-radius: 0.5em;
57
- -webkit-box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
58
- box-shadow: rgba(0, 0, 0, 0.75) 1.5em 0 0 0, rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) 0 1.5em 0 0, rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.75) -1.5em 0 0 0, rgba(0, 0, 0, 0.75) -1.1em -1.1em 0 0, rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0;
59
- }
60
-
61
- /* Animation */
62
-
63
- @-webkit-keyframes spinner {
64
- 0% {
65
- -webkit-transform: rotate(0deg);
66
- -moz-transform: rotate(0deg);
67
- -ms-transform: rotate(0deg);
68
- -o-transform: rotate(0deg);
69
- transform: rotate(0deg);
70
- }
71
- 100% {
72
- -webkit-transform: rotate(360deg);
73
- -moz-transform: rotate(360deg);
74
- -ms-transform: rotate(360deg);
75
- -o-transform: rotate(360deg);
76
- transform: rotate(360deg);
77
- }
78
- }
79
- @-moz-keyframes spinner {
80
- 0% {
81
- -webkit-transform: rotate(0deg);
82
- -moz-transform: rotate(0deg);
83
- -ms-transform: rotate(0deg);
84
- -o-transform: rotate(0deg);
85
- transform: rotate(0deg);
86
- }
87
- 100% {
88
- -webkit-transform: rotate(360deg);
89
- -moz-transform: rotate(360deg);
90
- -ms-transform: rotate(360deg);
91
- -o-transform: rotate(360deg);
92
- transform: rotate(360deg);
93
- }
94
- }
95
- @-o-keyframes spinner {
96
- 0% {
97
- -webkit-transform: rotate(0deg);
98
- -moz-transform: rotate(0deg);
99
- -ms-transform: rotate(0deg);
100
- -o-transform: rotate(0deg);
101
- transform: rotate(0deg);
102
- }
103
- 100% {
104
- -webkit-transform: rotate(360deg);
105
- -moz-transform: rotate(360deg);
106
- -ms-transform: rotate(360deg);
107
- -o-transform: rotate(360deg);
108
- transform: rotate(360deg);
109
- }
110
- }
111
- @keyframes spinner {
112
- 0% {
113
- -webkit-transform: rotate(0deg);
114
- -moz-transform: rotate(0deg);
115
- -ms-transform: rotate(0deg);
116
- -o-transform: rotate(0deg);
117
- transform: rotate(0deg);
118
- }
119
- 100% {
120
- -webkit-transform: rotate(360deg);
121
- -moz-transform: rotate(360deg);
122
- -ms-transform: rotate(360deg);
123
- -o-transform: rotate(360deg);
124
- transform: rotate(360deg);
125
- }
126
- }
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
- .icon-wpvrtourmake_icon:before {
141
- content: '';
142
- height: 30px;
143
- width: 30px;
144
- background: url('../images/icon.png') no-repeat center center / 100% 100%;
145
- }
146
- .scene-gallery {
147
- border-radius: 10px;
148
- max-width: 600px;
149
- margin: 0 auto;
150
- color: #32373c;
151
- background-color: #eceef1;
152
- }
153
- .scene-gallery ul {
154
- display: inline-grid;
155
- }
156
-
157
- .scctrl {
158
- border-radius: 5px;
159
- width: 100px;
160
- height: 100px;
161
- display: inline-block;
162
- cursor: pointer;
163
- margin: 5px;
164
- }
165
- .scctrl:hover {
166
- background: rgba(200, 200, 200, 1);
167
- }
168
- .vr-export {
169
- color: #fff!important;
170
- background-color: #2196F3!important;
171
- border: none;
172
- display: inline-block;
173
- padding: 8px 16px;
174
- vertical-align: middle;
175
- overflow: hidden;
176
- text-decoration: none;
177
- color: inherit;
178
- background-color: inherit;
179
- text-align: center;
180
- cursor: pointer;
181
- white-space: nowrap;
182
- }
183
- .rex-pano-tab-content ::-webkit-input-placeholder {
184
- color: #ccc;
185
- }
186
-
187
- .rex-pano-tab-content ::-moz-placeholder {
188
- color: #ccc;
189
- }
190
-
191
- .rex-pano-tab-content :-ms-input-placeholder {
192
- color: #ccc;
193
- }
194
 
195
  div.custom-tooltip span {
196
  visibility: hidden;
@@ -204,9 +17,6 @@ div.custom-tooltip span {
204
  margin: 0 0px 0px 12px !important;
205
  bottom: 40px;
206
  transform: translateX(-50%);
207
- min-width: 300px;
208
- font-size: 15px;
209
- line-height: 24px;
210
  }
211
  div.custom-tooltip:hover span{
212
  visibility: visible;
@@ -232,9 +42,7 @@ div.custom-tooltip:hover span:after {
232
  z-index: 99;
233
  width: 90%;
234
  }
235
- .icons-selector .selector {
236
- width: 100%;
237
- }
238
  .iframe-wrapper {
239
  max-width: 600px;
240
  position: relative;
@@ -254,7 +62,7 @@ div.custom-tooltip:hover span:after {
254
  background: rgba(0,0,0,0.4);
255
  width: 100%;
256
  height: 100%;
257
- z-index: 9;
258
  opacity: 0;
259
  visibility: hidden;
260
  transition: all 0.4s linear;
@@ -286,32 +94,11 @@ div.custom-tooltip:hover span:after {
286
  visibility: visible;
287
  }
288
 
289
- .post-type-wpvr_item:after {
290
- content: "";
291
- background: rgba(0, 0, 0, 0.54);
292
- top: 0;
293
- left: 0;
294
- width: 100%;
295
- height: 100%;
296
- position: fixed;
297
- opacity: 0;
298
- visibility: hidden;
299
- transition: all 0.4s ease;
300
- }
301
-
302
- .post-type-wpvr_item.error-overlay:after {
303
- opacity: 1;
304
- visibility: visible;
305
- }
306
-
307
  #custom-ifram p {
308
  background-color: #fff;
309
  padding: 10px;
310
  margin: auto;
311
  border-radius: 5px;
312
- text-align: center;
313
- font-size: 15px;
314
- line-height: 24px;
315
  }
316
 
317
  .custom-tooltip p {
@@ -341,85 +128,6 @@ div.custom-tooltip:hover span:after {
341
  width: 400px;
342
  }
343
 
344
- .rex-add-coordinates ul li {
345
- display: inline-block;
346
- text-align: center !important;
347
- cursor: pointer;
348
- vertical-align: middle;
349
- margin-bottom: 0;
350
- }
351
- .rex-add-coordinates ul li #panodata {
352
- margin-top: 0!important;
353
- font-size: 13px;
354
- }
355
- .rex-add-coordinates ul li.add-pitch {
356
- margin-bottom: 0;
357
- width: 20px;
358
- height: 20px;
359
- background: #222;
360
- color: #fff;
361
- border-radius: 100%;
362
- box-sizing: border-box;
363
- margin-left: 6px;
364
- position: relative;
365
- }
366
-
367
- .rex-hide-coordinates {
368
- display: none !important;
369
- }
370
-
371
- .toppitch {
372
- font-size: 11px;
373
- vertical-align: middle;
374
- }
375
-
376
- .rex-add-coordinates ul li.add-pitch .rex-tooltiptext {
377
- visibility: hidden;
378
- opacity: 0;
379
- width: auto;
380
- background-color: #222;
381
- color: #fff;
382
- text-align: center;
383
- border-radius: 5px;
384
- position: absolute;
385
- z-index: 1;
386
- top: -100%;
387
- left: 50%;
388
- padding: 6px 12px;
389
- white-space: nowrap;
390
- font-size: 11px;
391
- margin-top: -16px;
392
- letter-spacing: 0.5px;
393
- -webkit-transform: translateX(-50%);
394
- -moz-transform: translateX(-50%);
395
- -ms-transform: translateX(-50%);
396
- -o-transform: translateX(-50%);
397
- transform: translateX(-50%);
398
-
399
- -webkit-transition: all 0.5s ease;
400
- -moz-transition: all 0.5s ease;
401
- -ms-transition: all 0.5s ease;
402
- -o-transition: all 0.5s ease;
403
- transition: all 0.5s ease;
404
- }
405
-
406
- .rex-add-coordinates ul li.add-pitch .rex-tooltiptext::after {
407
- content: "";
408
- position: absolute;
409
- top: 100%;
410
- left: 50%;
411
- margin-left: -5px;
412
- border-width: 5px;
413
- border-style: solid;
414
- border-color: #222 transparent transparent transparent;
415
- }
416
-
417
- .rex-add-coordinates ul li.add-pitch:hover .rex-tooltiptext {
418
- visibility: visible;
419
- margin-top: -18px;
420
- opacity: 1;
421
- }
422
-
423
  @media (max-width: 1199px){
424
  .pnlm-container {
425
  width: 100%!important;
@@ -430,12 +138,12 @@ div.custom-tooltip:hover span:after {
430
  .custom-tooltip p {
431
  width: 420px;
432
  }
433
-
434
  .custom-tooltip span img {
435
  height: 230px;
436
  width: 420px;
437
  }
438
-
439
  }
440
  @media (max-width: 991px){
441
  div.custom-tooltip span {
@@ -448,7 +156,7 @@ div.custom-tooltip:hover span:after {
448
  height: 310px;
449
  width: 540px;
450
  }
451
-
452
  }
453
 
454
 
@@ -458,7 +166,7 @@ div.custom-tooltip:hover span:after {
458
  }
459
  .pano-setup {
460
  position: relative;
461
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
462
  }
463
  .rex-pano-tabs {
464
  position: relative;
@@ -485,7 +193,6 @@ div.custom-tooltip:hover span:after {
485
  text-transform: uppercase;
486
  color: #555555;
487
  cursor: pointer;
488
- white-space: nowrap;
489
  font-weight: 500;
490
  font-size: 16px;
491
  -webkit-user-select: none;
@@ -503,9 +210,6 @@ div.custom-tooltip:hover span:after {
503
  position: relative;
504
  transition: all 0.25s ease-in-out;
505
  }
506
- .rex-pano-tabs .rex-pano-tab-nav li:last-child span{
507
- margin-bottom: 0;
508
- }
509
  .rex-pano-tabs .rex-pano-tab-nav li span:after {
510
  content: "";
511
  position: absolute;
@@ -523,7 +227,7 @@ div.custom-tooltip:hover span:after {
523
  -o-transform: translateY(-50%) rotate(45deg);
524
  transform: translateY(-50%) rotate(45deg);
525
  transition: all 0.2s ease-in-out;
526
-
527
  }
528
 
529
  .rex-pano-tabs .rex-pano-tab-nav li.active > span:after{
@@ -534,10 +238,8 @@ div.custom-tooltip:hover span:after {
534
  font-size: 20px;
535
  margin-right: 5px;
536
  }
537
- .rex-pano-tabs .rex-pano-tab-nav li.video span i,
538
  .rex-pano-tabs .rex-pano-tab-nav li.scene span i {
539
  margin-right: 18px;
540
- vertical-align: middle;
541
  }
542
  .rex-pano-tabs .rex-pano-tab-nav li:hover > span,
543
  .rex-pano-tabs .rex-pano-tab-nav li.active > span {
@@ -599,8 +301,6 @@ div.custom-tooltip:hover span:after {
599
  background: #fff;
600
  width: 78%;
601
  border-left: 1px solid #d5e0fd;
602
- position: relative;
603
- align-self: stretch;
604
  }
605
  .rex-pano-tab-content .title {
606
  font-size: 18px;
@@ -626,8 +326,6 @@ div.custom-tooltip:hover span:after {
626
  .rex-pano-tab-content .title i {
627
  margin-right: 10px;
628
  }
629
- .rex-pano-tab-content .rex-pano-tab.streetview,
630
- .rex-pano-tab-content .rex-pano-tab.video,
631
  .rex-pano-tab-content .rex-pano-tab.general {
632
  padding: 50px 40px;
633
  }
@@ -716,15 +414,12 @@ div.custom-tooltip:hover span:after {
716
  .rex-pano-tab .single-settings:last-child {
717
  margin-bottom: 0px;
718
  }
719
- .rex-pano-tab .single-settings > span {
720
  min-width: 170px;
721
  font-size: 16px;
722
  display: block;
723
  color: #555555;
724
- font-weight: 400;
725
- }
726
- .rex-pano-tab.general .single-settings > span {
727
- min-width: 240px;
728
  }
729
  .rex-pano-tab .single-settings ul{
730
  margin: 0;
@@ -749,117 +444,11 @@ div.custom-tooltip:hover span:after {
749
  border-radius: 3px;
750
  }
751
 
752
- .single-scene .scene-content .scene-setting {
753
- max-width: 440px;
754
- }
755
-
756
- .rex-pano-tab .single-settings .colors label,
757
- .rex-pano-tab .single-settings .icons label{
758
- color: #555555;
759
- font-size: 15px;
760
- letter-spacing: 0;
761
- margin-right: 10px;
762
- }
763
- .rex-pano-tab .single-settings .colors {
764
- display: flex;
765
- flex-flow: row;
766
- align-items: center;
767
- margin-right: 20px;
768
- }
769
- .rex-pano-tab .single-settings .colors input[type="color"]{
770
- border: none;
771
- padding: 0;
772
- box-shadow: none;
773
- margin: 0;
774
- height: 36px;
775
- }
776
- .rex-pano-tab .single-settings .icons-selector .fip-box {
777
- width: 59px;
778
- }
779
-
780
- /*------------input field tooltip-----------*/
781
- .hotspot-icon input {
782
- width: 20% !important;
783
- }
784
- .rex-pano-tab.streetview .single-settings .field-tooltip,
785
- .rex-pano-tab.general .single-settings .field-tooltip {
786
- position: relative;
787
- padding-left: 10px;
788
- }
789
- .single-scene .scene-setting .field-tooltip,
790
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip {
791
- position: absolute;
792
- right: 0;
793
- bottom: 13px;
794
- }
795
- .rex-pano-tab.streetview .single-settings .field-tooltip i,
796
- .single-scene .scene-setting .field-tooltip i,
797
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip i,
798
- .rex-pano-tab.general .single-settings .field-tooltip i {
799
- font-size: 20px;
800
- cursor: help;
801
- }
802
- .rex-pano-tab.streetview .single-settings .field-tooltip span,
803
- .single-scene .scene-setting .field-tooltip span,
804
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip span,
805
- .rex-pano-tab.general .single-settings .field-tooltip span {
806
- position: absolute;
807
- top: 50%;
808
- font-weight: 300;
809
- background: #444;
810
- color: #fff;
811
- display: inline-block;
812
- text-align: center;
813
- min-width: 240px;
814
- max-width: 280px;
815
- padding: 7px 8px;
816
- font-size: 14px;
817
- left: 40px;
818
- line-height: 20px;
819
- border-radius: 3px;
820
- z-index: 1;
821
- opacity: 0;
822
- visibility: hidden;
823
- -webkit-transform: translateY(-50%);
824
- -moz-transform: translateY(-50%);
825
- -ms-transform: translateY(-50%);
826
- -o-transform: translateY(-50%);
827
- transform: translateY(-50%);
828
-
829
- -webkit-transition: all 0.5s ease;
830
- -moz-transition: all 0.5s ease;
831
- -ms-transition: all 0.5s ease;
832
- -o-transition: all 0.5s ease;
833
- transition: all 0.5s ease;
834
- }
835
- .rex-pano-tab.streetview .single-settings .field-tooltip span:before,
836
- .single-scene .scene-setting .field-tooltip span:before,
837
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip span:before,
838
- .rex-pano-tab.general .single-settings .field-tooltip span:before {
839
- content: "";
840
- position: absolute;
841
- left: -9px;
842
- top: 50%;
843
- width: 0;
844
- height: 0;
845
- border-top: 6px solid transparent;
846
- border-right: 9px solid #444;
847
- border-bottom: 6px solid transparent;
848
- -webkit-transform: translateY(-50%);
849
- -moz-transform: translateY(-50%);
850
- -ms-transform: translateY(-50%);
851
- -o-transform: translateY(-50%);
852
- transform: translateY(-50%);
853
- }
854
- .rex-pano-tab.streetview .single-settings .field-tooltip:hover span,
855
- .single-scene .scene-setting .field-tooltip:hover span,
856
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip:hover span,
857
- .rex-pano-tab.general .single-settings .field-tooltip:hover span {
858
- opacity: 1;
859
- visibility: visible;
860
- }
861
 
862
  /*------------sub tab style----------*/
 
 
 
863
  .rex-pano-sub-tabs .rex-pano-tab-nav {
864
  width: auto;
865
  padding: 50px 40px 30px;
@@ -955,55 +544,15 @@ div.custom-tooltip:hover span:after {
955
  .single-hotspot .hotspot-setting,
956
  .single-scene .scene-setting {
957
  margin-bottom: 21px;
958
- position: relative;
959
- }
960
- .single-hotspot .hotspot-setting .change-icon {
961
- position: absolute;
962
- bottom: 14px;
963
- right: 50px;
964
- font-size: 18px;
965
- }
966
- .single-hotspot .hotspot-setting .change-icon .custom-icon {
967
- width: 20px;
968
- height: 20px;
969
- display: block;
970
- }
971
-
972
- .pnlm-hotspot-base.icon1,
973
- .single-hotspot .hotspot-setting .change-icon .icon1 {
974
- background: url(../icon/audio.png) no-repeat center center / 100% 100%;
975
- }
976
- .pnlm-hotspot-base.icon2,
977
- .single-hotspot .hotspot-setting .change-icon .icon2 {
978
- background: url(../icon/video.png) no-repeat center center / 100% 100%;
979
- }
980
- .pnlm-hotspot-base.icon3,
981
- .single-hotspot .hotspot-setting .change-icon .icon3 {
982
- background: url(../icon/gallery.png) no-repeat center center / 100% 100%;
983
  }
984
- .pnlm-hotspot-base.icon4,
985
- .single-hotspot .hotspot-setting .change-icon .icon4 {
986
- background: url(../icon/info.png) no-repeat center center / 100% 100%;
987
- }
988
- .pnlm-hotspot-base.icon5,
989
- .single-hotspot .hotspot-setting .change-icon .icon5 {
990
- background: url(../icon/link.png) no-repeat center center / 100% 100%;
991
- }
992
-
993
  .single-hotspot .hotspot-setting label,
994
  .single-scene .scene-setting label {
995
  color: #494b51;
996
- font-size: 16px;
997
- font-weight: 400;
998
  display: block;
999
  margin-bottom: 10px;
1000
  }
1001
-
1002
- .rex-pano-tab .cp-logo-content .form-group textarea,
1003
- .rex-pano-tab .cp-logo-content .form-group input.cp-logo-upload,
1004
- .rex-pano-tab .streetview-setting .form-group input,
1005
- .rex-pano-tab .preview-setting input.preview-upload,
1006
- .rex-pano-tab .video-setting input.video-upload,
1007
  .single-hotspot .hotspot-setting select,
1008
  .single-hotspot .hotspot-setting textarea,
1009
  .single-hotspot .hotspot-setting input,
@@ -1018,23 +567,11 @@ div.custom-tooltip:hover span:after {
1018
  color: #454545;
1019
  border-radius: 3px;
1020
  }
1021
- .rex-pano-tab .streetview-setting .form-group input{
1022
- max-width: 100%;
1023
- }
1024
-
1025
- .single-settings.cp-logo-content .form-group img.cp-logo-img,
1026
- .single-settings.preview-setting .form-group img,
1027
  .single-scene .scene-setting .form-group img {
1028
  max-width: 400px;
1029
  width: 100%;
1030
- display: block;
1031
  margin-bottom: 15px;
1032
  }
1033
-
1034
-
1035
- .rex-pano-tab .cp-logo-content .form-group input.cp-logo-upload,
1036
- .rex-pano-tab .preview-setting input.preview-upload,
1037
- .rex-pano-tab .video-setting input.video-upload,
1038
  .single-scene .scene-setting input.scene-upload {
1039
  text-transform: uppercase;
1040
  font-weight: 500;
@@ -1044,71 +581,20 @@ div.custom-tooltip:hover span:after {
1044
  cursor: pointer;
1045
  transition: all 0.3s ease;
1046
  }
1047
-
1048
- .rex-pano-tab .single-settings.cp-logo-content {
1049
- display: block;
1050
- }
1051
- .rex-pano-tab .single-settings.cp-logo-content > span{
1052
- margin-bottom: 12px;
1053
- }
1054
- .single-settings.cp-logo-content .form-group {
1055
- width: 400px;
1056
- position: relative;
1057
- }
1058
- .single-settings.cp-logo-content .form-group img.cp-logo-img {
1059
- max-width: 100px;
1060
- width: auto;
1061
- }
1062
- .rex-pano-tab .cp-logo-content .form-group input.cp-logo-upload{
1063
- margin-top: 15px;
1064
- }
1065
- .rex-pano-tab.general .single-settings.cp-logo-content .field-tooltip{
1066
- position: absolute;
1067
- bottom: 12px;
1068
- right: -40px;
1069
- }
1070
-
1071
-
1072
- .rex-pano-tab .preview-setting input.preview-upload:hover,
1073
- .rex-pano-tab .video-setting .single-settings input.video-upload:hover,
1074
  .single-scene .scene-setting input.scene-upload:hover {
1075
  background: #3869f3;
1076
  }
1077
- .rex-pano-tab .streetview-setting .form-group input:focus,
1078
  .single-scene .scene-setting input.scene-upload:focus {
1079
  box-shadow: none;
1080
  outline: inherit;
1081
  }
1082
 
1083
- .rex-pano-tab .video-setting .single-settings {
1084
- align-items: flex-start;
1085
- }
1086
- .rex-pano-tab .video-setting input.video-upload {
1087
- max-width: 160px;
1088
- margin-top: 20px;
1089
- }
1090
- .rex-pano-tab .video-setting:before,
1091
- .rex-pano-tab .video-setting:after {
1092
- content: "";
1093
- display: table;
1094
- clear: both;
1095
- }
1096
 
1097
- .rex-pano-tab .single-settings.preview-setting {
1098
- display: block;
1099
- }
1100
- .single-settings.preview-setting .form-group input {
1101
- margin-bottom: 15px;
1102
- }
1103
- .rex-pano-tab .single-settings.preview-setting span {
1104
- margin-bottom: 10px;
1105
- }
1106
- .rex-pano-tab .single-settings.scene-fade-duration input {
1107
- width: 230px;
1108
- }
1109
 
1110
  /*--------------------hotspot style-------------------*/
1111
- .clearfix::before,
1112
  .clearfix::after {
1113
  content: " ";
1114
  display: table;
@@ -1120,7 +606,7 @@ div.custom-tooltip:hover span:after {
1120
  .hotspot-setup .rex-pano-tab-content {
1121
  padding: 30px 0px;
1122
  }
1123
- .hotspot-setup .single-hotspot > .wrapper,
1124
  .hotspot-setup .single-hotspot .hotspot-type {
1125
  float: left;
1126
  width: 50%;
@@ -1133,20 +619,11 @@ div.custom-tooltip:hover span:after {
1133
  resize: none;
1134
  min-height: 110px;
1135
  }
1136
- .rex-pano-tab .cp-logo-content .form-group textarea{
1137
- height: auto;
1138
- resize: none;
1139
- min-height: 110px;
1140
- }
1141
  .single-hotspot .hotspot-setting select,
1142
  .single-hotspot .hotspot-setting textarea,
1143
  .single-hotspot .hotspot-setting input{
1144
  max-width: 100%;
1145
  }
1146
- .hotspot-setup .hotspot-setting.custom-icon select {
1147
- max-width: calc(100% - 30px);
1148
- }
1149
-
1150
  .single-hotspot .hotspot-type .hotspot-scene,
1151
  .single-hotspot .hotspot-type .hotspot-hover,
1152
  .single-hotspot .hotspot-type .hotspot-content,
@@ -1195,8 +672,6 @@ button.delete-hotspot{
1195
  padding: 55px 0px;
1196
  border-top: 1px solid #e4eafe;
1197
  }
1198
- .streetview-setting #streetviewpreview,
1199
- .video-setting button#videopreview,
1200
  .preview-btn-area #panolenspreview {
1201
  text-transform: capitalize;
1202
  color: #fff;
@@ -1214,39 +689,27 @@ button.delete-hotspot{
1214
  box-shadow: 0px 7px 25px 0px rgba(56, 84, 163, 0.2);
1215
  float: right;
1216
  }
1217
- .video-setting button#videopreview:hover,
1218
  .preview-btn-area #panolenspreview:hover {
1219
  background: #3869f3;
1220
  box-shadow: none;
1221
  }
1222
 
1223
- #error_occured {
1224
- display: none;
 
1225
  min-height: 15px;
1226
- position: absolute;
1227
- top: 50%;
1228
- right: 50%;
1229
- background: #eee;
1230
- padding: 50px 50px;
1231
- min-width: 450px;
1232
- border-radius: 5px;
1233
- -webkit-transform: translate(50%, -50%);
1234
- -moz-transform: translate(50%, -50%);
1235
- -ms-transform: translate(50%, -50%);
1236
- -o-transform: translate(50%, -50%);
1237
- transform: translate(50%, -50%);
1238
- z-index: 2;
1239
- }
1240
- #error_occured p {
1241
  background: #fffbfb;
1242
  padding: 10px 25px;
1243
  margin: 0;
1244
  border: 1px solid #ffd9de;
1245
  color: #f93333;
1246
  border-radius: 5px;
1247
- font-size: 14px;
1248
  }
1249
- #error_occured p span{
1250
  font-weight: 500;
1251
  }
1252
 
@@ -1257,11 +720,10 @@ button.delete-hotspot{
1257
 
1258
 
1259
 
1260
-
1261
  /*-----------------responsive style------------------*/
1262
  @media (max-width: 1700px){
1263
  .rex-pano-tabs .main-nav li {
1264
- width: 162px;
1265
  }
1266
  .rex-pano-tabs .main-nav li span {
1267
  font-size: 15px;
@@ -1276,7 +738,7 @@ button.delete-hotspot{
1276
  width: 16px;
1277
  height: 16px;
1278
  }
1279
-
1280
  }
1281
 
1282
  @media (max-width: 1500px){
@@ -1289,8 +751,7 @@ button.delete-hotspot{
1289
  }
1290
  .rex-pano-tabs .main-nav li {
1291
  display: inline-block;
1292
- margin-right: 12px;
1293
- margin-bottom: 12px;
1294
  }
1295
  .rex-pano-tabs .main-nav li:last-child {
1296
  margin-right: 0px;
@@ -1298,7 +759,7 @@ button.delete-hotspot{
1298
  .rex-pano-tabs .main-nav li span {
1299
  margin-bottom: 0;
1300
  }
1301
-
1302
  .rex-pano-tab-content {
1303
  width: 100%;
1304
  }
@@ -1313,18 +774,7 @@ button.delete-hotspot{
1313
  transform: translateX(50%) rotate(45deg);
1314
  bottom: -8px;
1315
  }
1316
-
1317
- }
1318
-
1319
- @media (max-width: 1300px){
1320
- .preview-btn-area #error_occured {
1321
- float: none;
1322
- margin-bottom: 20px;
1323
- }
1324
- .preview-btn-area #panolenspreview {
1325
- float: none;
1326
- }
1327
-
1328
  }
1329
 
1330
  @media (max-width: 1199px){
@@ -1342,7 +792,6 @@ button.delete-hotspot{
1342
  .rex-pano-tabs .main-nav li span {
1343
  padding: 0 10px;
1344
  }
1345
- .rex-pano-tab-content .rex-pano-tab.video,
1346
  .rex-pano-tab-content .rex-pano-tab.general {
1347
  padding: 20px 20px;
1348
  }
@@ -1363,8 +812,8 @@ button.delete-hotspot{
1363
  .hotspot-setup .rex-pano-tab-content {
1364
  padding: 30px 0px 0;
1365
  }
1366
-
1367
-
1368
  .preview-btn-area {
1369
  padding: 0 0 55px 0px;
1370
  border-top: none;
@@ -1381,12 +830,7 @@ button.delete-hotspot{
1381
  input.delete-hotspot {
1382
  right: 5px;
1383
  top: 35px;
1384
- }
1385
-
1386
- .rex-pano-tab .single-settings.scene-fade-duration input {
1387
- width: 160px;
1388
- }
1389
-
1390
  }
1391
 
1392
  /**
@@ -1489,8 +933,8 @@ button.delete-hotspot{
1489
 
1490
  .onboarding-block .body .waves-effect:hover {
1491
  color: #fff;
1492
- box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14),
1493
- 0 1px 5px 0 rgba(0,0,0,0.12),
1494
  0 3px 1px -2px rgba(0,0,0,0.2)
1495
  }
1496
  .onboarding-block .body .social li a:hover {
@@ -1529,6 +973,17 @@ button.delete-hotspot{
1529
  padding: 0 !important
1530
  }
1531
 
 
 
 
 
 
 
 
 
 
 
 
1532
  .rex-onboarding .wrapper {
1533
  padding-right: 30px;
1534
  }
@@ -1600,7 +1055,7 @@ button.delete-hotspot{
1600
 
1601
 
1602
  .rex-upgrade .parent {
1603
- font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
1604
  counter-reset: my-counter;
1605
  width: 400px;
1606
  margin-bottom: 30px;
@@ -1694,7 +1149,7 @@ button.delete-hotspot{
1694
  .onboarding-block p {
1695
  font-size: 12px;
1696
  }
1697
-
1698
  }
1699
 
1700
  @media (max-width: 1400px) {
@@ -1781,34 +1236,5 @@ button.delete-hotspot{
1781
  .onboarding-block p {
1782
  font-size: 16px;
1783
  }
1784
-
1785
- }
1786
-
1787
- @media (max-width: 991px){
1788
- .single-hotspot .hotspot-setting select{
1789
- height: 46px!important;
1790
- }
1791
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip span {
1792
- top: inherit;
1793
- left: inherit;
1794
- right: -5px;
1795
- -webkit-transform: inherit;
1796
- -moz-transform: inherit;
1797
- -ms-transform: inherit;
1798
- -o-transform: inherit;
1799
- transform: inherit;
1800
- bottom: 42px;
1801
- }
1802
- .hotspot-setup .hotspot-setting.custom-icon .field-tooltip span:before {
1803
- left: inherit;
1804
- top: inherit;
1805
- -webkit-transform: translateY(0) rotate(-90deg);
1806
- -moz-transform: translateY(0) rotate(-90deg);
1807
- -ms-transform: translateY(0) rotate(-90deg);
1808
- -o-transform: translateY(0) rotate(-90deg);
1809
- transform: translateY(0) rotate(-90deg);
1810
- bottom: -10px;
1811
- right: 10px;
1812
- }
1813
-
1814
  }
3
  * included in this file.
4
  */
5
 
6
+ @import url('https://fonts.googleapis.com/css?family=Roboto:300,300i,400,500,700,900');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
8
  div.custom-tooltip span {
9
  visibility: hidden;
17
  margin: 0 0px 0px 12px !important;
18
  bottom: 40px;
19
  transform: translateX(-50%);
 
 
 
20
  }
21
  div.custom-tooltip:hover span{
22
  visibility: visible;
42
  z-index: 99;
43
  width: 90%;
44
  }
45
+
 
 
46
  .iframe-wrapper {
47
  max-width: 600px;
48
  position: relative;
62
  background: rgba(0,0,0,0.4);
63
  width: 100%;
64
  height: 100%;
65
+ z-index: 99;
66
  opacity: 0;
67
  visibility: hidden;
68
  transition: all 0.4s linear;
94
  visibility: visible;
95
  }
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  #custom-ifram p {
98
  background-color: #fff;
99
  padding: 10px;
100
  margin: auto;
101
  border-radius: 5px;
 
 
 
102
  }
103
 
104
  .custom-tooltip p {
128
  width: 400px;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  @media (max-width: 1199px){
132
  .pnlm-container {
133
  width: 100%!important;
138
  .custom-tooltip p {
139
  width: 420px;
140
  }
141
+
142
  .custom-tooltip span img {
143
  height: 230px;
144
  width: 420px;
145
  }
146
+
147
  }
148
  @media (max-width: 991px){
149
  div.custom-tooltip span {
156
  height: 310px;
157
  width: 540px;
158
  }
159
+
160
  }
161
 
162
 
166
  }
167
  .pano-setup {
168
  position: relative;
169
+ font-family: 'Roboto', sans-serif;
170
  }
171
  .rex-pano-tabs {
172
  position: relative;
193
  text-transform: uppercase;
194
  color: #555555;
195
  cursor: pointer;
 
196
  font-weight: 500;
197
  font-size: 16px;
198
  -webkit-user-select: none;
210
  position: relative;
211
  transition: all 0.25s ease-in-out;
212
  }
 
 
 
213
  .rex-pano-tabs .rex-pano-tab-nav li span:after {
214
  content: "";
215
  position: absolute;
227
  -o-transform: translateY(-50%) rotate(45deg);
228
  transform: translateY(-50%) rotate(45deg);
229
  transition: all 0.2s ease-in-out;
230
+
231
  }
232
 
233
  .rex-pano-tabs .rex-pano-tab-nav li.active > span:after{
238
  font-size: 20px;
239
  margin-right: 5px;
240
  }
 
241
  .rex-pano-tabs .rex-pano-tab-nav li.scene span i {
242
  margin-right: 18px;
 
243
  }
244
  .rex-pano-tabs .rex-pano-tab-nav li:hover > span,
245
  .rex-pano-tabs .rex-pano-tab-nav li.active > span {
301
  background: #fff;
302
  width: 78%;
303
  border-left: 1px solid #d5e0fd;
 
 
304
  }
305
  .rex-pano-tab-content .title {
306
  font-size: 18px;
326
  .rex-pano-tab-content .title i {
327
  margin-right: 10px;
328
  }
 
 
329
  .rex-pano-tab-content .rex-pano-tab.general {
330
  padding: 50px 40px;
331
  }
414
  .rex-pano-tab .single-settings:last-child {
415
  margin-bottom: 0px;
416
  }
417
+ .rex-pano-tab .single-settings span {
418
  min-width: 170px;
419
  font-size: 16px;
420
  display: block;
421
  color: #555555;
422
+ font-weight: 600;
 
 
 
423
  }
424
  .rex-pano-tab .single-settings ul{
425
  margin: 0;
444
  border-radius: 3px;
445
  }
446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
  /*------------sub tab style----------*/
449
+ .rex-pano-sub-tabs {
450
+
451
+ }
452
  .rex-pano-sub-tabs .rex-pano-tab-nav {
453
  width: auto;
454
  padding: 50px 40px 30px;
544
  .single-hotspot .hotspot-setting,
545
  .single-scene .scene-setting {
546
  margin-bottom: 21px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  }
 
 
 
 
 
 
 
 
 
548
  .single-hotspot .hotspot-setting label,
549
  .single-scene .scene-setting label {
550
  color: #494b51;
551
+ font-size: 18px;
552
+ font-weight: 500;
553
  display: block;
554
  margin-bottom: 10px;
555
  }
 
 
 
 
 
 
556
  .single-hotspot .hotspot-setting select,
557
  .single-hotspot .hotspot-setting textarea,
558
  .single-hotspot .hotspot-setting input,
567
  color: #454545;
568
  border-radius: 3px;
569
  }
 
 
 
 
 
 
570
  .single-scene .scene-setting .form-group img {
571
  max-width: 400px;
572
  width: 100%;
 
573
  margin-bottom: 15px;
574
  }
 
 
 
 
 
575
  .single-scene .scene-setting input.scene-upload {
576
  text-transform: uppercase;
577
  font-weight: 500;
581
  cursor: pointer;
582
  transition: all 0.3s ease;
583
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  .single-scene .scene-setting input.scene-upload:hover {
585
  background: #3869f3;
586
  }
 
587
  .single-scene .scene-setting input.scene-upload:focus {
588
  box-shadow: none;
589
  outline: inherit;
590
  }
591
 
 
 
 
 
 
 
 
 
 
 
 
 
 
592
 
593
+
594
+
 
 
 
 
 
 
 
 
 
 
595
 
596
  /*--------------------hotspot style-------------------*/
597
+ .clearfix::before,
598
  .clearfix::after {
599
  content: " ";
600
  display: table;
606
  .hotspot-setup .rex-pano-tab-content {
607
  padding: 30px 0px;
608
  }
609
+ .hotspot-setup .single-hotspot > .wrapper,
610
  .hotspot-setup .single-hotspot .hotspot-type {
611
  float: left;
612
  width: 50%;
619
  resize: none;
620
  min-height: 110px;
621
  }
 
 
 
 
 
622
  .single-hotspot .hotspot-setting select,
623
  .single-hotspot .hotspot-setting textarea,
624
  .single-hotspot .hotspot-setting input{
625
  max-width: 100%;
626
  }
 
 
 
 
627
  .single-hotspot .hotspot-type .hotspot-scene,
628
  .single-hotspot .hotspot-type .hotspot-hover,
629
  .single-hotspot .hotspot-type .hotspot-content,
672
  padding: 55px 0px;
673
  border-top: 1px solid #e4eafe;
674
  }
 
 
675
  .preview-btn-area #panolenspreview {
676
  text-transform: capitalize;
677
  color: #fff;
689
  box-shadow: 0px 7px 25px 0px rgba(56, 84, 163, 0.2);
690
  float: right;
691
  }
 
692
  .preview-btn-area #panolenspreview:hover {
693
  background: #3869f3;
694
  box-shadow: none;
695
  }
696
 
697
+ .preview-btn-area #error_occured {
698
+ display: block;
699
+ min-width: 150px;
700
  min-height: 15px;
701
+ float: left;
702
+ }
703
+ .preview-btn-area #error_occured p {
 
 
 
 
 
 
 
 
 
 
 
 
704
  background: #fffbfb;
705
  padding: 10px 25px;
706
  margin: 0;
707
  border: 1px solid #ffd9de;
708
  color: #f93333;
709
  border-radius: 5px;
710
+ font-size: 16px;
711
  }
712
+ .preview-btn-area #error_occured p span{
713
  font-weight: 500;
714
  }
715
 
720
 
721
 
722
 
 
723
  /*-----------------responsive style------------------*/
724
  @media (max-width: 1700px){
725
  .rex-pano-tabs .main-nav li {
726
+ width: 170px;
727
  }
728
  .rex-pano-tabs .main-nav li span {
729
  font-size: 15px;
738
  width: 16px;
739
  height: 16px;
740
  }
741
+
742
  }
743
 
744
  @media (max-width: 1500px){
751
  }
752
  .rex-pano-tabs .main-nav li {
753
  display: inline-block;
754
+ margin-right: 25px;
 
755
  }
756
  .rex-pano-tabs .main-nav li:last-child {
757
  margin-right: 0px;
759
  .rex-pano-tabs .main-nav li span {
760
  margin-bottom: 0;
761
  }
762
+
763
  .rex-pano-tab-content {
764
  width: 100%;
765
  }
774
  transform: translateX(50%) rotate(45deg);
775
  bottom: -8px;
776
  }
777
+
 
 
 
 
 
 
 
 
 
 
 
778
  }
779
 
780
  @media (max-width: 1199px){
792
  .rex-pano-tabs .main-nav li span {
793
  padding: 0 10px;
794
  }
 
795
  .rex-pano-tab-content .rex-pano-tab.general {
796
  padding: 20px 20px;
797
  }
812
  .hotspot-setup .rex-pano-tab-content {
813
  padding: 30px 0px 0;
814
  }
815
+
816
+
817
  .preview-btn-area {
818
  padding: 0 0 55px 0px;
819
  border-top: none;
830
  input.delete-hotspot {
831
  right: 5px;
832
  top: 35px;
833
+ }
 
 
 
 
 
834
  }
835
 
836
  /**
933
 
934
  .onboarding-block .body .waves-effect:hover {
935
  color: #fff;
936
+ box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14),
937
+ 0 1px 5px 0 rgba(0,0,0,0.12),
938
  0 3px 1px -2px rgba(0,0,0,0.2)
939
  }
940
  .onboarding-block .body .social li a:hover {
973
  padding: 0 !important
974
  }
975
 
976
+
977
+
978
+
979
+
980
+ .rex-onboarding .block-wrapper{
981
+ /*display: flex;
982
+ flex-flow: row;
983
+ justify-content: space-between;
984
+ align-items: flex-start;*/
985
+ }
986
+
987
  .rex-onboarding .wrapper {
988
  padding-right: 30px;
989
  }
1055
 
1056
 
1057
  .rex-upgrade .parent {
1058
+ font-family: 'Roboto';
1059
  counter-reset: my-counter;
1060
  width: 400px;
1061
  margin-bottom: 30px;
1149
  .onboarding-block p {
1150
  font-size: 12px;
1151
  }
1152
+
1153
  }
1154
 
1155
  @media (max-width: 1400px) {
1236
  .onboarding-block p {
1237
  font-size: 16px;
1238
  }
1239
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1240
  }
admin/icon/Document.png CHANGED
File without changes
admin/icon/Feedback.png CHANGED
File without changes
admin/icon/Heart.png CHANGED
File without changes
admin/icon/Rating.png CHANGED
File without changes
admin/icon/Social_Booster_Banner.png CHANGED
File without changes
admin/icon/Support.png CHANGED
File without changes
admin/icon/banner.png CHANGED
File without changes
admin/icon/icon-128x128.png CHANGED
File without changes
admin/icon/icon.png CHANGED
File without changes
admin/index.php CHANGED
File without changes
admin/js/jquery.repeater.min.js CHANGED
File without changes
admin/js/materialize.js CHANGED
File without changes
admin/js/materialize.min.js CHANGED
File without changes
admin/js/owl.carousel.js DELETED
@@ -1,1756 +0,0 @@
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/video.js DELETED
@@ -1,48094 +0,0 @@
1
- /**
2
- * @license
3
- * Video.js 7.1.0 <http://videojs.com/>
4
- * Copyright Brightcove, Inc. <https://www.brightcove.com/>
5
- * Available under Apache License Version 2.0
6
- * <https://github.com/videojs/video.js/blob/master/LICENSE>
7
- *
8
- * Includes vtt.js <https://github.com/mozilla/vtt.js>
9
- * Available under Apache License Version 2.0
10
- * <https://github.com/mozilla/vtt.js/blob/master/LICENSE>
11
- */
12
-
13
- (function (global, factory) {
14
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
15
- typeof define === 'function' && define.amd ? define(factory) :
16
- (global.videojs = factory());
17
- }(this, (function () {
18
- var version = "7.1.0";
19
-
20
- var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
21
-
22
- function createCommonjsModule(fn, module) {
23
- return module = { exports: {} }, fn(module, module.exports), module.exports;
24
- }
25
-
26
- var win;
27
-
28
- if (typeof window !== "undefined") {
29
- win = window;
30
- } else if (typeof commonjsGlobal !== "undefined") {
31
- win = commonjsGlobal;
32
- } else if (typeof self !== "undefined") {
33
- win = self;
34
- } else {
35
- win = {};
36
- }
37
-
38
- var window_1 = win;
39
-
40
- var empty = {};
41
-
42
- var empty$1 = /*#__PURE__*/Object.freeze({
43
- default: empty
44
- });
45
-
46
- var minDoc = ( empty$1 && empty ) || empty$1;
47
-
48
- var topLevel = typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof window !== 'undefined' ? window : {};
49
-
50
- var doccy;
51
-
52
- if (typeof document !== 'undefined') {
53
- doccy = document;
54
- } else {
55
- doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
56
-
57
- if (!doccy) {
58
- doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
59
- }
60
- }
61
-
62
- var document_1 = doccy;
63
-
64
- /**
65
- * @file log.js
66
- * @module log
67
- */
68
-
69
- var log = void 0;
70
-
71
- // This is the private tracking variable for logging level.
72
- var level = 'info';
73
-
74
- // This is the private tracking variable for the logging history.
75
- var history = [];
76
-
77
- /**
78
- * Log messages to the console and history based on the type of message
79
- *
80
- * @private
81
- * @param {string} type
82
- * The name of the console method to use.
83
- *
84
- * @param {Array} args
85
- * The arguments to be passed to the matching console method.
86
- */
87
- var logByType = function logByType(type, args) {
88
- var lvl = log.levels[level];
89
- var lvlRegExp = new RegExp('^(' + lvl + ')$');
90
-
91
- if (type !== 'log') {
92
-
93
- // Add the type to the front of the message when it's not "log".
94
- args.unshift(type.toUpperCase() + ':');
95
- }
96
-
97
- // Add a clone of the args at this point to history.
98
- if (history) {
99
- history.push([].concat(args));
100
- }
101
-
102
- // Add console prefix after adding to history.
103
- args.unshift('VIDEOJS:');
104
-
105
- // If there's no console then don't try to output messages, but they will
106
- // still be stored in history.
107
- if (!window_1.console) {
108
- return;
109
- }
110
-
111
- // Was setting these once outside of this function, but containing them
112
- // in the function makes it easier to test cases where console doesn't exist
113
- // when the module is executed.
114
- var fn = window_1.console[type];
115
-
116
- if (!fn && type === 'debug') {
117
- // Certain browsers don't have support for console.debug. For those, we
118
- // should default to the closest comparable log.
119
- fn = window_1.console.info || window_1.console.log;
120
- }
121
-
122
- // Bail out if there's no console or if this type is not allowed by the
123
- // current logging level.
124
- if (!fn || !lvl || !lvlRegExp.test(type)) {
125
- return;
126
- }
127
-
128
- fn[Array.isArray(args) ? 'apply' : 'call'](window_1.console, args);
129
- };
130
-
131
- /**
132
- * Logs plain debug messages. Similar to `console.log`.
133
- *
134
- * @class
135
- * @param {Mixed[]} args
136
- * One or more messages or objects that should be logged.
137
- */
138
- log = function log() {
139
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
140
- args[_key] = arguments[_key];
141
- }
142
-
143
- logByType('log', args);
144
- };
145
-
146
- /**
147
- * Enumeration of available logging levels, where the keys are the level names
148
- * and the values are `|`-separated strings containing logging methods allowed
149
- * in that logging level. These strings are used to create a regular expression
150
- * matching the function name being called.
151
- *
152
- * Levels provided by video.js are:
153
- *
154
- * - `off`: Matches no calls. Any value that can be cast to `false` will have
155
- * this effect. The most restrictive.
156
- * - `all`: Matches only Video.js-provided functions (`debug`, `log`,
157
- * `log.warn`, and `log.error`).
158
- * - `debug`: Matches `log.debug`, `log`, `log.warn`, and `log.error` calls.
159
- * - `info` (default): Matches `log`, `log.warn`, and `log.error` calls.
160
- * - `warn`: Matches `log.warn` and `log.error` calls.
161
- * - `error`: Matches only `log.error` calls.
162
- *
163
- * @type {Object}
164
- */
165
- log.levels = {
166
- all: 'debug|log|warn|error',
167
- off: '',
168
- debug: 'debug|log|warn|error',
169
- info: 'log|warn|error',
170
- warn: 'warn|error',
171
- error: 'error',
172
- DEFAULT: level
173
- };
174
-
175
- /**
176
- * Get or set the current logging level. If a string matching a key from
177
- * {@link log.levels} is provided, acts as a setter. Regardless of argument,
178
- * returns the current logging level.
179
- *
180
- * @param {string} [lvl]
181
- * Pass to set a new logging level.
182
- *
183
- * @return {string}
184
- * The current logging level.
185
- */
186
- log.level = function (lvl) {
187
- if (typeof lvl === 'string') {
188
- if (!log.levels.hasOwnProperty(lvl)) {
189
- throw new Error('"' + lvl + '" in not a valid log level');
190
- }
191
- level = lvl;
192
- }
193
- return level;
194
- };
195
-
196
- /**
197
- * Returns an array containing everything that has been logged to the history.
198
- *
199
- * This array is a shallow clone of the internal history record. However, its
200
- * contents are _not_ cloned; so, mutating objects inside this array will
201
- * mutate them in history.
202
- *
203
- * @return {Array}
204
- */
205
- log.history = function () {
206
- return history ? [].concat(history) : [];
207
- };
208
-
209
- /**
210
- * Clears the internal history tracking, but does not prevent further history
211
- * tracking.
212
- */
213
- log.history.clear = function () {
214
- if (history) {
215
- history.length = 0;
216
- }
217
- };
218
-
219
- /**
220
- * Disable history tracking if it is currently enabled.
221
- */
222
- log.history.disable = function () {
223
- if (history !== null) {
224
- history.length = 0;
225
- history = null;
226
- }
227
- };
228
-
229
- /**
230
- * Enable history tracking if it is currently disabled.
231
- */
232
- log.history.enable = function () {
233
- if (history === null) {
234
- history = [];
235
- }
236
- };
237
-
238
- /**
239
- * Logs error messages. Similar to `console.error`.
240
- *
241
- * @param {Mixed[]} args
242
- * One or more messages or objects that should be logged as an error
243
- */
244
- log.error = function () {
245
- for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
246
- args[_key2] = arguments[_key2];
247
- }
248
-
249
- return logByType('error', args);
250
- };
251
-
252
- /**
253
- * Logs warning messages. Similar to `console.warn`.
254
- *
255
- * @param {Mixed[]} args
256
- * One or more messages or objects that should be logged as a warning.
257
- */
258
- log.warn = function () {
259
- for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
260
- args[_key3] = arguments[_key3];
261
- }
262
-
263
- return logByType('warn', args);
264
- };
265
-
266
- /**
267
- * Logs debug messages. Similar to `console.debug`, but may also act as a comparable
268
- * log if `console.debug` is not available
269
- *
270
- * @param {Mixed[]} args
271
- * One or more messages or objects that should be logged as debug.
272
- */
273
- log.debug = function () {
274
- for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
275
- args[_key4] = arguments[_key4];
276
- }
277
-
278
- return logByType('debug', args);
279
- };
280
-
281
- var log$1 = log;
282
-
283
- function clean(s) {
284
- return s.replace(/\n\r?\s*/g, '');
285
- }
286
-
287
- var tsml = function tsml(sa) {
288
- var s = '',
289
- i = 0;
290
-
291
- for (; i < arguments.length; i++) {
292
- s += clean(sa[i]) + (arguments[i + 1] || '');
293
- }return s;
294
- };
295
-
296
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
297
- return typeof obj;
298
- } : function (obj) {
299
- return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
300
- };
301
-
302
- var classCallCheck = function (instance, Constructor) {
303
- if (!(instance instanceof Constructor)) {
304
- throw new TypeError("Cannot call a class as a function");
305
- }
306
- };
307
-
308
- var inherits = function (subClass, superClass) {
309
- if (typeof superClass !== "function" && superClass !== null) {
310
- throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
311
- }
312
-
313
- subClass.prototype = Object.create(superClass && superClass.prototype, {
314
- constructor: {
315
- value: subClass,
316
- enumerable: false,
317
- writable: true,
318
- configurable: true
319
- }
320
- });
321
- if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
322
- };
323
-
324
- var possibleConstructorReturn = function (self, call) {
325
- if (!self) {
326
- throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
327
- }
328
-
329
- return call && (typeof call === "object" || typeof call === "function") ? call : self;
330
- };
331
-
332
- var taggedTemplateLiteralLoose = function (strings, raw) {
333
- strings.raw = raw;
334
- return strings;
335
- };
336
-
337
- /**
338
- * @file obj.js
339
- * @module obj
340
- */
341
-
342
- /**
343
- * @callback obj:EachCallback
344
- *
345
- * @param {Mixed} value
346
- * The current key for the object that is being iterated over.
347
- *
348
- * @param {string} key
349
- * The current key-value for object that is being iterated over
350
- */
351
-
352
- /**
353
- * @callback obj:ReduceCallback
354
- *
355
- * @param {Mixed} accum
356
- * The value that is accumulating over the reduce loop.
357
- *
358
- * @param {Mixed} value
359
- * The current key for the object that is being iterated over.
360
- *
361
- * @param {string} key
362
- * The current key-value for object that is being iterated over
363
- *
364
- * @return {Mixed}
365
- * The new accumulated value.
366
- */
367
- var toString = Object.prototype.toString;
368
-
369
- /**
370
- * Get the keys of an Object
371
- *
372
- * @param {Object}
373
- * The Object to get the keys from
374
- *
375
- * @return {string[]}
376
- * An array of the keys from the object. Returns an empty array if the
377
- * object passed in was invalid or had no keys.
378
- *
379
- * @private
380
- */
381
- var keys = function keys(object) {
382
- return isObject(object) ? Object.keys(object) : [];
383
- };
384
-
385
- /**
386
- * Array-like iteration for objects.
387
- *
388
- * @param {Object} object
389
- * The object to iterate over
390
- *
391
- * @param {obj:EachCallback} fn
392
- * The callback function which is called for each key in the object.
393
- */
394
- function each(object, fn) {
395
- keys(object).forEach(function (key) {
396
- return fn(object[key], key);
397
- });
398
- }
399
-
400
- /**
401
- * Array-like reduce for objects.
402
- *
403
- * @param {Object} object
404
- * The Object that you want to reduce.
405
- *
406
- * @param {Function} fn
407
- * A callback function which is called for each key in the object. It
408
- * receives the accumulated value and the per-iteration value and key
409
- * as arguments.
410
- *
411
- * @param {Mixed} [initial = 0]
412
- * Starting value
413
- *
414
- * @return {Mixed}
415
- * The final accumulated value.
416
- */
417
- function reduce(object, fn) {
418
- var initial = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
419
-
420
- return keys(object).reduce(function (accum, key) {
421
- return fn(accum, object[key], key);
422
- }, initial);
423
- }
424
-
425
- /**
426
- * Object.assign-style object shallow merge/extend.
427
- *
428
- * @param {Object} target
429
- * @param {Object} ...sources
430
- * @return {Object}
431
- */
432
- function assign(target) {
433
- for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
434
- sources[_key - 1] = arguments[_key];
435
- }
436
-
437
- if (Object.assign) {
438
- return Object.assign.apply(Object, [target].concat(sources));
439
- }
440
-
441
- sources.forEach(function (source) {
442
- if (!source) {
443
- return;
444
- }
445
-
446
- each(source, function (value, key) {
447
- target[key] = value;
448
- });
449
- });
450
-
451
- return target;
452
- }
453
-
454
- /**
455
- * Returns whether a value is an object of any kind - including DOM nodes,
456
- * arrays, regular expressions, etc. Not functions, though.
457
- *
458
- * This avoids the gotcha where using `typeof` on a `null` value
459
- * results in `'object'`.
460
- *
461
- * @param {Object} value
462
- * @return {Boolean}
463
- */
464
- function isObject(value) {
465
- return !!value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object';
466
- }
467
-
468
- /**
469
- * Returns whether an object appears to be a "plain" object - that is, a
470
- * direct instance of `Object`.
471
- *
472
- * @param {Object} value
473
- * @return {Boolean}
474
- */
475
- function isPlain(value) {
476
- return isObject(value) && toString.call(value) === '[object Object]' && value.constructor === Object;
477
- }
478
-
479
- /**
480
- * @file computed-style.js
481
- * @module computed-style
482
- */
483
-
484
- /**
485
- * A safe getComputedStyle.
486
- *
487
- * This is needed because in Firefox, if the player is loaded in an iframe with
488
- * `display:none`, then `getComputedStyle` returns `null`, so, we do a null-check to
489
- * make sure that the player doesn't break in these cases.
490
- *
491
- * @param {Element} el
492
- * The element you want the computed style of
493
- *
494
- * @param {string} prop
495
- * The property name you want
496
- *
497
- * @see https://bugzilla.mozilla.org/show_bug.cgi?id=548397
498
- *
499
- * @static
500
- * @const
501
- */
502
- function computedStyle(el, prop) {
503
- if (!el || !prop) {
504
- return '';
505
- }
506
-
507
- if (typeof window_1.getComputedStyle === 'function') {
508
- var cs = window_1.getComputedStyle(el);
509
-
510
- return cs ? cs[prop] : '';
511
- }
512
-
513
- return '';
514
- }
515
-
516
- var _templateObject = taggedTemplateLiteralLoose(['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.'], ['Setting attributes in the second argument of createEl()\n has been deprecated. Use the third argument instead.\n createEl(type, properties, attributes). Attempting to set ', ' to ', '.']);
517
-
518
- /**
519
- * Detect if a value is a string with any non-whitespace characters.
520
- *
521
- * @param {string} str
522
- * The string to check
523
- *
524
- * @return {boolean}
525
- * - True if the string is non-blank
526
- * - False otherwise
527
- *
528
- */
529
- function isNonBlankString(str) {
530
- return typeof str === 'string' && /\S/.test(str);
531
- }
532
-
533
- /**
534
- * Throws an error if the passed string has whitespace. This is used by
535
- * class methods to be relatively consistent with the classList API.
536
- *
537
- * @param {string} str
538
- * The string to check for whitespace.
539
- *
540
- * @throws {Error}
541
- * Throws an error if there is whitespace in the string.
542
- *
543
- */
544
- function throwIfWhitespace(str) {
545
- if (/\s/.test(str)) {
546
- throw new Error('class has illegal whitespace characters');
547
- }
548
- }
549
-
550
- /**
551
- * Produce a regular expression for matching a className within an elements className.
552
- *
553
- * @param {string} className
554
- * The className to generate the RegExp for.
555
- *
556
- * @return {RegExp}
557
- * The RegExp that will check for a specific `className` in an elements
558
- * className.
559
- */
560
- function classRegExp(className) {
561
- return new RegExp('(^|\\s)' + className + '($|\\s)');
562
- }
563
-
564
- /**
565
- * Whether the current DOM interface appears to be real.
566
- *
567
- * @return {Boolean}
568
- */
569
- function isReal() {
570
- // Both document and window will never be undefined thanks to `global`.
571
- return document_1 === window_1.document;
572
- }
573
-
574
- /**
575
- * Determines, via duck typing, whether or not a value is a DOM element.
576
- *
577
- * @param {Mixed} value
578
- * The thing to check
579
- *
580
- * @return {boolean}
581
- * - True if it is a DOM element
582
- * - False otherwise
583
- */
584
- function isEl(value) {
585
- return isObject(value) && value.nodeType === 1;
586
- }
587
-
588
- /**
589
- * Determines if the current DOM is embedded in an iframe.
590
- *
591
- * @return {boolean}
592
- *
593
- */
594
- function isInFrame() {
595
-
596
- // We need a try/catch here because Safari will throw errors when attempting
597
- // to get either `parent` or `self`
598
- try {
599
- return window_1.parent !== window_1.self;
600
- } catch (x) {
601
- return true;
602
- }
603
- }
604
-
605
- /**
606
- * Creates functions to query the DOM using a given method.
607
- *
608
- * @param {string} method
609
- * The method to create the query with.
610
- *
611
- * @return {Function}
612
- * The query method
613
- */
614
- function createQuerier(method) {
615
- return function (selector, context) {
616
- if (!isNonBlankString(selector)) {
617
- return document_1[method](null);
618
- }
619
- if (isNonBlankString(context)) {
620
- context = document_1.querySelector(context);
621
- }
622
-
623
- var ctx = isEl(context) ? context : document_1;
624
-
625
- return ctx[method] && ctx[method](selector);
626
- };
627
- }
628
-
629
- /**
630
- * Creates an element and applies properties.
631
- *
632
- * @param {string} [tagName='div']
633
- * Name of tag to be created.
634
- *
635
- * @param {Object} [properties={}]
636
- * Element properties to be applied.
637
- *
638
- * @param {Object} [attributes={}]
639
- * Element attributes to be applied.
640
- *
641
- * @param {String|Element|TextNode|Array|Function} [content]
642
- * Contents for the element (see: {@link dom:normalizeContent})
643
- *
644
- * @return {Element}
645
- * The element that was created.
646
- */
647
- function createEl() {
648
- var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
649
- var properties = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
650
- var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
651
- var content = arguments[3];
652
-
653
- var el = document_1.createElement(tagName);
654
-
655
- Object.getOwnPropertyNames(properties).forEach(function (propName) {
656
- var val = properties[propName];
657
-
658
- // See #2176
659
- // We originally were accepting both properties and attributes in the
660
- // same object, but that doesn't work so well.
661
- if (propName.indexOf('aria-') !== -1 || propName === 'role' || propName === 'type') {
662
- log$1.warn(tsml(_templateObject, propName, val));
663
- el.setAttribute(propName, val);
664
-
665
- // Handle textContent since it's not supported everywhere and we have a
666
- // method for it.
667
- } else if (propName === 'textContent') {
668
- textContent(el, val);
669
- } else {
670
- el[propName] = val;
671
- }
672
- });
673
-
674
- Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
675
- el.setAttribute(attrName, attributes[attrName]);
676
- });
677
-
678
- if (content) {
679
- appendContent(el, content);
680
- }
681
-
682
- return el;
683
- }
684
-
685
- /**
686
- * Injects text into an element, replacing any existing contents entirely.
687
- *
688
- * @param {Element} el
689
- * The element to add text content into
690
- *
691
- * @param {string} text
692
- * The text content to add.
693
- *
694
- * @return {Element}
695
- * The element with added text content.
696
- */
697
- function textContent(el, text) {
698
- if (typeof el.textContent === 'undefined') {
699
- el.innerText = text;
700
- } else {
701
- el.textContent = text;
702
- }
703
- return el;
704
- }
705
-
706
- /**
707
- * Insert an element as the first child node of another
708
- *
709
- * @param {Element} child
710
- * Element to insert
711
- *
712
- * @param {Element} parent
713
- * Element to insert child into
714
- */
715
- function prependTo(child, parent) {
716
- if (parent.firstChild) {
717
- parent.insertBefore(child, parent.firstChild);
718
- } else {
719
- parent.appendChild(child);
720
- }
721
- }
722
-
723
- /**
724
- * Check if an element has a CSS class
725
- *
726
- * @param {Element} element
727
- * Element to check
728
- *
729
- * @param {string} classToCheck
730
- * Class name to check for
731
- *
732
- * @return {boolean}
733
- * - True if the element had the class
734
- * - False otherwise.
735
- *
736
- * @throws {Error}
737
- * Throws an error if `classToCheck` has white space.
738
- */
739
- function hasClass(element, classToCheck) {
740
- throwIfWhitespace(classToCheck);
741
- if (element.classList) {
742
- return element.classList.contains(classToCheck);
743
- }
744
- return classRegExp(classToCheck).test(element.className);
745
- }
746
-
747
- /**
748
- * Add a CSS class name to an element
749
- *
750
- * @param {Element} element
751
- * Element to add class name to.
752
- *
753
- * @param {string} classToAdd
754
- * Class name to add.
755
- *
756
- * @return {Element}
757
- * The dom element with the added class name.
758
- */
759
- function addClass(element, classToAdd) {
760
- if (element.classList) {
761
- element.classList.add(classToAdd);
762
-
763
- // Don't need to `throwIfWhitespace` here because `hasElClass` will do it
764
- // in the case of classList not being supported.
765
- } else if (!hasClass(element, classToAdd)) {
766
- element.className = (element.className + ' ' + classToAdd).trim();
767
- }
768
-
769
- return element;
770
- }
771
-
772
- /**
773
- * Remove a CSS class name from an element
774
- *
775
- * @param {Element} element
776
- * Element to remove a class name from.
777
- *
778
- * @param {string} classToRemove
779
- * Class name to remove
780
- *
781
- * @return {Element}
782
- * The dom element with class name removed.
783
- */
784
- function removeClass(element, classToRemove) {
785
- if (element.classList) {
786
- element.classList.remove(classToRemove);
787
- } else {
788
- throwIfWhitespace(classToRemove);
789
- element.className = element.className.split(/\s+/).filter(function (c) {
790
- return c !== classToRemove;
791
- }).join(' ');
792
- }
793
-
794
- return element;
795
- }
796
-
797
- /**
798
- * The callback definition for toggleElClass.
799
- *
800
- * @callback Dom~PredicateCallback
801
- * @param {Element} element
802
- * The DOM element of the Component.
803
- *
804
- * @param {string} classToToggle
805
- * The `className` that wants to be toggled
806
- *
807
- * @return {boolean|undefined}
808
- * - If true the `classToToggle` will get added to `element`.
809
- * - If false the `classToToggle` will get removed from `element`.
810
- * - If undefined this callback will be ignored
811
- */
812
-
813
- /**
814
- * Adds or removes a CSS class name on an element depending on an optional
815
- * condition or the presence/absence of the class name.
816
- *
817
- * @param {Element} element
818
- * The element to toggle a class name on.
819
- *
820
- * @param {string} classToToggle
821
- * The class that should be toggled
822
- *
823
- * @param {boolean|PredicateCallback} [predicate]
824
- * See the return value for {@link Dom~PredicateCallback}
825
- *
826
- * @return {Element}
827
- * The element with a class that has been toggled.
828
- */
829
- function toggleClass(element, classToToggle, predicate) {
830
-
831
- // This CANNOT use `classList` internally because IE11 does not support the
832
- // second parameter to the `classList.toggle()` method! Which is fine because
833
- // `classList` will be used by the add/remove functions.
834
- var has = hasClass(element, classToToggle);
835
-
836
- if (typeof predicate === 'function') {
837
- predicate = predicate(element, classToToggle);
838
- }
839
-
840
- if (typeof predicate !== 'boolean') {
841
- predicate = !has;
842
- }
843
-
844
- // If the necessary class operation matches the current state of the
845
- // element, no action is required.
846
- if (predicate === has) {
847
- return;
848
- }
849
-
850
- if (predicate) {
851
- addClass(element, classToToggle);
852
- } else {
853
- removeClass(element, classToToggle);
854
- }
855
-
856
- return element;
857
- }
858
-
859
- /**
860
- * Apply attributes to an HTML element.
861
- *
862
- * @param {Element} el
863
- * Element to add attributes to.
864
- *
865
- * @param {Object} [attributes]
866
- * Attributes to be applied.
867
- */
868
- function setAttributes(el, attributes) {
869
- Object.getOwnPropertyNames(attributes).forEach(function (attrName) {
870
- var attrValue = attributes[attrName];
871
-
872
- if (attrValue === null || typeof attrValue === 'undefined' || attrValue === false) {
873
- el.removeAttribute(attrName);
874
- } else {
875
- el.setAttribute(attrName, attrValue === true ? '' : attrValue);
876
- }
877
- });
878
- }
879
-
880
- /**
881
- * Get an element's attribute values, as defined on the HTML tag
882
- * Attributes are not the same as properties. They're defined on the tag
883
- * or with setAttribute (which shouldn't be used with HTML)
884
- * This will return true or false for boolean attributes.
885
- *
886
- * @param {Element} tag
887
- * Element from which to get tag attributes.
888
- *
889
- * @return {Object}
890
- * All attributes of the element.
891
- */
892
- function getAttributes(tag) {
893
- var obj = {};
894
-
895
- // known boolean attributes
896
- // we can check for matching boolean properties, but not all browsers
897
- // and not all tags know about these attributes, so, we still want to check them manually
898
- var knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ',';
899
-
900
- if (tag && tag.attributes && tag.attributes.length > 0) {
901
- var attrs = tag.attributes;
902
-
903
- for (var i = attrs.length - 1; i >= 0; i--) {
904
- var attrName = attrs[i].name;
905
- var attrVal = attrs[i].value;
906
-
907
- // check for known booleans
908
- // the matching element property will return a value for typeof
909
- if (typeof tag[attrName] === 'boolean' || knownBooleans.indexOf(',' + attrName + ',') !== -1) {
910
- // the value of an included boolean attribute is typically an empty
911
- // string ('') which would equal false if we just check for a false value.
912
- // we also don't want support bad code like autoplay='false'
913
- attrVal = attrVal !== null ? true : false;
914
- }
915
-
916
- obj[attrName] = attrVal;
917
- }
918
- }
919
-
920
- return obj;
921
- }
922
-
923
- /**
924
- * Get the value of an element's attribute
925
- *
926
- * @param {Element} el
927
- * A DOM element
928
- *
929
- * @param {string} attribute
930
- * Attribute to get the value of
931
- *
932
- * @return {string}
933
- * value of the attribute
934
- */
935
- function getAttribute(el, attribute) {
936
- return el.getAttribute(attribute);
937
- }
938
-
939
- /**
940
- * Set the value of an element's attribute
941
- *
942
- * @param {Element} el
943
- * A DOM element
944
- *
945
- * @param {string} attribute
946
- * Attribute to set
947
- *
948
- * @param {string} value
949
- * Value to set the attribute to
950
- */
951
- function setAttribute(el, attribute, value) {
952
- el.setAttribute(attribute, value);
953
- }
954
-
955
- /**
956
- * Remove an element's attribute
957
- *
958
- * @param {Element} el
959
- * A DOM element
960
- *
961
- * @param {string} attribute
962
- * Attribute to remove
963
- */
964
- function removeAttribute(el, attribute) {
965
- el.removeAttribute(attribute);
966
- }
967
-
968
- /**
969
- * Attempt to block the ability to select text while dragging controls
970
- */
971
- function blockTextSelection() {
972
- document_1.body.focus();
973
- document_1.onselectstart = function () {
974
- return false;
975
- };
976
- }
977
-
978
- /**
979
- * Turn off text selection blocking
980
- */
981
- function unblockTextSelection() {
982
- document_1.onselectstart = function () {
983
- return true;
984
- };
985
- }
986
-
987
- /**
988
- * Identical to the native `getBoundingClientRect` function, but ensures that
989
- * the method is supported at all (it is in all browsers we claim to support)
990
- * and that the element is in the DOM before continuing.
991
- *
992
- * This wrapper function also shims properties which are not provided by some
993
- * older browsers (namely, IE8).
994
- *
995
- * Additionally, some browsers do not support adding properties to a
996
- * `ClientRect`/`DOMRect` object; so, we shallow-copy it with the standard
997
- * properties (except `x` and `y` which are not widely supported). This helps
998
- * avoid implementations where keys are non-enumerable.
999
- *
1000
- * @param {Element} el
1001
- * Element whose `ClientRect` we want to calculate.
1002
- *
1003
- * @return {Object|undefined}
1004
- * Always returns a plain
1005
- */
1006
- function getBoundingClientRect(el) {
1007
- if (el && el.getBoundingClientRect && el.parentNode) {
1008
- var rect = el.getBoundingClientRect();
1009
- var result = {};
1010
-
1011
- ['bottom', 'height', 'left', 'right', 'top', 'width'].forEach(function (k) {
1012
- if (rect[k] !== undefined) {
1013
- result[k] = rect[k];
1014
- }
1015
- });
1016
-
1017
- if (!result.height) {
1018
- result.height = parseFloat(computedStyle(el, 'height'));
1019
- }
1020
-
1021
- if (!result.width) {
1022
- result.width = parseFloat(computedStyle(el, 'width'));
1023
- }
1024
-
1025
- return result;
1026
- }
1027
- }
1028
-
1029
- /**
1030
- * The postion of a DOM element on the page.
1031
- *
1032
- * @typedef {Object} module:dom~Position
1033
- *
1034
- * @property {number} left
1035
- * Pixels to the left
1036
- *
1037
- * @property {number} top
1038
- * Pixels on top
1039
- */
1040
-
1041
- /**
1042
- * Offset Left.
1043
- * getBoundingClientRect technique from
1044
- * John Resig
1045
- *
1046
- * @see http://ejohn.org/blog/getboundingclientrect-is-awesome/
1047
- *
1048
- * @param {Element} el
1049
- * Element from which to get offset
1050
- *
1051
- * @return {module:dom~Position}
1052
- * The position of the element that was passed in.
1053
- */
1054
- function findPosition(el) {
1055
- var box = void 0;
1056
-
1057
- if (el.getBoundingClientRect && el.parentNode) {
1058
- box = el.getBoundingClientRect();
1059
- }
1060
-
1061
- if (!box) {
1062
- return {
1063
- left: 0,
1064
- top: 0
1065
- };
1066
- }
1067
-
1068
- var docEl = document_1.documentElement;
1069
- var body = document_1.body;
1070
-
1071
- var clientLeft = docEl.clientLeft || body.clientLeft || 0;
1072
- var scrollLeft = window_1.pageXOffset || body.scrollLeft;
1073
- var left = box.left + scrollLeft - clientLeft;
1074
-
1075
- var clientTop = docEl.clientTop || body.clientTop || 0;
1076
- var scrollTop = window_1.pageYOffset || body.scrollTop;
1077
- var top = box.top + scrollTop - clientTop;
1078
-
1079
- // Android sometimes returns slightly off decimal values, so need to round
1080
- return {
1081
- left: Math.round(left),
1082
- top: Math.round(top)
1083
- };
1084
- }
1085
-
1086
- /**
1087
- * x and y coordinates for a dom element or mouse pointer
1088
- *
1089
- * @typedef {Object} Dom~Coordinates
1090
- *
1091
- * @property {number} x
1092
- * x coordinate in pixels
1093
- *
1094
- * @property {number} y
1095
- * y coordinate in pixels
1096
- */
1097
-
1098
- /**
1099
- * Get pointer position in element
1100
- * Returns an object with x and y coordinates.
1101
- * The base on the coordinates are the bottom left of the element.
1102
- *
1103
- * @param {Element} el
1104
- * Element on which to get the pointer position on
1105
- *
1106
- * @param {EventTarget~Event} event
1107
- * Event object
1108
- *
1109
- * @return {Dom~Coordinates}
1110
- * A Coordinates object corresponding to the mouse position.
1111
- *
1112
- */
1113
- function getPointerPosition(el, event) {
1114
- var position = {};
1115
- var box = findPosition(el);
1116
- var boxW = el.offsetWidth;
1117
- var boxH = el.offsetHeight;
1118
-
1119
- var boxY = box.top;
1120
- var boxX = box.left;
1121
- var pageY = event.pageY;
1122
- var pageX = event.pageX;
1123
-
1124
- if (event.changedTouches) {
1125
- pageX = event.changedTouches[0].pageX;
1126
- pageY = event.changedTouches[0].pageY;
1127
- }
1128
-
1129
- position.y = Math.max(0, Math.min(1, (boxY - pageY + boxH) / boxH));
1130
- position.x = Math.max(0, Math.min(1, (pageX - boxX) / boxW));
1131
-
1132
- return position;
1133
- }
1134
-
1135
- /**
1136
- * Determines, via duck typing, whether or not a value is a text node.
1137
- *
1138
- * @param {Mixed} value
1139
- * Check if this value is a text node.
1140
- *
1141
- * @return {boolean}
1142
- * - True if it is a text node
1143
- * - False otherwise
1144
- */
1145
- function isTextNode(value) {
1146
- return isObject(value) && value.nodeType === 3;
1147
- }
1148
-
1149
- /**
1150
- * Empties the contents of an element.
1151
- *
1152
- * @param {Element} el
1153
- * The element to empty children from
1154
- *
1155
- * @return {Element}
1156
- * The element with no children
1157
- */
1158
- function emptyEl(el) {
1159
- while (el.firstChild) {
1160
- el.removeChild(el.firstChild);
1161
- }
1162
- return el;
1163
- }
1164
-
1165
- /**
1166
- * Normalizes content for eventual insertion into the DOM.
1167
- *
1168
- * This allows a wide range of content definition methods, but protects
1169
- * from falling into the trap of simply writing to `innerHTML`, which is
1170
- * an XSS concern.
1171
- *
1172
- * The content for an element can be passed in multiple types and
1173
- * combinations, whose behavior is as follows:
1174
- *
1175
- * @param {String|Element|TextNode|Array|Function} content
1176
- * - String: Normalized into a text node.
1177
- * - Element/TextNode: Passed through.
1178
- * - Array: A one-dimensional array of strings, elements, nodes, or functions
1179
- * (which return single strings, elements, or nodes).
1180
- * - Function: If the sole argument, is expected to produce a string, element,
1181
- * node, or array as defined above.
1182
- *
1183
- * @return {Array}
1184
- * All of the content that was passed in normalized.
1185
- */
1186
- function normalizeContent(content) {
1187
-
1188
- // First, invoke content if it is a function. If it produces an array,
1189
- // that needs to happen before normalization.
1190
- if (typeof content === 'function') {
1191
- content = content();
1192
- }
1193
-
1194
- // Next up, normalize to an array, so one or many items can be normalized,
1195
- // filtered, and returned.
1196
- return (Array.isArray(content) ? content : [content]).map(function (value) {
1197
-
1198
- // First, invoke value if it is a function to produce a new value,
1199
- // which will be subsequently normalized to a Node of some kind.
1200
- if (typeof value === 'function') {
1201
- value = value();
1202
- }
1203
-
1204
- if (isEl(value) || isTextNode(value)) {
1205
- return value;
1206
- }
1207
-
1208
- if (typeof value === 'string' && /\S/.test(value)) {
1209
- return document_1.createTextNode(value);
1210
- }
1211
- }).filter(function (value) {
1212
- return value;
1213
- });
1214
- }
1215
-
1216
- /**
1217
- * Normalizes and appends content to an element.
1218
- *
1219
- * @param {Element} el
1220
- * Element to append normalized content to.
1221
- *
1222
- *
1223
- * @param {String|Element|TextNode|Array|Function} content
1224
- * See the `content` argument of {@link dom:normalizeContent}
1225
- *
1226
- * @return {Element}
1227
- * The element with appended normalized content.
1228
- */
1229
- function appendContent(el, content) {
1230
- normalizeContent(content).forEach(function (node) {
1231
- return el.appendChild(node);
1232
- });
1233
- return el;
1234
- }
1235
-
1236
- /**
1237
- * Normalizes and inserts content into an element; this is identical to
1238
- * `appendContent()`, except it empties the element first.
1239
- *
1240
- * @param {Element} el
1241
- * Element to insert normalized content into.
1242
- *
1243
- * @param {String|Element|TextNode|Array|Function} content
1244
- * See the `content` argument of {@link dom:normalizeContent}
1245
- *
1246
- * @return {Element}
1247
- * The element with inserted normalized content.
1248
- *
1249
- */
1250
- function insertContent(el, content) {
1251
- return appendContent(emptyEl(el), content);
1252
- }
1253
-
1254
- /**
1255
- * Check if event was a single left click
1256
- *
1257
- * @param {EventTarget~Event} event
1258
- * Event object
1259
- *
1260
- * @return {boolean}
1261
- * - True if a left click
1262
- * - False if not a left click
1263
- */
1264
- function isSingleLeftClick(event) {
1265
- // Note: if you create something draggable, be sure to
1266
- // call it on both `mousedown` and `mousemove` event,
1267
- // otherwise `mousedown` should be enough for a button
1268
-
1269
- if (event.button === undefined && event.buttons === undefined) {
1270
- // Why do we need `buttons` ?
1271
- // Because, middle mouse sometimes have this:
1272
- // e.button === 0 and e.buttons === 4
1273
- // Furthermore, we want to prevent combination click, something like
1274
- // HOLD middlemouse then left click, that would be
1275
- // e.button === 0, e.buttons === 5
1276
- // just `button` is not gonna work
1277
-
1278
- // Alright, then what this block does ?
1279
- // this is for chrome `simulate mobile devices`
1280
- // I want to support this as well
1281
-
1282
- return true;
1283
- }
1284
-
1285
- if (event.button === 0 && event.buttons === undefined) {
1286
- // Touch screen, sometimes on some specific device, `buttons`
1287
- // doesn't have anything (safari on ios, blackberry...)
1288
-
1289
- return true;
1290
- }
1291
-
1292
- if (event.button !== 0 || event.buttons !== 1) {
1293
- // This is the reason we have those if else block above
1294
- // if any special case we can catch and let it slide
1295
- // we do it above, when get to here, this definitely
1296
- // is-not-left-click
1297
-
1298
- return false;
1299
- }
1300
-
1301
- return true;
1302
- }
1303
-
1304
- /**
1305
- * Finds a single DOM element matching `selector` within the optional
1306
- * `context` of another DOM element (defaulting to `document`).
1307
- *
1308
- * @param {string} selector
1309
- * A valid CSS selector, which will be passed to `querySelector`.
1310
- *
1311
- * @param {Element|String} [context=document]
1312
- * A DOM element within which to query. Can also be a selector
1313
- * string in which case the first matching element will be used
1314
- * as context. If missing (or no element matches selector), falls
1315
- * back to `document`.
1316
- *
1317
- * @return {Element|null}
1318
- * The element that was found or null.
1319
- */
1320
- var $ = createQuerier('querySelector');
1321
-
1322
- /**
1323
- * Finds a all DOM elements matching `selector` within the optional
1324
- * `context` of another DOM element (defaulting to `document`).
1325
- *
1326
- * @param {string} selector
1327
- * A valid CSS selector, which will be passed to `querySelectorAll`.
1328
- *
1329
- * @param {Element|String} [context=document]
1330
- * A DOM element within which to query. Can also be a selector
1331
- * string in which case the first matching element will be used
1332
- * as context. If missing (or no element matches selector), falls
1333
- * back to `document`.
1334
- *
1335
- * @return {NodeList}
1336
- * A element list of elements that were found. Will be empty if none were found.
1337
- *
1338
- */
1339
- var $$ = createQuerier('querySelectorAll');
1340
-
1341
- var Dom = /*#__PURE__*/Object.freeze({
1342
- isReal: isReal,
1343
- isEl: isEl,
1344
- isInFrame: isInFrame,
1345
- createEl: createEl,
1346
- textContent: textContent,
1347
- prependTo: prependTo,
1348
- hasClass: hasClass,
1349
- addClass: addClass,
1350
- removeClass: removeClass,
1351
- toggleClass: toggleClass,
1352
- setAttributes: setAttributes,
1353
- getAttributes: getAttributes,
1354
- getAttribute: getAttribute,
1355
- setAttribute: setAttribute,
1356
- removeAttribute: removeAttribute,
1357
- blockTextSelection: blockTextSelection,
1358
- unblockTextSelection: unblockTextSelection,
1359
- getBoundingClientRect: getBoundingClientRect,
1360
- findPosition: findPosition,
1361
- getPointerPosition: getPointerPosition,
1362
- isTextNode: isTextNode,
1363
- emptyEl: emptyEl,
1364
- normalizeContent: normalizeContent,
1365
- appendContent: appendContent,
1366
- insertContent: insertContent,
1367
- isSingleLeftClick: isSingleLeftClick,
1368
- $: $,
1369
- $$: $$
1370
- });
1371
-
1372
- /**
1373
- * @file guid.js
1374
- * @module guid
1375
- */
1376
-
1377
- /**
1378
- * Unique ID for an element or function
1379
- * @type {Number}
1380
- */
1381
- var _guid = 1;
1382
-
1383
- /**
1384
- * Get a unique auto-incrementing ID by number that has not been returned before.
1385
- *
1386
- * @return {number}
1387
- * A new unique ID.
1388
- */
1389
- function newGUID() {
1390
- return _guid++;
1391
- }
1392
-
1393
- /**
1394
- * @file dom-data.js
1395
- * @module dom-data
1396
- */
1397
-
1398
- /**
1399
- * Element Data Store.
1400
- *
1401
- * Allows for binding data to an element without putting it directly on the
1402
- * element. Ex. Event listeners are stored here.
1403
- * (also from jsninja.com, slightly modified and updated for closure compiler)
1404
- *
1405
- * @type {Object}
1406
- * @private
1407
- */
1408
- var elData = {};
1409
-
1410
- /*
1411
- * Unique attribute name to store an element's guid in
1412
- *
1413
- * @type {String}
1414
- * @constant
1415
- * @private
1416
- */
1417
- var elIdAttr = 'vdata' + new Date().getTime();
1418
-
1419
- /**
1420
- * Returns the cache object where data for an element is stored
1421
- *
1422
- * @param {Element} el
1423
- * Element to store data for.
1424
- *
1425
- * @return {Object}
1426
- * The cache object for that el that was passed in.
1427
- */
1428
- function getData(el) {
1429
- var id = el[elIdAttr];
1430
-
1431
- if (!id) {
1432
- id = el[elIdAttr] = newGUID();
1433
- }
1434
-
1435
- if (!elData[id]) {
1436
- elData[id] = {};
1437
- }
1438
-
1439
- return elData[id];
1440
- }
1441
-
1442
- /**
1443
- * Returns whether or not an element has cached data
1444
- *
1445
- * @param {Element} el
1446
- * Check if this element has cached data.
1447
- *
1448
- * @return {boolean}
1449
- * - True if the DOM element has cached data.
1450
- * - False otherwise.
1451
- */
1452
- function hasData(el) {
1453
- var id = el[elIdAttr];
1454
-
1455
- if (!id) {
1456
- return false;
1457
- }
1458
-
1459
- return !!Object.getOwnPropertyNames(elData[id]).length;
1460
- }
1461
-
1462
- /**
1463
- * Delete data for the element from the cache and the guid attr from getElementById
1464
- *
1465
- * @param {Element} el
1466
- * Remove cached data for this element.
1467
- */
1468
- function removeData(el) {
1469
- var id = el[elIdAttr];
1470
-
1471
- if (!id) {
1472
- return;
1473
- }
1474
-
1475
- // Remove all stored data
1476
- delete elData[id];
1477
-
1478
- // Remove the elIdAttr property from the DOM node
1479
- try {
1480
- delete el[elIdAttr];
1481
- } catch (e) {
1482
- if (el.removeAttribute) {
1483
- el.removeAttribute(elIdAttr);
1484
- } else {
1485
- // IE doesn't appear to support removeAttribute on the document element
1486
- el[elIdAttr] = null;
1487
- }
1488
- }
1489
- }
1490
-
1491
- /**
1492
- * @file events.js. An Event System (John Resig - Secrets of a JS Ninja http://jsninja.com/)
1493
- * (Original book version wasn't completely usable, so fixed some things and made Closure Compiler compatible)
1494
- * This should work very similarly to jQuery's events, however it's based off the book version which isn't as
1495
- * robust as jquery's, so there's probably some differences.
1496
- *
1497
- * @module events
1498
- */
1499
-
1500
- /**
1501
- * Clean up the listener cache and dispatchers
1502
- *
1503
- * @param {Element|Object} elem
1504
- * Element to clean up
1505
- *
1506
- * @param {string} type
1507
- * Type of event to clean up
1508
- */
1509
- function _cleanUpEvents(elem, type) {
1510
- var data = getData(elem);
1511
-
1512
- // Remove the events of a particular type if there are none left
1513
- if (data.handlers[type].length === 0) {
1514
- delete data.handlers[type];
1515
- // data.handlers[type] = null;
1516
- // Setting to null was causing an error with data.handlers
1517
-
1518
- // Remove the meta-handler from the element
1519
- if (elem.removeEventListener) {
1520
- elem.removeEventListener(type, data.dispatcher, false);
1521
- } else if (elem.detachEvent) {
1522
- elem.detachEvent('on' + type, data.dispatcher);
1523
- }
1524
- }
1525
-
1526
- // Remove the events object if there are no types left
1527
- if (Object.getOwnPropertyNames(data.handlers).length <= 0) {
1528
- delete data.handlers;
1529
- delete data.dispatcher;
1530
- delete data.disabled;
1531
- }
1532
-
1533
- // Finally remove the element data if there is no data left
1534
- if (Object.getOwnPropertyNames(data).length === 0) {
1535
- removeData(elem);
1536
- }
1537
- }
1538
-
1539
- /**
1540
- * Loops through an array of event types and calls the requested method for each type.
1541
- *
1542
- * @param {Function} fn
1543
- * The event method we want to use.
1544
- *
1545
- * @param {Element|Object} elem
1546
- * Element or object to bind listeners to
1547
- *
1548
- * @param {string} type
1549
- * Type of event to bind to.
1550
- *
1551
- * @param {EventTarget~EventListener} callback
1552
- * Event listener.
1553
- */
1554
- function _handleMultipleEvents(fn, elem, types, callback) {
1555
- types.forEach(function (type) {
1556
- // Call the event method for each one of the types
1557
- fn(elem, type, callback);
1558
- });
1559
- }
1560
-
1561
- /**
1562
- * Fix a native event to have standard property values
1563
- *
1564
- * @param {Object} event
1565
- * Event object to fix.
1566
- *
1567
- * @return {Object}
1568
- * Fixed event object.
1569
- */
1570
- function fixEvent(event) {
1571
-
1572
- function returnTrue() {
1573
- return true;
1574
- }
1575
-
1576
- function returnFalse() {
1577
- return false;
1578
- }
1579
-
1580
- // Test if fixing up is needed
1581
- // Used to check if !event.stopPropagation instead of isPropagationStopped
1582
- // But native events return true for stopPropagation, but don't have
1583
- // other expected methods like isPropagationStopped. Seems to be a problem
1584
- // with the Javascript Ninja code. So we're just overriding all events now.
1585
- if (!event || !event.isPropagationStopped) {
1586
- var old = event || window_1.event;
1587
-
1588
- event = {};
1589
- // Clone the old object so that we can modify the values event = {};
1590
- // IE8 Doesn't like when you mess with native event properties
1591
- // Firefox returns false for event.hasOwnProperty('type') and other props
1592
- // which makes copying more difficult.
1593
- // TODO: Probably best to create a whitelist of event props
1594
- for (var key in old) {
1595
- // Safari 6.0.3 warns you if you try to copy deprecated layerX/Y
1596
- // Chrome warns you if you try to copy deprecated keyboardEvent.keyLocation
1597
- // and webkitMovementX/Y
1598
- if (key !== 'layerX' && key !== 'layerY' && key !== 'keyLocation' && key !== 'webkitMovementX' && key !== 'webkitMovementY') {
1599
- // Chrome 32+ warns if you try to copy deprecated returnValue, but
1600
- // we still want to if preventDefault isn't supported (IE8).
1601
- if (!(key === 'returnValue' && old.preventDefault)) {
1602
- event[key] = old[key];
1603
- }
1604
- }
1605
- }
1606
-
1607
- // The event occurred on this element
1608
- if (!event.target) {
1609
- event.target = event.srcElement || document_1;
1610
- }
1611
-
1612
- // Handle which other element the event is related to
1613
- if (!event.relatedTarget) {
1614
- event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
1615
- }
1616
-
1617
- // Stop the default browser action
1618
- event.preventDefault = function () {
1619
- if (old.preventDefault) {
1620
- old.preventDefault();
1621
- }
1622
- event.returnValue = false;
1623
- old.returnValue = false;
1624
- event.defaultPrevented = true;
1625
- };
1626
-
1627
- event.defaultPrevented = false;
1628
-
1629
- // Stop the event from bubbling
1630
- event.stopPropagation = function () {
1631
- if (old.stopPropagation) {
1632
- old.stopPropagation();
1633
- }
1634
- event.cancelBubble = true;
1635
- old.cancelBubble = true;
1636
- event.isPropagationStopped = returnTrue;
1637
- };
1638
-
1639
- event.isPropagationStopped = returnFalse;
1640
-
1641
- // Stop the event from bubbling and executing other handlers
1642
- event.stopImmediatePropagation = function () {
1643
- if (old.stopImmediatePropagation) {
1644
- old.stopImmediatePropagation();
1645
- }
1646
- event.isImmediatePropagationStopped = returnTrue;
1647
- event.stopPropagation();
1648
- };
1649
-
1650
- event.isImmediatePropagationStopped = returnFalse;
1651
-
1652
- // Handle mouse position
1653
- if (event.clientX !== null && event.clientX !== undefined) {
1654
- var doc = document_1.documentElement;
1655
- var body = document_1.body;
1656
-
1657
- event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
1658
- event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
1659
- }
1660
-
1661
- // Handle key presses
1662
- event.which = event.charCode || event.keyCode;
1663
-
1664
- // Fix button for mouse clicks:
1665
- // 0 == left; 1 == middle; 2 == right
1666
- if (event.button !== null && event.button !== undefined) {
1667
-
1668
- // The following is disabled because it does not pass videojs-standard
1669
- // and... yikes.
1670
- /* eslint-disable */
1671
- event.button = event.button & 1 ? 0 : event.button & 4 ? 1 : event.button & 2 ? 2 : 0;
1672
- /* eslint-enable */
1673
- }
1674
- }
1675
-
1676
- // Returns fixed-up instance
1677
- return event;
1678
- }
1679
-
1680
- /**
1681
- * Whether passive event listeners are supported
1682
- */
1683
- var _supportsPassive = false;
1684
-
1685
- (function () {
1686
- try {
1687
- var opts = Object.defineProperty({}, 'passive', {
1688
- get: function get() {
1689
- _supportsPassive = true;
1690
- }
1691
- });
1692
-
1693
- window_1.addEventListener('test', null, opts);
1694
- window_1.removeEventListener('test', null, opts);
1695
- } catch (e) {
1696
- // disregard
1697
- }
1698
- })();
1699
-
1700
- /**
1701
- * Touch events Chrome expects to be passive
1702
- */
1703
- var passiveEvents = ['touchstart', 'touchmove'];
1704
-
1705
- /**
1706
- * Add an event listener to element
1707
- * It stores the handler function in a separate cache object
1708
- * and adds a generic handler to the element's event,
1709
- * along with a unique id (guid) to the element.
1710
- *
1711
- * @param {Element|Object} elem
1712
- * Element or object to bind listeners to
1713
- *
1714
- * @param {string|string[]} type
1715
- * Type of event to bind to.
1716
- *
1717
- * @param {EventTarget~EventListener} fn
1718
- * Event listener.
1719
- */
1720
- function on(elem, type, fn) {
1721
- if (Array.isArray(type)) {
1722
- return _handleMultipleEvents(on, elem, type, fn);
1723
- }
1724
-
1725
- var data = getData(elem);
1726
-
1727
- // We need a place to store all our handler data
1728
- if (!data.handlers) {
1729
- data.handlers = {};
1730
- }
1731
-
1732
- if (!data.handlers[type]) {
1733
- data.handlers[type] = [];
1734
- }
1735
-
1736
- if (!fn.guid) {
1737
- fn.guid = newGUID();
1738
- }
1739
-
1740
- data.handlers[type].push(fn);
1741
-
1742
- if (!data.dispatcher) {
1743
- data.disabled = false;
1744
-
1745
- data.dispatcher = function (event, hash) {
1746
-
1747
- if (data.disabled) {
1748
- return;
1749
- }
1750
-
1751
- event = fixEvent(event);
1752
-
1753
- var handlers = data.handlers[event.type];
1754
-
1755
- if (handlers) {
1756
- // Copy handlers so if handlers are added/removed during the process it doesn't throw everything off.
1757
- var handlersCopy = handlers.slice(0);
1758
-
1759
- for (var m = 0, n = handlersCopy.length; m < n; m++) {
1760
- if (event.isImmediatePropagationStopped()) {
1761
- break;
1762
- } else {
1763
- try {
1764
- handlersCopy[m].call(elem, event, hash);
1765
- } catch (e) {
1766
- log$1.error(e);
1767
- }
1768
- }
1769
- }
1770
- }
1771
- };
1772
- }
1773
-
1774
- if (data.handlers[type].length === 1) {
1775
- if (elem.addEventListener) {
1776
- var options = false;
1777
-
1778
- if (_supportsPassive && passiveEvents.indexOf(type) > -1) {
1779
- options = { passive: true };
1780
- }
1781
- elem.addEventListener(type, data.dispatcher, options);
1782
- } else if (elem.attachEvent) {
1783
- elem.attachEvent('on' + type, data.dispatcher);
1784
- }
1785
- }
1786
- }
1787
-
1788
- /**
1789
- * Removes event listeners from an element
1790
- *
1791
- * @param {Element|Object} elem
1792
- * Object to remove listeners from.
1793
- *
1794
- * @param {string|string[]} [type]
1795
- * Type of listener to remove. Don't include to remove all events from element.
1796
- *
1797
- * @param {EventTarget~EventListener} [fn]
1798
- * Specific listener to remove. Don't include to remove listeners for an event
1799
- * type.
1800
- */
1801
- function off(elem, type, fn) {
1802
- // Don't want to add a cache object through getElData if not needed
1803
- if (!hasData(elem)) {
1804
- return;
1805
- }
1806
-
1807
- var data = getData(elem);
1808
-
1809
- // If no events exist, nothing to unbind
1810
- if (!data.handlers) {
1811
- return;
1812
- }
1813
-
1814
- if (Array.isArray(type)) {
1815
- return _handleMultipleEvents(off, elem, type, fn);
1816
- }
1817
-
1818
- // Utility function
1819
- var removeType = function removeType(el, t) {
1820
- data.handlers[t] = [];
1821
- _cleanUpEvents(el, t);
1822
- };
1823
-
1824
- // Are we removing all bound events?
1825
- if (type === undefined) {
1826
- for (var t in data.handlers) {
1827
- if (Object.prototype.hasOwnProperty.call(data.handlers || {}, t)) {
1828
- removeType(elem, t);
1829
- }
1830
- }
1831
- return;
1832
- }
1833
-
1834
- var handlers = data.handlers[type];
1835
-
1836
- // If no handlers exist, nothing to unbind
1837
- if (!handlers) {
1838
- return;
1839
- }
1840
-
1841
- // If no listener was provided, remove all listeners for type
1842
- if (!fn) {
1843
- removeType(elem, type);
1844
- return;
1845
- }
1846
-
1847
- // We're only removing a single handler
1848
- if (fn.guid) {
1849
- for (var n = 0; n < handlers.length; n++) {
1850
- if (handlers[n].guid === fn.guid) {
1851
- handlers.splice(n--, 1);
1852
- }
1853
- }
1854
- }
1855
-
1856
- _cleanUpEvents(elem, type);
1857
- }
1858
-
1859
- /**
1860
- * Trigger an event for an element
1861
- *
1862
- * @param {Element|Object} elem
1863
- * Element to trigger an event on
1864
- *
1865
- * @param {EventTarget~Event|string} event
1866
- * A string (the type) or an event object with a type attribute
1867
- *
1868
- * @param {Object} [hash]
1869
- * data hash to pass along with the event
1870
- *
1871
- * @return {boolean|undefined}
1872
- * - Returns the opposite of `defaultPrevented` if default was prevented
1873
- * - Otherwise returns undefined
1874
- */
1875
- function trigger(elem, event, hash) {
1876
- // Fetches element data and a reference to the parent (for bubbling).
1877
- // Don't want to add a data object to cache for every parent,
1878
- // so checking hasElData first.
1879
- var elemData = hasData(elem) ? getData(elem) : {};
1880
- var parent = elem.parentNode || elem.ownerDocument;
1881
- // type = event.type || event,
1882
- // handler;
1883
-
1884
- // If an event name was passed as a string, creates an event out of it
1885
- if (typeof event === 'string') {
1886
- event = { type: event, target: elem };
1887
- } else if (!event.target) {
1888
- event.target = elem;
1889
- }
1890
-
1891
- // Normalizes the event properties.
1892
- event = fixEvent(event);
1893
-
1894
- // If the passed element has a dispatcher, executes the established handlers.
1895
- if (elemData.dispatcher) {
1896
- elemData.dispatcher.call(elem, event, hash);
1897
- }
1898
-
1899
- // Unless explicitly stopped or the event does not bubble (e.g. media events)
1900
- // recursively calls this function to bubble the event up the DOM.
1901
- if (parent && !event.isPropagationStopped() && event.bubbles === true) {
1902
- trigger.call(null, parent, event, hash);
1903
-
1904
- // If at the top of the DOM, triggers the default action unless disabled.
1905
- } else if (!parent && !event.defaultPrevented) {
1906
- var targetData = getData(event.target);
1907
-
1908
- // Checks if the target has a default action for this event.
1909
- if (event.target[event.type]) {
1910
- // Temporarily disables event dispatching on the target as we have already executed the handler.
1911
- targetData.disabled = true;
1912
- // Executes the default action.
1913
- if (typeof event.target[event.type] === 'function') {
1914
- event.target[event.type]();
1915
- }
1916
- // Re-enables event dispatching.
1917
- targetData.disabled = false;
1918
- }
1919
- }
1920
-
1921
- // Inform the triggerer if the default was prevented by returning false
1922
- return !event.defaultPrevented;
1923
- }
1924
-
1925
- /**
1926
- * Trigger a listener only once for an event
1927
- *
1928
- * @param {Element|Object} elem
1929
- * Element or object to bind to.
1930
- *
1931
- * @param {string|string[]} type
1932
- * Name/type of event
1933
- *
1934
- * @param {Event~EventListener} fn
1935
- * Event Listener function
1936
- */
1937
- function one(elem, type, fn) {
1938
- if (Array.isArray(type)) {
1939
- return _handleMultipleEvents(one, elem, type, fn);
1940
- }
1941
- var func = function func() {
1942
- off(elem, type, func);
1943
- fn.apply(this, arguments);
1944
- };
1945
-
1946
- // copy the guid to the new function so it can removed using the original function's ID
1947
- func.guid = fn.guid = fn.guid || newGUID();
1948
- on(elem, type, func);
1949
- }
1950
-
1951
- var Events = /*#__PURE__*/Object.freeze({
1952
- fixEvent: fixEvent,
1953
- on: on,
1954
- off: off,
1955
- trigger: trigger,
1956
- one: one
1957
- });
1958
-
1959
- /**
1960
- * @file setup.js - Functions for setting up a player without
1961
- * user interaction based on the data-setup `attribute` of the video tag.
1962
- *
1963
- * @module setup
1964
- */
1965
-
1966
- var _windowLoaded = false;
1967
- var videojs = void 0;
1968
-
1969
- /**
1970
- * Set up any tags that have a data-setup `attribute` when the player is started.
1971
- */
1972
- var autoSetup = function autoSetup() {
1973
-
1974
- // Protect against breakage in non-browser environments and check global autoSetup option.
1975
- if (!isReal() || videojs.options.autoSetup === false) {
1976
- return;
1977
- }
1978
-
1979
- var vids = Array.prototype.slice.call(document_1.getElementsByTagName('video'));
1980
- var audios = Array.prototype.slice.call(document_1.getElementsByTagName('audio'));
1981
- var divs = Array.prototype.slice.call(document_1.getElementsByTagName('video-js'));
1982
- var mediaEls = vids.concat(audios, divs);
1983
-
1984
- // Check if any media elements exist
1985
- if (mediaEls && mediaEls.length > 0) {
1986
-
1987
- for (var i = 0, e = mediaEls.length; i < e; i++) {
1988
- var mediaEl = mediaEls[i];
1989
-
1990
- // Check if element exists, has getAttribute func.
1991
- if (mediaEl && mediaEl.getAttribute) {
1992
-
1993
- // Make sure this player hasn't already been set up.
1994
- if (mediaEl.player === undefined) {
1995
- var options = mediaEl.getAttribute('data-setup');
1996
-
1997
- // Check if data-setup attr exists.
1998
- // We only auto-setup if they've added the data-setup attr.
1999
- if (options !== null) {
2000
- // Create new video.js instance.
2001
- videojs(mediaEl);
2002
- }
2003
- }
2004
-
2005
- // If getAttribute isn't defined, we need to wait for the DOM.
2006
- } else {
2007
- autoSetupTimeout(1);
2008
- break;
2009
- }
2010
- }
2011
-
2012
- // No videos were found, so keep looping unless page is finished loading.
2013
- } else if (!_windowLoaded) {
2014
- autoSetupTimeout(1);
2015
- }
2016
- };
2017
-
2018
- /**
2019
- * Wait until the page is loaded before running autoSetup. This will be called in
2020
- * autoSetup if `hasLoaded` returns false.
2021
- *
2022
- * @param {number} wait
2023
- * How long to wait in ms
2024
- *
2025
- * @param {module:videojs} [vjs]
2026
- * The videojs library function
2027
- */
2028
- function autoSetupTimeout(wait, vjs) {
2029
- if (vjs) {
2030
- videojs = vjs;
2031
- }
2032
-
2033
- window_1.setTimeout(autoSetup, wait);
2034
- }
2035
-
2036
- if (isReal() && document_1.readyState === 'complete') {
2037
- _windowLoaded = true;
2038
- } else {
2039
- /**
2040
- * Listen for the load event on window, and set _windowLoaded to true.
2041
- *
2042
- * @listens load
2043
- */
2044
- one(window_1, 'load', function () {
2045
- _windowLoaded = true;
2046
- });
2047
- }
2048
-
2049
- /**
2050
- * @file stylesheet.js
2051
- * @module stylesheet
2052
- */
2053
-
2054
- /**
2055
- * Create a DOM syle element given a className for it.
2056
- *
2057
- * @param {string} className
2058
- * The className to add to the created style element.
2059
- *
2060
- * @return {Element}
2061
- * The element that was created.
2062
- */
2063
- var createStyleElement = function createStyleElement(className) {
2064
- var style = document_1.createElement('style');
2065
-
2066
- style.className = className;
2067
-
2068
- return style;
2069
- };
2070
-
2071
- /**
2072
- * Add text to a DOM element.
2073
- *
2074
- * @param {Element} el
2075
- * The Element to add text content to.
2076
- *
2077
- * @param {string} content
2078
- * The text to add to the element.
2079
- */
2080
- var setTextContent = function setTextContent(el, content) {
2081
- if (el.styleSheet) {
2082
- el.styleSheet.cssText = content;
2083
- } else {
2084
- el.textContent = content;
2085
- }
2086
- };
2087
-
2088
- /**
2089
- * @file fn.js
2090
- * @module fn
2091
- */
2092
-
2093
- /**
2094
- * Bind (a.k.a proxy or Context). A simple method for changing the context of a function
2095
- * It also stores a unique id on the function so it can be easily removed from events.
2096
- *
2097
- * @param {Mixed} context
2098
- * The object to bind as scope.
2099
- *
2100
- * @param {Function} fn
2101
- * The function to be bound to a scope.
2102
- *
2103
- * @param {number} [uid]
2104
- * An optional unique ID for the function to be set
2105
- *
2106
- * @return {Function}
2107
- * The new function that will be bound into the context given
2108
- */
2109
- var bind = function bind(context, fn, uid) {
2110
- // Make sure the function has a unique ID
2111
- if (!fn.guid) {
2112
- fn.guid = newGUID();
2113
- }
2114
-
2115
- // Create the new function that changes the context
2116
- var bound = function bound() {
2117
- return fn.apply(context, arguments);
2118
- };
2119
-
2120
- // Allow for the ability to individualize this function
2121
- // Needed in the case where multiple objects might share the same prototype
2122
- // IF both items add an event listener with the same function, then you try to remove just one
2123
- // it will remove both because they both have the same guid.
2124
- // when using this, you need to use the bind method when you remove the listener as well.
2125
- // currently used in text tracks
2126
- bound.guid = uid ? uid + '_' + fn.guid : fn.guid;
2127
-
2128
- return bound;
2129
- };
2130
-
2131
- /**
2132
- * Wraps the given function, `fn`, with a new function that only invokes `fn`
2133
- * at most once per every `wait` milliseconds.
2134
- *
2135
- * @param {Function} fn
2136
- * The function to be throttled.
2137
- *
2138
- * @param {Number} wait
2139
- * The number of milliseconds by which to throttle.
2140
- *
2141
- * @return {Function}
2142
- */
2143
- var throttle = function throttle(fn, wait) {
2144
- var last = Date.now();
2145
-
2146
- var throttled = function throttled() {
2147
- var now = Date.now();
2148
-
2149
- if (now - last >= wait) {
2150
- fn.apply(undefined, arguments);
2151
- last = now;
2152
- }
2153
- };
2154
-
2155
- return throttled;
2156
- };
2157
-
2158
- /**
2159
- * Creates a debounced function that delays invoking `func` until after `wait`
2160
- * milliseconds have elapsed since the last time the debounced function was
2161
- * invoked.
2162
- *
2163
- * Inspired by lodash and underscore implementations.
2164
- *
2165
- * @param {Function} func
2166
- * The function to wrap with debounce behavior.
2167
- *
2168
- * @param {number} wait
2169
- * The number of milliseconds to wait after the last invocation.
2170
- *
2171
- * @param {boolean} [immediate]
2172
- * Whether or not to invoke the function immediately upon creation.
2173
- *
2174
- * @param {Object} [context=window]
2175
- * The "context" in which the debounced function should debounce. For
2176
- * example, if this function should be tied to a Video.js player,
2177
- * the player can be passed here. Alternatively, defaults to the
2178
- * global `window` object.
2179
- *
2180
- * @return {Function}
2181
- * A debounced function.
2182
- */
2183
- var debounce = function debounce(func, wait, immediate) {
2184
- var context = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : window_1;
2185
-
2186
- var timeout = void 0;
2187
-
2188
- /* eslint-disable consistent-this */
2189
- return function () {
2190
- var self = this;
2191
- var args = arguments;
2192
-
2193
- var _later = function later() {
2194
- timeout = null;
2195
- _later = null;
2196
- if (!immediate) {
2197
- func.apply(self, args);
2198
- }
2199
- };
2200
-
2201
- if (!timeout && immediate) {
2202
- func.apply(self, args);
2203
- }
2204
-
2205
- context.clearTimeout(timeout);
2206
- timeout = context.setTimeout(_later, wait);
2207
- };
2208
- /* eslint-enable consistent-this */
2209
- };
2210
-
2211
- /**
2212
- * @file src/js/event-target.js
2213
- */
2214
-
2215
- /**
2216
- * `EventTarget` is a class that can have the same API as the DOM `EventTarget`. It
2217
- * adds shorthand functions that wrap around lengthy functions. For example:
2218
- * the `on` function is a wrapper around `addEventListener`.
2219
- *
2220
- * @see [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
2221
- * @class EventTarget
2222
- */
2223
- var EventTarget = function EventTarget() {};
2224
-
2225
- /**
2226
- * A Custom DOM event.
2227
- *
2228
- * @typedef {Object} EventTarget~Event
2229
- * @see [Properties]{@link https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
2230
- */
2231
-
2232
- /**
2233
- * All event listeners should follow the following format.
2234
- *
2235
- * @callback EventTarget~EventListener
2236
- * @this {EventTarget}
2237
- *
2238
- * @param {EventTarget~Event} event
2239
- * the event that triggered this function
2240
- *
2241
- * @param {Object} [hash]
2242
- * hash of data sent during the event
2243
- */
2244
-
2245
- /**
2246
- * An object containing event names as keys and booleans as values.
2247
- *
2248
- * > NOTE: If an event name is set to a true value here {@link EventTarget#trigger}
2249
- * will have extra functionality. See that function for more information.
2250
- *
2251
- * @property EventTarget.prototype.allowedEvents_
2252
- * @private
2253
- */
2254
- EventTarget.prototype.allowedEvents_ = {};
2255
-
2256
- /**
2257
- * Adds an `event listener` to an instance of an `EventTarget`. An `event listener` is a
2258
- * function that will get called when an event with a certain name gets triggered.
2259
- *
2260
- * @param {string|string[]} type
2261
- * An event name or an array of event names.
2262
- *
2263
- * @param {EventTarget~EventListener} fn
2264
- * The function to call with `EventTarget`s
2265
- */
2266
- EventTarget.prototype.on = function (type, fn) {
2267
- // Remove the addEventListener alias before calling Events.on
2268
- // so we don't get into an infinite type loop
2269
- var ael = this.addEventListener;
2270
-
2271
- this.addEventListener = function () {};
2272
- on(this, type, fn);
2273
- this.addEventListener = ael;
2274
- };
2275
-
2276
- /**
2277
- * An alias of {@link EventTarget#on}. Allows `EventTarget` to mimic
2278
- * the standard DOM API.
2279
- *
2280
- * @function
2281
- * @see {@link EventTarget#on}
2282
- */
2283
- EventTarget.prototype.addEventListener = EventTarget.prototype.on;
2284
-
2285
- /**
2286
- * Removes an `event listener` for a specific event from an instance of `EventTarget`.
2287
- * This makes it so that the `event listener` will no longer get called when the
2288
- * named event happens.
2289
- *
2290
- * @param {string|string[]} type
2291
- * An event name or an array of event names.
2292
- *
2293
- * @param {EventTarget~EventListener} fn
2294
- * The function to remove.
2295
- */
2296
- EventTarget.prototype.off = function (type, fn) {
2297
- off(this, type, fn);
2298
- };
2299
-
2300
- /**
2301
- * An alias of {@link EventTarget#off}. Allows `EventTarget` to mimic
2302
- * the standard DOM API.
2303
- *
2304
- * @function
2305
- * @see {@link EventTarget#off}
2306
- */
2307
- EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
2308
-
2309
- /**
2310
- * This function will add an `event listener` that gets triggered only once. After the
2311
- * first trigger it will get removed. This is like adding an `event listener`
2312
- * with {@link EventTarget#on} that calls {@link EventTarget#off} on itself.
2313
- *
2314
- * @param {string|string[]} type
2315
- * An event name or an array of event names.
2316
- *
2317
- * @param {EventTarget~EventListener} fn
2318
- * The function to be called once for each event name.
2319
- */
2320
- EventTarget.prototype.one = function (type, fn) {
2321
- // Remove the addEventListener alialing Events.on
2322
- // so we don't get into an infinite type loop
2323
- var ael = this.addEventListener;
2324
-
2325
- this.addEventListener = function () {};
2326
- one(this, type, fn);
2327
- this.addEventListener = ael;
2328
- };
2329
-
2330
- /**
2331
- * This function causes an event to happen. This will then cause any `event listeners`
2332
- * that are waiting for that event, to get called. If there are no `event listeners`
2333
- * for an event then nothing will happen.
2334
- *
2335
- * If the name of the `Event` that is being triggered is in `EventTarget.allowedEvents_`.
2336
- * Trigger will also call the `on` + `uppercaseEventName` function.
2337
- *
2338
- * Example:
2339
- * 'click' is in `EventTarget.allowedEvents_`, so, trigger will attempt to call
2340
- * `onClick` if it exists.
2341
- *
2342
- * @param {string|EventTarget~Event|Object} event
2343
- * The name of the event, an `Event`, or an object with a key of type set to
2344
- * an event name.
2345
- */
2346
- EventTarget.prototype.trigger = function (event) {
2347
- var type = event.type || event;
2348
-
2349
- if (typeof event === 'string') {
2350
- event = { type: type };
2351
- }
2352
- event = fixEvent(event);
2353
-
2354
- if (this.allowedEvents_[type] && this['on' + type]) {
2355
- this['on' + type](event);
2356
- }
2357
-
2358
- trigger(this, event);
2359
- };
2360
-
2361
- /**
2362
- * An alias of {@link EventTarget#trigger}. Allows `EventTarget` to mimic
2363
- * the standard DOM API.
2364
- *
2365
- * @function
2366
- * @see {@link EventTarget#trigger}
2367
- */
2368
- EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
2369
-
2370
- /**
2371
- * @file mixins/evented.js
2372
- * @module evented
2373
- */
2374
-
2375
- /**
2376
- * Returns whether or not an object has had the evented mixin applied.
2377
- *
2378
- * @param {Object} object
2379
- * An object to test.
2380
- *
2381
- * @return {boolean}
2382
- * Whether or not the object appears to be evented.
2383
- */
2384
- var isEvented = function isEvented(object) {
2385
- return object instanceof EventTarget || !!object.eventBusEl_ && ['on', 'one', 'off', 'trigger'].every(function (k) {
2386
- return typeof object[k] === 'function';
2387
- });
2388
- };
2389
-
2390
- /**
2391
- * Whether a value is a valid event type - non-empty string or array.
2392
- *
2393
- * @private
2394
- * @param {string|Array} type
2395
- * The type value to test.
2396
- *
2397
- * @return {boolean}
2398
- * Whether or not the type is a valid event type.
2399
- */
2400
- var isValidEventType = function isValidEventType(type) {
2401
- return (
2402
- // The regex here verifies that the `type` contains at least one non-
2403
- // whitespace character.
2404
- typeof type === 'string' && /\S/.test(type) || Array.isArray(type) && !!type.length
2405
- );
2406
- };
2407
-
2408
- /**
2409
- * Validates a value to determine if it is a valid event target. Throws if not.
2410
- *
2411
- * @private
2412
- * @throws {Error}
2413
- * If the target does not appear to be a valid event target.
2414
- *
2415
- * @param {Object} target
2416
- * The object to test.
2417
- */
2418
- var validateTarget = function validateTarget(target) {
2419
- if (!target.nodeName && !isEvented(target)) {
2420
- throw new Error('Invalid target; must be a DOM node or evented object.');
2421
- }
2422
- };
2423
-
2424
- /**
2425
- * Validates a value to determine if it is a valid event target. Throws if not.
2426
- *
2427
- * @private
2428
- * @throws {Error}
2429
- * If the type does not appear to be a valid event type.
2430
- *
2431
- * @param {string|Array} type
2432
- * The type to test.
2433
- */
2434
- var validateEventType = function validateEventType(type) {
2435
- if (!isValidEventType(type)) {
2436
- throw new Error('Invalid event type; must be a non-empty string or array.');
2437
- }
2438
- };
2439
-
2440
- /**
2441
- * Validates a value to determine if it is a valid listener. Throws if not.
2442
- *
2443
- * @private
2444
- * @throws {Error}
2445
- * If the listener is not a function.
2446
- *
2447
- * @param {Function} listener
2448
- * The listener to test.
2449
- */
2450
- var validateListener = function validateListener(listener) {
2451
- if (typeof listener !== 'function') {
2452
- throw new Error('Invalid listener; must be a function.');
2453
- }
2454
- };
2455
-
2456
- /**
2457
- * Takes an array of arguments given to `on()` or `one()`, validates them, and
2458
- * normalizes them into an object.
2459
- *
2460
- * @private
2461
- * @param {Object} self
2462
- * The evented object on which `on()` or `one()` was called. This
2463
- * object will be bound as the `this` value for the listener.
2464
- *
2465
- * @param {Array} args
2466
- * An array of arguments passed to `on()` or `one()`.
2467
- *
2468
- * @return {Object}
2469
- * An object containing useful values for `on()` or `one()` calls.
2470
- */
2471
- var normalizeListenArgs = function normalizeListenArgs(self, args) {
2472
-
2473
- // If the number of arguments is less than 3, the target is always the
2474
- // evented object itself.
2475
- var isTargetingSelf = args.length < 3 || args[0] === self || args[0] === self.eventBusEl_;
2476
- var target = void 0;
2477
- var type = void 0;
2478
- var listener = void 0;
2479
-
2480
- if (isTargetingSelf) {
2481
- target = self.eventBusEl_;
2482
-
2483
- // Deal with cases where we got 3 arguments, but we are still listening to
2484
- // the evented object itself.
2485
- if (args.length >= 3) {
2486
- args.shift();
2487
- }
2488
-
2489
- type = args[0];
2490
- listener = args[1];
2491
- } else {
2492
- target = args[0];
2493
- type = args[1];
2494
- listener = args[2];
2495
- }
2496
-
2497
- validateTarget(target);
2498
- validateEventType(type);
2499
- validateListener(listener);
2500
-
2501
- listener = bind(self, listener);
2502
-
2503
- return { isTargetingSelf: isTargetingSelf, target: target, type: type, listener: listener };
2504
- };
2505
-
2506
- /**
2507
- * Adds the listener to the event type(s) on the target, normalizing for
2508
- * the type of target.
2509
- *
2510
- * @private
2511
- * @param {Element|Object} target
2512
- * A DOM node or evented object.
2513
- *
2514
- * @param {string} method
2515
- * The event binding method to use ("on" or "one").
2516
- *
2517
- * @param {string|Array} type
2518
- * One or more event type(s).
2519
- *
2520
- * @param {Function} listener
2521
- * A listener function.
2522
- */
2523
- var listen = function listen(target, method, type, listener) {
2524
- validateTarget(target);
2525
-
2526
- if (target.nodeName) {
2527
- Events[method](target, type, listener);
2528
- } else {
2529
- target[method](type, listener);
2530
- }
2531
- };
2532
-
2533
- /**
2534
- * Contains methods that provide event capabilities to an object which is passed
2535
- * to {@link module:evented|evented}.
2536
- *
2537
- * @mixin EventedMixin
2538
- */
2539
- var EventedMixin = {
2540
-
2541
- /**
2542
- * Add a listener to an event (or events) on this object or another evented
2543
- * object.
2544
- *
2545
- * @param {string|Array|Element|Object} targetOrType
2546
- * If this is a string or array, it represents the event type(s)
2547
- * that will trigger the listener.
2548
- *
2549
- * Another evented object can be passed here instead, which will
2550
- * cause the listener to listen for events on _that_ object.
2551
- *
2552
- * In either case, the listener's `this` value will be bound to
2553
- * this object.
2554
- *
2555
- * @param {string|Array|Function} typeOrListener
2556
- * If the first argument was a string or array, this should be the
2557
- * listener function. Otherwise, this is a string or array of event
2558
- * type(s).
2559
- *
2560
- * @param {Function} [listener]
2561
- * If the first argument was another evented object, this will be
2562
- * the listener function.
2563
- */
2564
- on: function on$$1() {
2565
- var _this = this;
2566
-
2567
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
2568
- args[_key] = arguments[_key];
2569
- }
2570
-
2571
- var _normalizeListenArgs = normalizeListenArgs(this, args),
2572
- isTargetingSelf = _normalizeListenArgs.isTargetingSelf,
2573
- target = _normalizeListenArgs.target,
2574
- type = _normalizeListenArgs.type,
2575
- listener = _normalizeListenArgs.listener;
2576
-
2577
- listen(target, 'on', type, listener);
2578
-
2579
- // If this object is listening to another evented object.
2580
- if (!isTargetingSelf) {
2581
-
2582
- // If this object is disposed, remove the listener.
2583
- var removeListenerOnDispose = function removeListenerOnDispose() {
2584
- return _this.off(target, type, listener);
2585
- };
2586
-
2587
- // Use the same function ID as the listener so we can remove it later it
2588
- // using the ID of the original listener.
2589
- removeListenerOnDispose.guid = listener.guid;
2590
-
2591
- // Add a listener to the target's dispose event as well. This ensures
2592
- // that if the target is disposed BEFORE this object, we remove the
2593
- // removal listener that was just added. Otherwise, we create a memory leak.
2594
- var removeRemoverOnTargetDispose = function removeRemoverOnTargetDispose() {
2595
- return _this.off('dispose', removeListenerOnDispose);
2596
- };
2597
-
2598
- // Use the same function ID as the listener so we can remove it later
2599
- // it using the ID of the original listener.
2600
- removeRemoverOnTargetDispose.guid = listener.guid;
2601
-
2602
- listen(this, 'on', 'dispose', removeListenerOnDispose);
2603
- listen(target, 'on', 'dispose', removeRemoverOnTargetDispose);
2604
- }
2605
- },
2606
-
2607
-
2608
- /**
2609
- * Add a listener to an event (or events) on this object or another evented
2610
- * object. The listener will only be called once and then removed.
2611
- *
2612
- * @param {string|Array|Element|Object} targetOrType
2613
- * If this is a string or array, it represents the event type(s)
2614
- * that will trigger the listener.
2615
- *
2616
- * Another evented object can be passed here instead, which will
2617
- * cause the listener to listen for events on _that_ object.
2618
- *
2619
- * In either case, the listener's `this` value will be bound to
2620
- * this object.
2621
- *
2622
- * @param {string|Array|Function} typeOrListener
2623
- * If the first argument was a string or array, this should be the
2624
- * listener function. Otherwise, this is a string or array of event
2625
- * type(s).
2626
- *
2627
- * @param {Function} [listener]
2628
- * If the first argument was another evented object, this will be
2629
- * the listener function.
2630
- */
2631
- one: function one$$1() {
2632
- var _this2 = this;
2633
-
2634
- for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
2635
- args[_key2] = arguments[_key2];
2636
- }
2637
-
2638
- var _normalizeListenArgs2 = normalizeListenArgs(this, args),
2639
- isTargetingSelf = _normalizeListenArgs2.isTargetingSelf,
2640
- target = _normalizeListenArgs2.target,
2641
- type = _normalizeListenArgs2.type,
2642
- listener = _normalizeListenArgs2.listener;
2643
-
2644
- // Targeting this evented object.
2645
-
2646
-
2647
- if (isTargetingSelf) {
2648
- listen(target, 'one', type, listener);
2649
-
2650
- // Targeting another evented object.
2651
- } else {
2652
- var wrapper = function wrapper() {
2653
- for (var _len3 = arguments.length, largs = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
2654
- largs[_key3] = arguments[_key3];
2655
- }
2656
-
2657
- _this2.off(target, type, wrapper);
2658
- listener.apply(null, largs);
2659
- };
2660
-
2661
- // Use the same function ID as the listener so we can remove it later
2662
- // it using the ID of the original listener.
2663
- wrapper.guid = listener.guid;
2664
- listen(target, 'one', type, wrapper);
2665
- }
2666
- },
2667
-
2668
-
2669
- /**
2670
- * Removes listener(s) from event(s) on an evented object.
2671
- *
2672
- * @param {string|Array|Element|Object} [targetOrType]
2673
- * If this is a string or array, it represents the event type(s).
2674
- *
2675
- * Another evented object can be passed here instead, in which case
2676
- * ALL 3 arguments are _required_.
2677
- *
2678
- * @param {string|Array|Function} [typeOrListener]
2679
- * If the first argument was a string or array, this may be the
2680
- * listener function. Otherwise, this is a string or array of event
2681
- * type(s).
2682
- *
2683
- * @param {Function} [listener]
2684
- * If the first argument was another evented object, this will be
2685
- * the listener function; otherwise, _all_ listeners bound to the
2686
- * event type(s) will be removed.
2687
- */
2688
- off: function off$$1(targetOrType, typeOrListener, listener) {
2689
-
2690
- // Targeting this evented object.
2691
- if (!targetOrType || isValidEventType(targetOrType)) {
2692
- off(this.eventBusEl_, targetOrType, typeOrListener);
2693
-
2694
- // Targeting another evented object.
2695
- } else {
2696
- var target = targetOrType;
2697
- var type = typeOrListener;
2698
-
2699
- // Fail fast and in a meaningful way!
2700
- validateTarget(target);
2701
- validateEventType(type);
2702
- validateListener(listener);
2703
-
2704
- // Ensure there's at least a guid, even if the function hasn't been used
2705
- listener = bind(this, listener);
2706
-
2707
- // Remove the dispose listener on this evented object, which was given
2708
- // the same guid as the event listener in on().
2709
- this.off('dispose', listener);
2710
-
2711
- if (target.nodeName) {
2712
- off(target, type, listener);
2713
- off(target, 'dispose', listener);
2714
- } else if (isEvented(target)) {
2715
- target.off(type, listener);
2716
- target.off('dispose', listener);
2717
- }
2718
- }
2719
- },
2720
-
2721
-
2722
- /**
2723
- * Fire an event on this evented object, causing its listeners to be called.
2724
- *
2725
- * @param {string|Object} event
2726
- * An event type or an object with a type property.
2727
- *
2728
- * @param {Object} [hash]
2729
- * An additional object to pass along to listeners.
2730
- *
2731
- * @returns {boolean}
2732
- * Whether or not the default behavior was prevented.
2733
- */
2734
- trigger: function trigger$$1(event, hash) {
2735
- return trigger(this.eventBusEl_, event, hash);
2736
- }
2737
- };
2738
-
2739
- /**
2740
- * Applies {@link module:evented~EventedMixin|EventedMixin} to a target object.
2741
- *
2742
- * @param {Object} target
2743
- * The object to which to add event methods.
2744
- *
2745
- * @param {Object} [options={}]
2746
- * Options for customizing the mixin behavior.
2747
- *
2748
- * @param {String} [options.eventBusKey]
2749
- * By default, adds a `eventBusEl_` DOM element to the target object,
2750
- * which is used as an event bus. If the target object already has a
2751
- * DOM element that should be used, pass its key here.
2752
- *
2753
- * @return {Object}
2754
- * The target object.
2755
- */
2756
- function evented(target) {
2757
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2758
- var eventBusKey = options.eventBusKey;
2759
-
2760
- // Set or create the eventBusEl_.
2761
-
2762
- if (eventBusKey) {
2763
- if (!target[eventBusKey].nodeName) {
2764
- throw new Error('The eventBusKey "' + eventBusKey + '" does not refer to an element.');
2765
- }
2766
- target.eventBusEl_ = target[eventBusKey];
2767
- } else {
2768
- target.eventBusEl_ = createEl('span', { className: 'vjs-event-bus' });
2769
- }
2770
-
2771
- assign(target, EventedMixin);
2772
-
2773
- // When any evented object is disposed, it removes all its listeners.
2774
- target.on('dispose', function () {
2775
- target.off();
2776
- window_1.setTimeout(function () {
2777
- target.eventBusEl_ = null;
2778
- }, 0);
2779
- });
2780
-
2781
- return target;
2782
- }
2783
-
2784
- /**
2785
- * @file mixins/stateful.js
2786
- * @module stateful
2787
- */
2788
-
2789
- /**
2790
- * Contains methods that provide statefulness to an object which is passed
2791
- * to {@link module:stateful}.
2792
- *
2793
- * @mixin StatefulMixin
2794
- */
2795
- var StatefulMixin = {
2796
-
2797
- /**
2798
- * A hash containing arbitrary keys and values representing the state of
2799
- * the object.
2800
- *
2801
- * @type {Object}
2802
- */
2803
- state: {},
2804
-
2805
- /**
2806
- * Set the state of an object by mutating its
2807
- * {@link module:stateful~StatefulMixin.state|state} object in place.
2808
- *
2809
- * @fires module:stateful~StatefulMixin#statechanged
2810
- * @param {Object|Function} stateUpdates
2811
- * A new set of properties to shallow-merge into the plugin state.
2812
- * Can be a plain object or a function returning a plain object.
2813
- *
2814
- * @returns {Object|undefined}
2815
- * An object containing changes that occurred. If no changes
2816
- * occurred, returns `undefined`.
2817
- */
2818
- setState: function setState(stateUpdates) {
2819
- var _this = this;
2820
-
2821
- // Support providing the `stateUpdates` state as a function.
2822
- if (typeof stateUpdates === 'function') {
2823
- stateUpdates = stateUpdates();
2824
- }
2825
-
2826
- var changes = void 0;
2827
-
2828
- each(stateUpdates, function (value, key) {
2829
-
2830
- // Record the change if the value is different from what's in the
2831
- // current state.
2832
- if (_this.state[key] !== value) {
2833
- changes = changes || {};
2834
- changes[key] = {
2835
- from: _this.state[key],
2836
- to: value
2837
- };
2838
- }
2839
-
2840
- _this.state[key] = value;
2841
- });
2842
-
2843
- // Only trigger "statechange" if there were changes AND we have a trigger
2844
- // function. This allows us to not require that the target object be an
2845
- // evented object.
2846
- if (changes && isEvented(this)) {
2847
-
2848
- /**
2849
- * An event triggered on an object that is both
2850
- * {@link module:stateful|stateful} and {@link module:evented|evented}
2851
- * indicating that its state has changed.
2852
- *
2853
- * @event module:stateful~StatefulMixin#statechanged
2854
- * @type {Object}
2855
- * @property {Object} changes
2856
- * A hash containing the properties that were changed and
2857
- * the values they were changed `from` and `to`.
2858
- */
2859
- this.trigger({
2860
- changes: changes,
2861
- type: 'statechanged'
2862
- });
2863
- }
2864
-
2865
- return changes;
2866
- }
2867
- };
2868
-
2869
- /**
2870
- * Applies {@link module:stateful~StatefulMixin|StatefulMixin} to a target
2871
- * object.
2872
- *
2873
- * If the target object is {@link module:evented|evented} and has a
2874
- * `handleStateChanged` method, that method will be automatically bound to the
2875
- * `statechanged` event on itself.
2876
- *
2877
- * @param {Object} target
2878
- * The object to be made stateful.
2879
- *
2880
- * @param {Object} [defaultState]
2881
- * A default set of properties to populate the newly-stateful object's
2882
- * `state` property.
2883
- *
2884
- * @returns {Object}
2885
- * Returns the `target`.
2886
- */
2887
- function stateful(target, defaultState) {
2888
- assign(target, StatefulMixin);
2889
-
2890
- // This happens after the mixing-in because we need to replace the `state`
2891
- // added in that step.
2892
- target.state = assign({}, target.state, defaultState);
2893
-
2894
- // Auto-bind the `handleStateChanged` method of the target object if it exists.
2895
- if (typeof target.handleStateChanged === 'function' && isEvented(target)) {
2896
- target.on('statechanged', target.handleStateChanged);
2897
- }
2898
-
2899
- return target;
2900
- }
2901
-
2902
- /**
2903
- * @file to-title-case.js
2904
- * @module to-title-case
2905
- */
2906
-
2907
- /**
2908
- * Uppercase the first letter of a string.
2909
- *
2910
- * @param {string} string
2911
- * String to be uppercased
2912
- *
2913
- * @return {string}
2914
- * The string with an uppercased first letter
2915
- */
2916
- function toTitleCase(string) {
2917
- if (typeof string !== 'string') {
2918
- return string;
2919
- }
2920
-
2921
- return string.charAt(0).toUpperCase() + string.slice(1);
2922
- }
2923
-
2924
- /**
2925
- * Compares the TitleCase versions of the two strings for equality.
2926
- *
2927
- * @param {string} str1
2928
- * The first string to compare
2929
- *
2930
- * @param {string} str2
2931
- * The second string to compare
2932
- *
2933
- * @return {boolean}
2934
- * Whether the TitleCase versions of the strings are equal
2935
- */
2936
- function titleCaseEquals(str1, str2) {
2937
- return toTitleCase(str1) === toTitleCase(str2);
2938
- }
2939
-
2940
- /**
2941
- * @file merge-options.js
2942
- * @module merge-options
2943
- */
2944
-
2945
- /**
2946
- * Deep-merge one or more options objects, recursively merging **only** plain
2947
- * object properties.
2948
- *
2949
- * @param {Object[]} sources
2950
- * One or more objects to merge into a new object.
2951
- *
2952
- * @returns {Object}
2953
- * A new object that is the merged result of all sources.
2954
- */
2955
- function mergeOptions() {
2956
- var result = {};
2957
-
2958
- for (var _len = arguments.length, sources = Array(_len), _key = 0; _key < _len; _key++) {
2959
- sources[_key] = arguments[_key];
2960
- }
2961
-
2962
- sources.forEach(function (source) {
2963
- if (!source) {
2964
- return;
2965
- }
2966
-
2967
- each(source, function (value, key) {
2968
- if (!isPlain(value)) {
2969
- result[key] = value;
2970
- return;
2971
- }
2972
-
2973
- if (!isPlain(result[key])) {
2974
- result[key] = {};
2975
- }
2976
-
2977
- result[key] = mergeOptions(result[key], value);
2978
- });
2979
- });
2980
-
2981
- return result;
2982
- }
2983
-
2984
- /**
2985
- * Player Component - Base class for all UI objects
2986
- *
2987
- * @file component.js
2988
- */
2989
-
2990
- /**
2991
- * Base class for all UI Components.
2992
- * Components are UI objects which represent both a javascript object and an element
2993
- * in the DOM. They can be children of other components, and can have
2994
- * children themselves.
2995
- *
2996
- * Components can also use methods from {@link EventTarget}
2997
- */
2998
-
2999
- var Component = function () {
3000
-
3001
- /**
3002
- * A callback that is called when a component is ready. Does not have any
3003
- * paramters and any callback value will be ignored.
3004
- *
3005
- * @callback Component~ReadyCallback
3006
- * @this Component
3007
- */
3008
-
3009
- /**
3010
- * Creates an instance of this class.
3011
- *
3012
- * @param {Player} player
3013
- * The `Player` that this class should be attached to.
3014
- *
3015
- * @param {Object} [options]
3016
- * The key/value store of player options.
3017
- *
3018
- * @param {Object[]} [options.children]
3019
- * An array of children objects to intialize this component with. Children objects have
3020
- * a name property that will be used if more than one component of the same type needs to be
3021
- * added.
3022
- *
3023
- * @param {Component~ReadyCallback} [ready]
3024
- * Function that gets called when the `Component` is ready.
3025
- */
3026
- function Component(player, options, ready) {
3027
- classCallCheck(this, Component);
3028
-
3029
-
3030
- // The component might be the player itself and we can't pass `this` to super
3031
- if (!player && this.play) {
3032
- this.player_ = player = this; // eslint-disable-line
3033
- } else {
3034
- this.player_ = player;
3035
- }
3036
-
3037
- // Make a copy of prototype.options_ to protect against overriding defaults
3038
- this.options_ = mergeOptions({}, this.options_);
3039
-
3040
- // Updated options with supplied options
3041
- options = this.options_ = mergeOptions(this.options_, options);
3042
-
3043
- // Get ID from options or options element if one is supplied
3044
- this.id_ = options.id || options.el && options.el.id;
3045
-
3046
- // If there was no ID from the options, generate one
3047
- if (!this.id_) {
3048
- // Don't require the player ID function in the case of mock players
3049
- var id = player && player.id && player.id() || 'no_player';
3050
-
3051
- this.id_ = id + '_component_' + newGUID();
3052
- }
3053
-
3054
- this.name_ = options.name || null;
3055
-
3056
- // Create element if one wasn't provided in options
3057
- if (options.el) {
3058
- this.el_ = options.el;
3059
- } else if (options.createEl !== false) {
3060
- this.el_ = this.createEl();
3061
- }
3062
-
3063
- // if evented is anything except false, we want to mixin in evented
3064
- if (options.evented !== false) {
3065
- // Make this an evented object and use `el_`, if available, as its event bus
3066
- evented(this, { eventBusKey: this.el_ ? 'el_' : null });
3067
- }
3068
- stateful(this, this.constructor.defaultState);
3069
-
3070
- this.children_ = [];
3071
- this.childIndex_ = {};
3072
- this.childNameIndex_ = {};
3073
-
3074
- // Add any child components in options
3075
- if (options.initChildren !== false) {
3076
- this.initChildren();
3077
- }
3078
-
3079
- this.ready(ready);
3080
- // Don't want to trigger ready here or it will before init is actually
3081
- // finished for all children that run this constructor
3082
-
3083
- if (options.reportTouchActivity !== false) {
3084
- this.enableTouchActivity();
3085
- }
3086
- }
3087
-
3088
- /**
3089
- * Dispose of the `Component` and all child components.
3090
- *
3091
- * @fires Component#dispose
3092
- */
3093
-
3094
-
3095
- Component.prototype.dispose = function dispose() {
3096
-
3097
- /**
3098
- * Triggered when a `Component` is disposed.
3099
- *
3100
- * @event Component#dispose
3101
- * @type {EventTarget~Event}
3102
- *
3103
- * @property {boolean} [bubbles=false]
3104
- * set to false so that the close event does not
3105
- * bubble up
3106
- */
3107
- this.trigger({ type: 'dispose', bubbles: false });
3108
-
3109
- // Dispose all children.
3110
- if (this.children_) {
3111
- for (var i = this.children_.length - 1; i >= 0; i--) {
3112
- if (this.children_[i].dispose) {
3113
- this.children_[i].dispose();
3114
- }
3115
- }
3116
- }
3117
-
3118
- // Delete child references
3119
- this.children_ = null;
3120
- this.childIndex_ = null;
3121
- this.childNameIndex_ = null;
3122
-
3123
- if (this.el_) {
3124
- // Remove element from DOM
3125
- if (this.el_.parentNode) {
3126
- this.el_.parentNode.removeChild(this.el_);
3127
- }
3128
-
3129
- removeData(this.el_);
3130
- this.el_ = null;
3131
- }
3132
-
3133
- // remove reference to the player after disposing of the element
3134
- this.player_ = null;
3135
- };
3136
-
3137
- /**
3138
- * Return the {@link Player} that the `Component` has attached to.
3139
- *
3140
- * @return {Player}
3141
- * The player that this `Component` has attached to.
3142
- */
3143
-
3144
-
3145
- Component.prototype.player = function player() {
3146
- return this.player_;
3147
- };
3148
-
3149
- /**
3150
- * Deep merge of options objects with new options.
3151
- * > Note: When both `obj` and `options` contain properties whose values are objects.
3152
- * The two properties get merged using {@link module:mergeOptions}
3153
- *
3154
- * @param {Object} obj
3155
- * The object that contains new options.
3156
- *
3157
- * @return {Object}
3158
- * A new object of `this.options_` and `obj` merged together.
3159
- *
3160
- * @deprecated since version 5
3161
- */
3162
-
3163
-
3164
- Component.prototype.options = function options(obj) {
3165
- log$1.warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
3166
-
3167
- if (!obj) {
3168
- return this.options_;
3169
- }
3170
-
3171
- this.options_ = mergeOptions(this.options_, obj);
3172
- return this.options_;
3173
- };
3174
-
3175
- /**
3176
- * Get the `Component`s DOM element
3177
- *
3178
- * @return {Element}
3179
- * The DOM element for this `Component`.
3180
- */
3181
-
3182
-
3183
- Component.prototype.el = function el() {
3184
- return this.el_;
3185
- };
3186
-
3187
- /**
3188
- * Create the `Component`s DOM element.
3189
- *
3190
- * @param {string} [tagName]
3191
- * Element's DOM node type. e.g. 'div'
3192
- *
3193
- * @param {Object} [properties]
3194
- * An object of properties that should be set.
3195
- *
3196
- * @param {Object} [attributes]
3197
- * An object of attributes that should be set.
3198
- *
3199
- * @return {Element}
3200
- * The element that gets created.
3201
- */
3202
-
3203
-
3204
- Component.prototype.createEl = function createEl$$1(tagName, properties, attributes) {
3205
- return createEl(tagName, properties, attributes);
3206
- };
3207
-
3208
- /**
3209
- * Localize a string given the string in english.
3210
- *
3211
- * If tokens are provided, it'll try and run a simple token replacement on the provided string.
3212
- * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array.
3213
- *
3214
- * If a `defaultValue` is provided, it'll use that over `string`,
3215
- * if a value isn't found in provided language files.
3216
- * This is useful if you want to have a descriptive key for token replacement
3217
- * but have a succinct localized string and not require `en.json` to be included.
3218
- *
3219
- * Currently, it is used for the progress bar timing.
3220
- * ```js
3221
- * {
3222
- * "progress bar timing: currentTime={1} duration={2}": "{1} of {2}"
3223
- * }
3224
- * ```
3225
- * It is then used like so:
3226
- * ```js
3227
- * this.localize('progress bar timing: currentTime={1} duration{2}',
3228
- * [this.player_.currentTime(), this.player_.duration()],
3229
- * '{1} of {2}');
3230
- * ```
3231
- *
3232
- * Which outputs something like: `01:23 of 24:56`.
3233
- *
3234
- *
3235
- * @param {string} string
3236
- * The string to localize and the key to lookup in the language files.
3237
- * @param {string[]} [tokens]
3238
- * If the current item has token replacements, provide the tokens here.
3239
- * @param {string} [defaultValue]
3240
- * Defaults to `string`. Can be a default value to use for token replacement
3241
- * if the lookup key is needed to be separate.
3242
- *
3243
- * @return {string}
3244
- * The localized string or if no localization exists the english string.
3245
- */
3246
-
3247
-
3248
- Component.prototype.localize = function localize(string, tokens) {
3249
- var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : string;
3250
-
3251
- var code = this.player_.language && this.player_.language();
3252
- var languages = this.player_.languages && this.player_.languages();
3253
- var language = languages && languages[code];
3254
- var primaryCode = code && code.split('-')[0];
3255
- var primaryLang = languages && languages[primaryCode];
3256
-
3257
- var localizedString = defaultValue;
3258
-
3259
- if (language && language[string]) {
3260
- localizedString = language[string];
3261
- } else if (primaryLang && primaryLang[string]) {
3262
- localizedString = primaryLang[string];
3263
- }
3264
-
3265
- if (tokens) {
3266
- localizedString = localizedString.replace(/\{(\d+)\}/g, function (match, index) {
3267
- var value = tokens[index - 1];
3268
- var ret = value;
3269
-
3270
- if (typeof value === 'undefined') {
3271
- ret = match;
3272
- }
3273
-
3274
- return ret;
3275
- });
3276
- }
3277
-
3278
- return localizedString;
3279
- };
3280
-
3281
- /**
3282
- * Return the `Component`s DOM element. This is where children get inserted.
3283
- * This will usually be the the same as the element returned in {@link Component#el}.
3284
- *
3285
- * @return {Element}
3286
- * The content element for this `Component`.
3287
- */
3288
-
3289
-
3290
- Component.prototype.contentEl = function contentEl() {
3291
- return this.contentEl_ || this.el_;
3292
- };
3293
-
3294
- /**
3295
- * Get this `Component`s ID
3296
- *
3297
- * @return {string}
3298
- * The id of this `Component`
3299
- */
3300
-
3301
-
3302
- Component.prototype.id = function id() {
3303
- return this.id_;
3304
- };
3305
-
3306
- /**
3307
- * Get the `Component`s name. The name gets used to reference the `Component`
3308
- * and is set during registration.
3309
- *
3310
- * @return {string}
3311
- * The name of this `Component`.
3312
- */
3313
-
3314
-
3315
- Component.prototype.name = function name() {
3316
- return this.name_;
3317
- };
3318
-
3319
- /**
3320
- * Get an array of all child components
3321
- *
3322
- * @return {Array}
3323
- * The children
3324
- */
3325
-
3326
-
3327
- Component.prototype.children = function children() {
3328
- return this.children_;
3329
- };
3330
-
3331
- /**
3332
- * Returns the child `Component` with the given `id`.
3333
- *
3334
- * @param {string} id
3335
- * The id of the child `Component` to get.
3336
- *
3337
- * @return {Component|undefined}
3338
- * The child `Component` with the given `id` or undefined.
3339
- */
3340
-
3341
-
3342
- Component.prototype.getChildById = function getChildById(id) {
3343
- return this.childIndex_[id];
3344
- };
3345
-
3346
- /**
3347
- * Returns the child `Component` with the given `name`.
3348
- *
3349
- * @param {string} name
3350
- * The name of the child `Component` to get.
3351
- *
3352
- * @return {Component|undefined}
3353
- * The child `Component` with the given `name` or undefined.
3354
- */
3355
-
3356
-
3357
- Component.prototype.getChild = function getChild(name) {
3358
- if (!name) {
3359
- return;
3360
- }
3361
-
3362
- name = toTitleCase(name);
3363
-
3364
- return this.childNameIndex_[name];
3365
- };
3366
-
3367
- /**
3368
- * Add a child `Component` inside the current `Component`.
3369
- *
3370
- *
3371
- * @param {string|Component} child
3372
- * The name or instance of a child to add.
3373
- *
3374
- * @param {Object} [options={}]
3375
- * The key/value store of options that will get passed to children of
3376
- * the child.
3377
- *
3378
- * @param {number} [index=this.children_.length]
3379
- * The index to attempt to add a child into.
3380
- *
3381
- * @return {Component}
3382
- * The `Component` that gets added as a child. When using a string the
3383
- * `Component` will get created by this process.
3384
- */
3385
-
3386
-
3387
- Component.prototype.addChild = function addChild(child) {
3388
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3389
- var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length;
3390
-
3391
- var component = void 0;
3392
- var componentName = void 0;
3393
-
3394
- // If child is a string, create component with options
3395
- if (typeof child === 'string') {
3396
- componentName = toTitleCase(child);
3397
-
3398
- var componentClassName = options.componentClass || componentName;
3399
-
3400
- // Set name through options
3401
- options.name = componentName;
3402
-
3403
- // Create a new object & element for this controls set
3404
- // If there's no .player_, this is a player
3405
- var ComponentClass = Component.getComponent(componentClassName);
3406
-
3407
- if (!ComponentClass) {
3408
- throw new Error('Component ' + componentClassName + ' does not exist');
3409
- }
3410
-
3411
- // data stored directly on the videojs object may be
3412
- // misidentified as a component to retain
3413
- // backwards-compatibility with 4.x. check to make sure the
3414
- // component class can be instantiated.
3415
- if (typeof ComponentClass !== 'function') {
3416
- return null;
3417
- }
3418
-
3419
- component = new ComponentClass(this.player_ || this, options);
3420
-
3421
- // child is a component instance
3422
- } else {
3423
- component = child;
3424
- }
3425
-
3426
- this.children_.splice(index, 0, component);
3427
-
3428
- if (typeof component.id === 'function') {
3429
- this.childIndex_[component.id()] = component;
3430
- }
3431
-
3432
- // If a name wasn't used to create the component, check if we can use the
3433
- // name function of the component
3434
- componentName = componentName || component.name && toTitleCase(component.name());
3435
-
3436
- if (componentName) {
3437
- this.childNameIndex_[componentName] = component;
3438
- }
3439
-
3440
- // Add the UI object's element to the container div (box)
3441
- // Having an element is not required
3442
- if (typeof component.el === 'function' && component.el()) {
3443
- var childNodes = this.contentEl().children;
3444
- var refNode = childNodes[index] || null;
3445
-
3446
- this.contentEl().insertBefore(component.el(), refNode);
3447
- }
3448
-
3449
- // Return so it can stored on parent object if desired.
3450
- return component;
3451
- };
3452
-
3453
- /**
3454
- * Remove a child `Component` from this `Component`s list of children. Also removes
3455
- * the child `Component`s element from this `Component`s element.
3456
- *
3457
- * @param {Component} component
3458
- * The child `Component` to remove.
3459
- */
3460
-
3461
-
3462
- Component.prototype.removeChild = function removeChild(component) {
3463
- if (typeof component === 'string') {
3464
- component = this.getChild(component);
3465
- }
3466
-
3467
- if (!component || !this.children_) {
3468
- return;
3469
- }
3470
-
3471
- var childFound = false;
3472
-
3473
- for (var i = this.children_.length - 1; i >= 0; i--) {
3474
- if (this.children_[i] === component) {
3475
- childFound = true;
3476
- this.children_.splice(i, 1);
3477
- break;
3478
- }
3479
- }
3480
-
3481
- if (!childFound) {
3482
- return;
3483
- }
3484
-
3485
- this.childIndex_[component.id()] = null;
3486
- this.childNameIndex_[component.name()] = null;
3487
-
3488
- var compEl = component.el();
3489
-
3490
- if (compEl && compEl.parentNode === this.contentEl()) {
3491
- this.contentEl().removeChild(component.el());
3492
- }
3493
- };
3494
-
3495
- /**
3496
- * Add and initialize default child `Component`s based upon options.
3497
- */
3498
-
3499
-
3500
- Component.prototype.initChildren = function initChildren() {
3501
- var _this = this;
3502
-
3503
- var children = this.options_.children;
3504
-
3505
- if (children) {
3506
- // `this` is `parent`
3507
- var parentOptions = this.options_;
3508
-
3509
- var handleAdd = function handleAdd(child) {
3510
- var name = child.name;
3511
- var opts = child.opts;
3512
-
3513
- // Allow options for children to be set at the parent options
3514
- // e.g. videojs(id, { controlBar: false });
3515
- // instead of videojs(id, { children: { controlBar: false });
3516
- if (parentOptions[name] !== undefined) {
3517
- opts = parentOptions[name];
3518
- }
3519
-
3520
- // Allow for disabling default components
3521
- // e.g. options['children']['posterImage'] = false
3522
- if (opts === false) {
3523
- return;
3524
- }
3525
-
3526
- // Allow options to be passed as a simple boolean if no configuration
3527
- // is necessary.
3528
- if (opts === true) {
3529
- opts = {};
3530
- }
3531
-
3532
- // We also want to pass the original player options
3533
- // to each component as well so they don't need to
3534
- // reach back into the player for options later.
3535
- opts.playerOptions = _this.options_.playerOptions;
3536
-
3537
- // Create and add the child component.
3538
- // Add a direct reference to the child by name on the parent instance.
3539
- // If two of the same component are used, different names should be supplied
3540
- // for each
3541
- var newChild = _this.addChild(name, opts);
3542
-
3543
- if (newChild) {
3544
- _this[name] = newChild;
3545
- }
3546
- };
3547
-
3548
- // Allow for an array of children details to passed in the options
3549
- var workingChildren = void 0;
3550
- var Tech = Component.getComponent('Tech');
3551
-
3552
- if (Array.isArray(children)) {
3553
- workingChildren = children;
3554
- } else {
3555
- workingChildren = Object.keys(children);
3556
- }
3557
-
3558
- workingChildren
3559
- // children that are in this.options_ but also in workingChildren would
3560
- // give us extra children we do not want. So, we want to filter them out.
3561
- .concat(Object.keys(this.options_).filter(function (child) {
3562
- return !workingChildren.some(function (wchild) {
3563
- if (typeof wchild === 'string') {
3564
- return child === wchild;
3565
- }
3566
- return child === wchild.name;
3567
- });
3568
- })).map(function (child) {
3569
- var name = void 0;
3570
- var opts = void 0;
3571
-
3572
- if (typeof child === 'string') {
3573
- name = child;
3574
- opts = children[name] || _this.options_[name] || {};
3575
- } else {
3576
- name = child.name;
3577
- opts = child;
3578
- }
3579
-
3580
- return { name: name, opts: opts };
3581
- }).filter(function (child) {
3582
- // we have to make sure that child.name isn't in the techOrder since
3583
- // techs are registerd as Components but can't aren't compatible
3584
- // See https://github.com/videojs/video.js/issues/2772
3585
- var c = Component.getComponent(child.opts.componentClass || toTitleCase(child.name));
3586
-
3587
- return c && !Tech.isTech(c);
3588
- }).forEach(handleAdd);
3589
- }
3590
- };
3591
-
3592
- /**
3593
- * Builds the default DOM class name. Should be overriden by sub-components.
3594
- *
3595
- * @return {string}
3596
- * The DOM class name for this object.
3597
- *
3598
- * @abstract
3599
- */
3600
-
3601
-
3602
- Component.prototype.buildCSSClass = function buildCSSClass() {
3603
- // Child classes can include a function that does:
3604
- // return 'CLASS NAME' + this._super();
3605
- return '';
3606
- };
3607
-
3608
- /**
3609
- * Bind a listener to the component's ready state.
3610
- * Different from event listeners in that if the ready event has already happened
3611
- * it will trigger the function immediately.
3612
- *
3613
- * @return {Component}
3614
- * Returns itself; method can be chained.
3615
- */
3616
-
3617
-
3618
- Component.prototype.ready = function ready(fn) {
3619
- var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3620
-
3621
- if (!fn) {
3622
- return;
3623
- }
3624
-
3625
- if (!this.isReady_) {
3626
- this.readyQueue_ = this.readyQueue_ || [];
3627
- this.readyQueue_.push(fn);
3628
- return;
3629
- }
3630
-
3631
- if (sync) {
3632
- fn.call(this);
3633
- } else {
3634
- // Call the function asynchronously by default for consistency
3635
- this.setTimeout(fn, 1);
3636
- }
3637
- };
3638
-
3639
- /**
3640
- * Trigger all the ready listeners for this `Component`.
3641
- *
3642
- * @fires Component#ready
3643
- */
3644
-
3645
-
3646
- Component.prototype.triggerReady = function triggerReady() {
3647
- this.isReady_ = true;
3648
-
3649
- // Ensure ready is triggered asynchronously
3650
- this.setTimeout(function () {
3651
- var readyQueue = this.readyQueue_;
3652
-
3653
- // Reset Ready Queue
3654
- this.readyQueue_ = [];
3655
-
3656
- if (readyQueue && readyQueue.length > 0) {
3657
- readyQueue.forEach(function (fn) {
3658
- fn.call(this);
3659
- }, this);
3660
- }
3661
-
3662
- // Allow for using event listeners also
3663
- /**
3664
- * Triggered when a `Component` is ready.
3665
- *
3666
- * @event Component#ready
3667
- * @type {EventTarget~Event}
3668
- */
3669
- this.trigger('ready');
3670
- }, 1);
3671
- };
3672
-
3673
- /**
3674
- * Find a single DOM element matching a `selector`. This can be within the `Component`s
3675
- * `contentEl()` or another custom context.
3676
- *
3677
- * @param {string} selector
3678
- * A valid CSS selector, which will be passed to `querySelector`.
3679
- *
3680
- * @param {Element|string} [context=this.contentEl()]
3681
- * A DOM element within which to query. Can also be a selector string in
3682
- * which case the first matching element will get used as context. If
3683
- * missing `this.contentEl()` gets used. If `this.contentEl()` returns
3684
- * nothing it falls back to `document`.
3685
- *
3686
- * @return {Element|null}
3687
- * the dom element that was found, or null
3688
- *
3689
- * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
3690
- */
3691
-
3692
-
3693
- Component.prototype.$ = function $$$1(selector, context) {
3694
- return $(selector, context || this.contentEl());
3695
- };
3696
-
3697
- /**
3698
- * Finds all DOM element matching a `selector`. This can be within the `Component`s
3699
- * `contentEl()` or another custom context.
3700
- *
3701
- * @param {string} selector
3702
- * A valid CSS selector, which will be passed to `querySelectorAll`.
3703
- *
3704
- * @param {Element|string} [context=this.contentEl()]
3705
- * A DOM element within which to query. Can also be a selector string in
3706
- * which case the first matching element will get used as context. If
3707
- * missing `this.contentEl()` gets used. If `this.contentEl()` returns
3708
- * nothing it falls back to `document`.
3709
- *
3710
- * @return {NodeList}
3711
- * a list of dom elements that were found
3712
- *
3713
- * @see [Information on CSS Selectors](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
3714
- */
3715
-
3716
-
3717
- Component.prototype.$$ = function $$$$1(selector, context) {
3718
- return $$(selector, context || this.contentEl());
3719
- };
3720
-
3721
- /**
3722
- * Check if a component's element has a CSS class name.
3723
- *
3724
- * @param {string} classToCheck
3725
- * CSS class name to check.
3726
- *
3727
- * @return {boolean}
3728
- * - True if the `Component` has the class.
3729
- * - False if the `Component` does not have the class`
3730
- */
3731
-
3732
-
3733
- Component.prototype.hasClass = function hasClass$$1(classToCheck) {
3734
- return hasClass(this.el_, classToCheck);
3735
- };
3736
-
3737
- /**
3738
- * Add a CSS class name to the `Component`s element.
3739
- *
3740
- * @param {string} classToAdd
3741
- * CSS class name to add
3742
- */
3743
-
3744
-
3745
- Component.prototype.addClass = function addClass$$1(classToAdd) {
3746
- addClass(this.el_, classToAdd);
3747
- };
3748
-
3749
- /**
3750
- * Remove a CSS class name from the `Component`s element.
3751
- *
3752
- * @param {string} classToRemove
3753
- * CSS class name to remove
3754
- */
3755
-
3756
-
3757
- Component.prototype.removeClass = function removeClass$$1(classToRemove) {
3758
- removeClass(this.el_, classToRemove);
3759
- };
3760
-
3761
- /**
3762
- * Add or remove a CSS class name from the component's element.
3763
- * - `classToToggle` gets added when {@link Component#hasClass} would return false.
3764
- * - `classToToggle` gets removed when {@link Component#hasClass} would return true.
3765
- *
3766
- * @param {string} classToToggle
3767
- * The class to add or remove based on (@link Component#hasClass}
3768
- *
3769
- * @param {boolean|Dom~predicate} [predicate]
3770
- * An {@link Dom~predicate} function or a boolean
3771
- */
3772
-
3773
-
3774
- Component.prototype.toggleClass = function toggleClass$$1(classToToggle, predicate) {
3775
- toggleClass(this.el_, classToToggle, predicate);
3776
- };
3777
-
3778
- /**
3779
- * Show the `Component`s element if it is hidden by removing the
3780
- * 'vjs-hidden' class name from it.
3781
- */
3782
-
3783
-
3784
- Component.prototype.show = function show() {
3785
- this.removeClass('vjs-hidden');
3786
- };
3787
-
3788
- /**
3789
- * Hide the `Component`s element if it is currently showing by adding the
3790
- * 'vjs-hidden` class name to it.
3791
- */
3792
-
3793
-
3794
- Component.prototype.hide = function hide() {
3795
- this.addClass('vjs-hidden');
3796
- };
3797
-
3798
- /**
3799
- * Lock a `Component`s element in its visible state by adding the 'vjs-lock-showing'
3800
- * class name to it. Used during fadeIn/fadeOut.
3801
- *
3802
- * @private
3803
- */
3804
-
3805
-
3806
- Component.prototype.lockShowing = function lockShowing() {
3807
- this.addClass('vjs-lock-showing');
3808
- };
3809
-
3810
- /**
3811
- * Unlock a `Component`s element from its visible state by removing the 'vjs-lock-showing'
3812
- * class name from it. Used during fadeIn/fadeOut.
3813
- *
3814
- * @private
3815
- */
3816
-
3817
-
3818
- Component.prototype.unlockShowing = function unlockShowing() {
3819
- this.removeClass('vjs-lock-showing');
3820
- };
3821
-
3822
- /**
3823
- * Get the value of an attribute on the `Component`s element.
3824
- *
3825
- * @param {string} attribute
3826
- * Name of the attribute to get the value from.
3827
- *
3828
- * @return {string|null}
3829
- * - The value of the attribute that was asked for.
3830
- * - Can be an empty string on some browsers if the attribute does not exist
3831
- * or has no value
3832
- * - Most browsers will return null if the attibute does not exist or has
3833
- * no value.
3834
- *
3835
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
3836
- */
3837
-
3838
-
3839
- Component.prototype.getAttribute = function getAttribute$$1(attribute) {
3840
- return getAttribute(this.el_, attribute);
3841
- };
3842
-
3843
- /**
3844
- * Set the value of an attribute on the `Component`'s element
3845
- *
3846
- * @param {string} attribute
3847
- * Name of the attribute to set.
3848
- *
3849
- * @param {string} value
3850
- * Value to set the attribute to.
3851
- *
3852
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
3853
- */
3854
-
3855
-
3856
- Component.prototype.setAttribute = function setAttribute$$1(attribute, value) {
3857
- setAttribute(this.el_, attribute, value);
3858
- };
3859
-
3860
- /**
3861
- * Remove an attribute from the `Component`s element.
3862
- *
3863
- * @param {string} attribute
3864
- * Name of the attribute to remove.
3865
- *
3866
- * @see [DOM API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
3867
- */
3868
-
3869
-
3870
- Component.prototype.removeAttribute = function removeAttribute$$1(attribute) {
3871
- removeAttribute(this.el_, attribute);
3872
- };
3873
-
3874
- /**
3875
- * Get or set the width of the component based upon the CSS styles.
3876
- * See {@link Component#dimension} for more detailed information.
3877
- *
3878
- * @param {number|string} [num]
3879
- * The width that you want to set postfixed with '%', 'px' or nothing.
3880
- *
3881
- * @param {boolean} [skipListeners]
3882
- * Skip the componentresize event trigger
3883
- *
3884
- * @return {number|string}
3885
- * The width when getting, zero if there is no width. Can be a string
3886
- * postpixed with '%' or 'px'.
3887
- */
3888
-
3889
-
3890
- Component.prototype.width = function width(num, skipListeners) {
3891
- return this.dimension('width', num, skipListeners);
3892
- };
3893
-
3894
- /**
3895
- * Get or set the height of the component based upon the CSS styles.
3896
- * See {@link Component#dimension} for more detailed information.
3897
- *
3898
- * @param {number|string} [num]
3899
- * The height that you want to set postfixed with '%', 'px' or nothing.
3900
- *
3901
- * @param {boolean} [skipListeners]
3902
- * Skip the componentresize event trigger
3903
- *
3904
- * @return {number|string}
3905
- * The width when getting, zero if there is no width. Can be a string
3906
- * postpixed with '%' or 'px'.
3907
- */
3908
-
3909
-
3910
- Component.prototype.height = function height(num, skipListeners) {
3911
- return this.dimension('height', num, skipListeners);
3912
- };
3913
-
3914
- /**
3915
- * Set both the width and height of the `Component` element at the same time.
3916
- *
3917
- * @param {number|string} width
3918
- * Width to set the `Component`s element to.
3919
- *
3920
- * @param {number|string} height
3921
- * Height to set the `Component`s element to.
3922
- */
3923
-
3924
-
3925
- Component.prototype.dimensions = function dimensions(width, height) {
3926
- // Skip componentresize listeners on width for optimization
3927
- this.width(width, true);
3928
- this.height(height);
3929
- };
3930
-
3931
- /**
3932
- * Get or set width or height of the `Component` element. This is the shared code
3933
- * for the {@link Component#width} and {@link Component#height}.
3934
- *
3935
- * Things to know:
3936
- * - If the width or height in an number this will return the number postfixed with 'px'.
3937
- * - If the width/height is a percent this will return the percent postfixed with '%'
3938
- * - Hidden elements have a width of 0 with `window.getComputedStyle`. This function
3939
- * defaults to the `Component`s `style.width` and falls back to `window.getComputedStyle`.
3940
- * See [this]{@link http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}
3941
- * for more information
3942
- * - If you want the computed style of the component, use {@link Component#currentWidth}
3943
- * and {@link {Component#currentHeight}
3944
- *
3945
- * @fires Component#componentresize
3946
- *
3947
- * @param {string} widthOrHeight
3948
- 8 'width' or 'height'
3949
- *
3950
- * @param {number|string} [num]
3951
- 8 New dimension
3952
- *
3953
- * @param {boolean} [skipListeners]
3954
- * Skip componentresize event trigger
3955
- *
3956
- * @return {number}
3957
- * The dimension when getting or 0 if unset
3958
- */
3959
-
3960
-
3961
- Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
3962
- if (num !== undefined) {
3963
- // Set to zero if null or literally NaN (NaN !== NaN)
3964
- if (num === null || num !== num) {
3965
- num = 0;
3966
- }
3967
-
3968
- // Check if using css width/height (% or px) and adjust
3969
- if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
3970
- this.el_.style[widthOrHeight] = num;
3971
- } else if (num === 'auto') {
3972
- this.el_.style[widthOrHeight] = '';
3973
- } else {
3974
- this.el_.style[widthOrHeight] = num + 'px';
3975
- }
3976
-
3977
- // skipListeners allows us to avoid triggering the resize event when setting both width and height
3978
- if (!skipListeners) {
3979
- /**
3980
- * Triggered when a component is resized.
3981
- *
3982
- * @event Component#componentresize
3983
- * @type {EventTarget~Event}
3984
- */
3985
- this.trigger('componentresize');
3986
- }
3987
-
3988
- return;
3989
- }
3990
-
3991
- // Not setting a value, so getting it
3992
- // Make sure element exists
3993
- if (!this.el_) {
3994
- return 0;
3995
- }
3996
-
3997
- // Get dimension value from style
3998
- var val = this.el_.style[widthOrHeight];
3999
- var pxIndex = val.indexOf('px');
4000
-
4001
- if (pxIndex !== -1) {
4002
- // Return the pixel value with no 'px'
4003
- return parseInt(val.slice(0, pxIndex), 10);
4004
- }
4005
-
4006
- // No px so using % or no style was set, so falling back to offsetWidth/height
4007
- // If component has display:none, offset will return 0
4008
- // TODO: handle display:none and no dimension style using px
4009
- return parseInt(this.el_['offset' + toTitleCase(widthOrHeight)], 10);
4010
- };
4011
-
4012
- /**
4013
- * Get the width or the height of the `Component` elements computed style. Uses
4014
- * `window.getComputedStyle`.
4015
- *
4016
- * @param {string} widthOrHeight
4017
- * A string containing 'width' or 'height'. Whichever one you want to get.
4018
- *
4019
- * @return {number}
4020
- * The dimension that gets asked for or 0 if nothing was set
4021
- * for that dimension.
4022
- */
4023
-
4024
-
4025
- Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
4026
- var computedWidthOrHeight = 0;
4027
-
4028
- if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
4029
- throw new Error('currentDimension only accepts width or height value');
4030
- }
4031
-
4032
- if (typeof window_1.getComputedStyle === 'function') {
4033
- var computedStyle = window_1.getComputedStyle(this.el_);
4034
-
4035
- computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
4036
- }
4037
-
4038
- // remove 'px' from variable and parse as integer
4039
- computedWidthOrHeight = parseFloat(computedWidthOrHeight);
4040
-
4041
- // if the computed value is still 0, it's possible that the browser is lying
4042
- // and we want to check the offset values.
4043
- // This code also runs wherever getComputedStyle doesn't exist.
4044
- if (computedWidthOrHeight === 0) {
4045
- var rule = 'offset' + toTitleCase(widthOrHeight);
4046
-
4047
- computedWidthOrHeight = this.el_[rule];
4048
- }
4049
-
4050
- return computedWidthOrHeight;
4051
- };
4052
-
4053
- /**
4054
- * An object that contains width and height values of the `Component`s
4055
- * computed style. Uses `window.getComputedStyle`.
4056
- *
4057
- * @typedef {Object} Component~DimensionObject
4058
- *
4059
- * @property {number} width
4060
- * The width of the `Component`s computed style.
4061
- *
4062
- * @property {number} height
4063
- * The height of the `Component`s computed style.
4064
- */
4065
-
4066
- /**
4067
- * Get an object that contains width and height values of the `Component`s
4068
- * computed style.
4069
- *
4070
- * @return {Component~DimensionObject}
4071
- * The dimensions of the components element
4072
- */
4073
-
4074
-
4075
- Component.prototype.currentDimensions = function currentDimensions() {
4076
- return {
4077
- width: this.currentDimension('width'),
4078
- height: this.currentDimension('height')
4079
- };
4080
- };
4081
-
4082
- /**
4083
- * Get the width of the `Component`s computed style. Uses `window.getComputedStyle`.
4084
- *
4085
- * @return {number} width
4086
- * The width of the `Component`s computed style.
4087
- */
4088
-
4089
-
4090
- Component.prototype.currentWidth = function currentWidth() {
4091
- return this.currentDimension('width');
4092
- };
4093
-
4094
- /**
4095
- * Get the height of the `Component`s computed style. Uses `window.getComputedStyle`.
4096
- *
4097
- * @return {number} height
4098
- * The height of the `Component`s computed style.
4099
- */
4100
-
4101
-
4102
- Component.prototype.currentHeight = function currentHeight() {
4103
- return this.currentDimension('height');
4104
- };
4105
-
4106
- /**
4107
- * Set the focus to this component
4108
- */
4109
-
4110
-
4111
- Component.prototype.focus = function focus() {
4112
- this.el_.focus();
4113
- };
4114
-
4115
- /**
4116
- * Remove the focus from this component
4117
- */
4118
-
4119
-
4120
- Component.prototype.blur = function blur() {
4121
- this.el_.blur();
4122
- };
4123
-
4124
- /**
4125
- * Emit a 'tap' events when touch event support gets detected. This gets used to
4126
- * support toggling the controls through a tap on the video. They get enabled
4127
- * because every sub-component would have extra overhead otherwise.
4128
- *
4129
- * @private
4130
- * @fires Component#tap
4131
- * @listens Component#touchstart
4132
- * @listens Component#touchmove
4133
- * @listens Component#touchleave
4134
- * @listens Component#touchcancel
4135
- * @listens Component#touchend
4136
- */
4137
-
4138
-
4139
- Component.prototype.emitTapEvents = function emitTapEvents() {
4140
- // Track the start time so we can determine how long the touch lasted
4141
- var touchStart = 0;
4142
- var firstTouch = null;
4143
-
4144
- // Maximum movement allowed during a touch event to still be considered a tap
4145
- // Other popular libs use anywhere from 2 (hammer.js) to 15,
4146
- // so 10 seems like a nice, round number.
4147
- var tapMovementThreshold = 10;
4148
-
4149
- // The maximum length a touch can be while still being considered a tap
4150
- var touchTimeThreshold = 200;
4151
-
4152
- var couldBeTap = void 0;
4153
-
4154
- this.on('touchstart', function (event) {
4155
- // If more than one finger, don't consider treating this as a click
4156
- if (event.touches.length === 1) {
4157
- // Copy pageX/pageY from the object
4158
- firstTouch = {
4159
- pageX: event.touches[0].pageX,
4160
- pageY: event.touches[0].pageY
4161
- };
4162
- // Record start time so we can detect a tap vs. "touch and hold"
4163
- touchStart = new Date().getTime();
4164
- // Reset couldBeTap tracking
4165
- couldBeTap = true;
4166
- }
4167
- });
4168
-
4169
- this.on('touchmove', function (event) {
4170
- // If more than one finger, don't consider treating this as a click
4171
- if (event.touches.length > 1) {
4172
- couldBeTap = false;
4173
- } else if (firstTouch) {
4174
- // Some devices will throw touchmoves for all but the slightest of taps.
4175
- // So, if we moved only a small distance, this could still be a tap
4176
- var xdiff = event.touches[0].pageX - firstTouch.pageX;
4177
- var ydiff = event.touches[0].pageY - firstTouch.pageY;
4178
- var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
4179
-
4180
- if (touchDistance > tapMovementThreshold) {
4181
- couldBeTap = false;
4182
- }
4183
- }
4184
- });
4185
-
4186
- var noTap = function noTap() {
4187
- couldBeTap = false;
4188
- };
4189
-
4190
- // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
4191
- this.on('touchleave', noTap);
4192
- this.on('touchcancel', noTap);
4193
-
4194
- // When the touch ends, measure how long it took and trigger the appropriate
4195
- // event
4196
- this.on('touchend', function (event) {
4197
- firstTouch = null;
4198
- // Proceed only if the touchmove/leave/cancel event didn't happen
4199
- if (couldBeTap === true) {
4200
- // Measure how long the touch lasted
4201
- var touchTime = new Date().getTime() - touchStart;
4202
-
4203
- // Make sure the touch was less than the threshold to be considered a tap
4204
- if (touchTime < touchTimeThreshold) {
4205
- // Don't let browser turn this into a click
4206
- event.preventDefault();
4207
- /**
4208
- * Triggered when a `Component` is tapped.
4209
- *
4210
- * @event Component#tap
4211
- * @type {EventTarget~Event}
4212
- */
4213
- this.trigger('tap');
4214
- // It may be good to copy the touchend event object and change the
4215
- // type to tap, if the other event properties aren't exact after
4216
- // Events.fixEvent runs (e.g. event.target)
4217
- }
4218
- }
4219
- });
4220
- };
4221
-
4222
- /**
4223
- * This function reports user activity whenever touch events happen. This can get
4224
- * turned off by any sub-components that wants touch events to act another way.
4225
- *
4226
- * Report user touch activity when touch events occur. User activity gets used to
4227
- * determine when controls should show/hide. It is simple when it comes to mouse
4228
- * events, because any mouse event should show the controls. So we capture mouse
4229
- * events that bubble up to the player and report activity when that happens.
4230
- * With touch events it isn't as easy as `touchstart` and `touchend` toggle player
4231
- * controls. So touch events can't help us at the player level either.
4232
- *
4233
- * User activity gets checked asynchronously. So what could happen is a tap event
4234
- * on the video turns the controls off. Then the `touchend` event bubbles up to
4235
- * the player. Which, if it reported user activity, would turn the controls right
4236
- * back on. We also don't want to completely block touch events from bubbling up.
4237
- * Furthermore a `touchmove` event and anything other than a tap, should not turn
4238
- * controls back on.
4239
- *
4240
- * @listens Component#touchstart
4241
- * @listens Component#touchmove
4242
- * @listens Component#touchend
4243
- * @listens Component#touchcancel
4244
- */
4245
-
4246
-
4247
- Component.prototype.enableTouchActivity = function enableTouchActivity() {
4248
- // Don't continue if the root player doesn't support reporting user activity
4249
- if (!this.player() || !this.player().reportUserActivity) {
4250
- return;
4251
- }
4252
-
4253
- // listener for reporting that the user is active
4254
- var report = bind(this.player(), this.player().reportUserActivity);
4255
-
4256
- var touchHolding = void 0;
4257
-
4258
- this.on('touchstart', function () {
4259
- report();
4260
- // For as long as the they are touching the device or have their mouse down,
4261
- // we consider them active even if they're not moving their finger or mouse.
4262
- // So we want to continue to update that they are active
4263
- this.clearInterval(touchHolding);
4264
- // report at the same interval as activityCheck
4265
- touchHolding = this.setInterval(report, 250);
4266
- });
4267
-
4268
- var touchEnd = function touchEnd(event) {
4269
- report();
4270
- // stop the interval that maintains activity if the touch is holding
4271
- this.clearInterval(touchHolding);
4272
- };
4273
-
4274
- this.on('touchmove', report);
4275
- this.on('touchend', touchEnd);
4276
- this.on('touchcancel', touchEnd);
4277
- };
4278
-
4279
- /**
4280
- * A callback that has no parameters and is bound into `Component`s context.
4281
- *
4282
- * @callback Component~GenericCallback
4283
- * @this Component
4284
- */
4285
-
4286
- /**
4287
- * Creates a function that runs after an `x` millisecond timeout. This function is a
4288
- * wrapper around `window.setTimeout`. There are a few reasons to use this one
4289
- * instead though:
4290
- * 1. It gets cleared via {@link Component#clearTimeout} when
4291
- * {@link Component#dispose} gets called.
4292
- * 2. The function callback will gets turned into a {@link Component~GenericCallback}
4293
- *
4294
- * > Note: You can't use `window.clearTimeout` on the id returned by this function. This
4295
- * will cause its dispose listener not to get cleaned up! Please use
4296
- * {@link Component#clearTimeout} or {@link Component#dispose} instead.
4297
- *
4298
- * @param {Component~GenericCallback} fn
4299
- * The function that will be run after `timeout`.
4300
- *
4301
- * @param {number} timeout
4302
- * Timeout in milliseconds to delay before executing the specified function.
4303
- *
4304
- * @return {number}
4305
- * Returns a timeout ID that gets used to identify the timeout. It can also
4306
- * get used in {@link Component#clearTimeout} to clear the timeout that
4307
- * was set.
4308
- *
4309
- * @listens Component#dispose
4310
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
4311
- */
4312
-
4313
-
4314
- Component.prototype.setTimeout = function setTimeout(fn, timeout) {
4315
- var _this2 = this;
4316
-
4317
- // declare as variables so they are properly available in timeout function
4318
- // eslint-disable-next-line
4319
- var timeoutId, disposeFn;
4320
-
4321
- fn = bind(this, fn);
4322
-
4323
- timeoutId = window_1.setTimeout(function () {
4324
- _this2.off('dispose', disposeFn);
4325
- fn();
4326
- }, timeout);
4327
-
4328
- disposeFn = function disposeFn() {
4329
- return _this2.clearTimeout(timeoutId);
4330
- };
4331
-
4332
- disposeFn.guid = 'vjs-timeout-' + timeoutId;
4333
-
4334
- this.on('dispose', disposeFn);
4335
-
4336
- return timeoutId;
4337
- };
4338
-
4339
- /**
4340
- * Clears a timeout that gets created via `window.setTimeout` or
4341
- * {@link Component#setTimeout}. If you set a timeout via {@link Component#setTimeout}
4342
- * use this function instead of `window.clearTimout`. If you don't your dispose
4343
- * listener will not get cleaned up until {@link Component#dispose}!
4344
- *
4345
- * @param {number} timeoutId
4346
- * The id of the timeout to clear. The return value of
4347
- * {@link Component#setTimeout} or `window.setTimeout`.
4348
- *
4349
- * @return {number}
4350
- * Returns the timeout id that was cleared.
4351
- *
4352
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
4353
- */
4354
-
4355
-
4356
- Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
4357
- window_1.clearTimeout(timeoutId);
4358
-
4359
- var disposeFn = function disposeFn() {};
4360
-
4361
- disposeFn.guid = 'vjs-timeout-' + timeoutId;
4362
-
4363
- this.off('dispose', disposeFn);
4364
-
4365
- return timeoutId;
4366
- };
4367
-
4368
- /**
4369
- * Creates a function that gets run every `x` milliseconds. This function is a wrapper
4370
- * around `window.setInterval`. There are a few reasons to use this one instead though.
4371
- * 1. It gets cleared via {@link Component#clearInterval} when
4372
- * {@link Component#dispose} gets called.
4373
- * 2. The function callback will be a {@link Component~GenericCallback}
4374
- *
4375
- * @param {Component~GenericCallback} fn
4376
- * The function to run every `x` seconds.
4377
- *
4378
- * @param {number} interval
4379
- * Execute the specified function every `x` milliseconds.
4380
- *
4381
- * @return {number}
4382
- * Returns an id that can be used to identify the interval. It can also be be used in
4383
- * {@link Component#clearInterval} to clear the interval.
4384
- *
4385
- * @listens Component#dispose
4386
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
4387
- */
4388
-
4389
-
4390
- Component.prototype.setInterval = function setInterval(fn, interval) {
4391
- var _this3 = this;
4392
-
4393
- fn = bind(this, fn);
4394
-
4395
- var intervalId = window_1.setInterval(fn, interval);
4396
-
4397
- var disposeFn = function disposeFn() {
4398
- return _this3.clearInterval(intervalId);
4399
- };
4400
-
4401
- disposeFn.guid = 'vjs-interval-' + intervalId;
4402
-
4403
- this.on('dispose', disposeFn);
4404
-
4405
- return intervalId;
4406
- };
4407
-
4408
- /**
4409
- * Clears an interval that gets created via `window.setInterval` or
4410
- * {@link Component#setInterval}. If you set an inteval via {@link Component#setInterval}
4411
- * use this function instead of `window.clearInterval`. If you don't your dispose
4412
- * listener will not get cleaned up until {@link Component#dispose}!
4413
- *
4414
- * @param {number} intervalId
4415
- * The id of the interval to clear. The return value of
4416
- * {@link Component#setInterval} or `window.setInterval`.
4417
- *
4418
- * @return {number}
4419
- * Returns the interval id that was cleared.
4420
- *
4421
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
4422
- */
4423
-
4424
-
4425
- Component.prototype.clearInterval = function clearInterval(intervalId) {
4426
- window_1.clearInterval(intervalId);
4427
-
4428
- var disposeFn = function disposeFn() {};
4429
-
4430
- disposeFn.guid = 'vjs-interval-' + intervalId;
4431
-
4432
- this.off('dispose', disposeFn);
4433
-
4434
- return intervalId;
4435
- };
4436
-
4437
- /**
4438
- * Queues up a callback to be passed to requestAnimationFrame (rAF), but
4439
- * with a few extra bonuses:
4440
- *
4441
- * - Supports browsers that do not support rAF by falling back to
4442
- * {@link Component#setTimeout}.
4443
- *
4444
- * - The callback is turned into a {@link Component~GenericCallback} (i.e.
4445
- * bound to the component).
4446
- *
4447
- * - Automatic cancellation of the rAF callback is handled if the component
4448
- * is disposed before it is called.
4449
- *
4450
- * @param {Component~GenericCallback} fn
4451
- * A function that will be bound to this component and executed just
4452
- * before the browser's next repaint.
4453
- *
4454
- * @return {number}
4455
- * Returns an rAF ID that gets used to identify the timeout. It can
4456
- * also be used in {@link Component#cancelAnimationFrame} to cancel
4457
- * the animation frame callback.
4458
- *
4459
- * @listens Component#dispose
4460
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame}
4461
- */
4462
-
4463
-
4464
- Component.prototype.requestAnimationFrame = function requestAnimationFrame(fn) {
4465
- var _this4 = this;
4466
-
4467
- // declare as variables so they are properly available in rAF function
4468
- // eslint-disable-next-line
4469
- var id, disposeFn;
4470
-
4471
- if (this.supportsRaf_) {
4472
- fn = bind(this, fn);
4473
-
4474
- id = window_1.requestAnimationFrame(function () {
4475
- _this4.off('dispose', disposeFn);
4476
- fn();
4477
- });
4478
-
4479
- disposeFn = function disposeFn() {
4480
- return _this4.cancelAnimationFrame(id);
4481
- };
4482
-
4483
- disposeFn.guid = 'vjs-raf-' + id;
4484
- this.on('dispose', disposeFn);
4485
-
4486
- return id;
4487
- }
4488
-
4489
- // Fall back to using a timer.
4490
- return this.setTimeout(fn, 1000 / 60);
4491
- };
4492
-
4493
- /**
4494
- * Cancels a queued callback passed to {@link Component#requestAnimationFrame}
4495
- * (rAF).
4496
- *
4497
- * If you queue an rAF callback via {@link Component#requestAnimationFrame},
4498
- * use this function instead of `window.cancelAnimationFrame`. If you don't,
4499
- * your dispose listener will not get cleaned up until {@link Component#dispose}!
4500
- *
4501
- * @param {number} id
4502
- * The rAF ID to clear. The return value of {@link Component#requestAnimationFrame}.
4503
- *
4504
- * @return {number}
4505
- * Returns the rAF ID that was cleared.
4506
- *
4507
- * @see [Similar to]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame}
4508
- */
4509
-
4510
-
4511
- Component.prototype.cancelAnimationFrame = function cancelAnimationFrame(id) {
4512
- if (this.supportsRaf_) {
4513
- window_1.cancelAnimationFrame(id);
4514
-
4515
- var disposeFn = function disposeFn() {};
4516
-
4517
- disposeFn.guid = 'vjs-raf-' + id;
4518
-
4519
- this.off('dispose', disposeFn);
4520
-
4521
- return id;
4522
- }
4523
-
4524
- // Fall back to using a timer.
4525
- return this.clearTimeout(id);
4526
- };
4527
-
4528
- /**
4529
- * Register a `Component` with `videojs` given the name and the component.
4530
- *
4531
- * > NOTE: {@link Tech}s should not be registered as a `Component`. {@link Tech}s
4532
- * should be registered using {@link Tech.registerTech} or
4533
- * {@link videojs:videojs.registerTech}.
4534
- *
4535
- * > NOTE: This function can also be seen on videojs as
4536
- * {@link videojs:videojs.registerComponent}.
4537
- *
4538
- * @param {string} name
4539
- * The name of the `Component` to register.
4540
- *
4541
- * @param {Component} ComponentToRegister
4542
- * The `Component` class to register.
4543
- *
4544
- * @return {Component}
4545
- * The `Component` that was registered.
4546
- */
4547
-
4548
-
4549
- Component.registerComponent = function registerComponent(name, ComponentToRegister) {
4550
- if (typeof name !== 'string' || !name) {
4551
- throw new Error('Illegal component name, "' + name + '"; must be a non-empty string.');
4552
- }
4553
-
4554
- var Tech = Component.getComponent('Tech');
4555
-
4556
- // We need to make sure this check is only done if Tech has been registered.
4557
- var isTech = Tech && Tech.isTech(ComponentToRegister);
4558
- var isComp = Component === ComponentToRegister || Component.prototype.isPrototypeOf(ComponentToRegister.prototype);
4559
-
4560
- if (isTech || !isComp) {
4561
- var reason = void 0;
4562
-
4563
- if (isTech) {
4564
- reason = 'techs must be registered using Tech.registerTech()';
4565
- } else {
4566
- reason = 'must be a Component subclass';
4567
- }
4568
-
4569
- throw new Error('Illegal component, "' + name + '"; ' + reason + '.');
4570
- }
4571
-
4572
- name = toTitleCase(name);
4573
-
4574
- if (!Component.components_) {
4575
- Component.components_ = {};
4576
- }
4577
-
4578
- var Player = Component.getComponent('Player');
4579
-
4580
- if (name === 'Player' && Player && Player.players) {
4581
- var players = Player.players;
4582
- var playerNames = Object.keys(players);
4583
-
4584
- // If we have players that were disposed, then their name will still be
4585
- // in Players.players. So, we must loop through and verify that the value
4586
- // for each item is not null. This allows registration of the Player component
4587
- // after all players have been disposed or before any were created.
4588
- if (players && playerNames.length > 0 && playerNames.map(function (pname) {
4589
- return players[pname];
4590
- }).every(Boolean)) {
4591
- throw new Error('Can not register Player component after player has been created.');
4592
- }
4593
- }
4594
-
4595
- Component.components_[name] = ComponentToRegister;
4596
-
4597
- return ComponentToRegister;
4598
- };
4599
-
4600
- /**
4601
- * Get a `Component` based on the name it was registered with.
4602
- *
4603
- * @param {string} name
4604
- * The Name of the component to get.
4605
- *
4606
- * @return {Component}
4607
- * The `Component` that got registered under the given name.
4608
- *
4609
- * @deprecated In `videojs` 6 this will not return `Component`s that were not
4610
- * registered using {@link Component.registerComponent}. Currently we
4611
- * check the global `videojs` object for a `Component` name and
4612
- * return that if it exists.
4613
- */
4614
-
4615
-
4616
- Component.getComponent = function getComponent(name) {
4617
- if (!name) {
4618
- return;
4619
- }
4620
-
4621
- name = toTitleCase(name);
4622
-
4623
- if (Component.components_ && Component.components_[name]) {
4624
- return Component.components_[name];
4625
- }
4626
- };
4627
-
4628
- return Component;
4629
- }();
4630
-
4631
- /**
4632
- * Whether or not this component supports `requestAnimationFrame`.
4633
- *
4634
- * This is exposed primarily for testing purposes.
4635
- *
4636
- * @private
4637
- * @type {Boolean}
4638
- */
4639
-
4640
-
4641
- Component.prototype.supportsRaf_ = typeof window_1.requestAnimationFrame === 'function' && typeof window_1.cancelAnimationFrame === 'function';
4642
-
4643
- Component.registerComponent('Component', Component);
4644
-
4645
- /**
4646
- * @file browser.js
4647
- * @module browser
4648
- */
4649
-
4650
- var USER_AGENT = window_1.navigator && window_1.navigator.userAgent || '';
4651
- var webkitVersionMap = /AppleWebKit\/([\d.]+)/i.exec(USER_AGENT);
4652
- var appleWebkitVersion = webkitVersionMap ? parseFloat(webkitVersionMap.pop()) : null;
4653
-
4654
- /*
4655
- * Device is an iPhone
4656
- *
4657
- * @type {Boolean}
4658
- * @constant
4659
- * @private
4660
- */
4661
- var IS_IPAD = /iPad/i.test(USER_AGENT);
4662
-
4663
- // The Facebook app's UIWebView identifies as both an iPhone and iPad, so
4664
- // to identify iPhones, we need to exclude iPads.
4665
- // http://artsy.github.io/blog/2012/10/18/the-perils-of-ios-user-agent-sniffing/
4666
- var IS_IPHONE = /iPhone/i.test(USER_AGENT) && !IS_IPAD;
4667
- var IS_IPOD = /iPod/i.test(USER_AGENT);
4668
- var IS_IOS = IS_IPHONE || IS_IPAD || IS_IPOD;
4669
-
4670
- var IOS_VERSION = function () {
4671
- var match = USER_AGENT.match(/OS (\d+)_/i);
4672
-
4673
- if (match && match[1]) {
4674
- return match[1];
4675
- }
4676
- return null;
4677
- }();
4678
-
4679
- var IS_ANDROID = /Android/i.test(USER_AGENT);
4680
- var ANDROID_VERSION = function () {
4681
- // This matches Android Major.Minor.Patch versions
4682
- // ANDROID_VERSION is Major.Minor as a Number, if Minor isn't available, then only Major is returned
4683
- var match = USER_AGENT.match(/Android (\d+)(?:\.(\d+))?(?:\.(\d+))*/i);
4684
-
4685
- if (!match) {
4686
- return null;
4687
- }
4688
-
4689
- var major = match[1] && parseFloat(match[1]);
4690
- var minor = match[2] && parseFloat(match[2]);
4691
-
4692
- if (major && minor) {
4693
- return parseFloat(match[1] + '.' + match[2]);
4694
- } else if (major) {
4695
- return major;
4696
- }
4697
- return null;
4698
- }();
4699
-
4700
- var IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537;
4701
-
4702
- var IS_FIREFOX = /Firefox/i.test(USER_AGENT);
4703
- var IS_EDGE = /Edge/i.test(USER_AGENT);
4704
- var IS_CHROME = !IS_EDGE && (/Chrome/i.test(USER_AGENT) || /CriOS/i.test(USER_AGENT));
4705
- var CHROME_VERSION = function () {
4706
- var match = USER_AGENT.match(/(Chrome|CriOS)\/(\d+)/);
4707
-
4708
- if (match && match[2]) {
4709
- return parseFloat(match[2]);
4710
- }
4711
- return null;
4712
- }();
4713
- var IE_VERSION = function () {
4714
- var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
4715
- var version = result && parseFloat(result[1]);
4716
-
4717
- if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
4718
- // IE 11 has a different user agent string than other IE versions
4719
- version = 11.0;
4720
- }
4721
-
4722
- return version;
4723
- }();
4724
-
4725
- var IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
4726
- var IS_ANY_SAFARI = (IS_SAFARI || IS_IOS) && !IS_CHROME;
4727
-
4728
- var TOUCH_ENABLED = isReal() && ('ontouchstart' in window_1 || window_1.navigator.maxTouchPoints || window_1.DocumentTouch && window_1.document instanceof window_1.DocumentTouch);
4729
-
4730
- var browser = /*#__PURE__*/Object.freeze({
4731
- IS_IPAD: IS_IPAD,
4732
- IS_IPHONE: IS_IPHONE,
4733
- IS_IPOD: IS_IPOD,
4734
- IS_IOS: IS_IOS,
4735
- IOS_VERSION: IOS_VERSION,
4736
- IS_ANDROID: IS_ANDROID,
4737
- ANDROID_VERSION: ANDROID_VERSION,
4738
- IS_NATIVE_ANDROID: IS_NATIVE_ANDROID,
4739
- IS_FIREFOX: IS_FIREFOX,
4740
- IS_EDGE: IS_EDGE,
4741
- IS_CHROME: IS_CHROME,
4742
- CHROME_VERSION: CHROME_VERSION,
4743
- IE_VERSION: IE_VERSION,
4744
- IS_SAFARI: IS_SAFARI,
4745
- IS_ANY_SAFARI: IS_ANY_SAFARI,
4746
- TOUCH_ENABLED: TOUCH_ENABLED
4747
- });
4748
-
4749
- /**
4750
- * @file time-ranges.js
4751
- * @module time-ranges
4752
- */
4753
-
4754
- /**
4755
- * Returns the time for the specified index at the start or end
4756
- * of a TimeRange object.
4757
- *
4758
- * @function time-ranges:indexFunction
4759
- *
4760
- * @param {number} [index=0]
4761
- * The range number to return the time for.
4762
- *
4763
- * @return {number}
4764
- * The time that offset at the specified index.
4765
- *
4766
- * @depricated index must be set to a value, in the future this will throw an error.
4767
- */
4768
-
4769
- /**
4770
- * An object that contains ranges of time for various reasons.
4771
- *
4772
- * @typedef {Object} TimeRange
4773
- *
4774
- * @property {number} length
4775
- * The number of time ranges represented by this Object
4776
- *
4777
- * @property {time-ranges:indexFunction} start
4778
- * Returns the time offset at which a specified time range begins.
4779
- *
4780
- * @property {time-ranges:indexFunction} end
4781
- * Returns the time offset at which a specified time range ends.
4782
- *
4783
- * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges
4784
- */
4785
-
4786
- /**
4787
- * Check if any of the time ranges are over the maximum index.
4788
- *
4789
- * @param {string} fnName
4790
- * The function name to use for logging
4791
- *
4792
- * @param {number} index
4793
- * The index to check
4794
- *
4795
- * @param {number} maxIndex
4796
- * The maximum possible index
4797
- *
4798
- * @throws {Error} if the timeRanges provided are over the maxIndex
4799
- */
4800
- function rangeCheck(fnName, index, maxIndex) {
4801
- if (typeof index !== 'number' || index < 0 || index > maxIndex) {
4802
- throw new Error('Failed to execute \'' + fnName + '\' on \'TimeRanges\': The index provided (' + index + ') is non-numeric or out of bounds (0-' + maxIndex + ').');
4803
- }
4804
- }
4805
-
4806
- /**
4807
- * Get the time for the specified index at the start or end
4808
- * of a TimeRange object.
4809
- *
4810
- * @param {string} fnName
4811
- * The function name to use for logging
4812
- *
4813
- * @param {string} valueIndex
4814
- * The property that should be used to get the time. should be 'start' or 'end'
4815
- *
4816
- * @param {Array} ranges
4817
- * An array of time ranges
4818
- *
4819
- * @param {Array} [rangeIndex=0]
4820
- * The index to start the search at
4821
- *
4822
- * @return {number}
4823
- * The time that offset at the specified index.
4824
- *
4825
- *
4826
- * @depricated rangeIndex must be set to a value, in the future this will throw an error.
4827
- * @throws {Error} if rangeIndex is more than the length of ranges
4828
- */
4829
- function getRange(fnName, valueIndex, ranges, rangeIndex) {
4830
- rangeCheck(fnName, rangeIndex, ranges.length - 1);
4831
- return ranges[rangeIndex][valueIndex];
4832
- }
4833
-
4834
- /**
4835
- * Create a time range object given ranges of time.
4836
- *
4837
- * @param {Array} [ranges]
4838
- * An array of time ranges.
4839
- */
4840
- function createTimeRangesObj(ranges) {
4841
- if (ranges === undefined || ranges.length === 0) {
4842
- return {
4843
- length: 0,
4844
- start: function start() {
4845
- throw new Error('This TimeRanges object is empty');
4846
- },
4847
- end: function end() {
4848
- throw new Error('This TimeRanges object is empty');
4849
- }
4850
- };
4851
- }
4852
- return {
4853
- length: ranges.length,
4854
- start: getRange.bind(null, 'start', 0, ranges),
4855
- end: getRange.bind(null, 'end', 1, ranges)
4856
- };
4857
- }
4858
-
4859
- /**
4860
- * Should create a fake `TimeRange` object which mimics an HTML5 time range instance.
4861
- *
4862
- * @param {number|Array} start
4863
- * The start of a single range or an array of ranges
4864
- *
4865
- * @param {number} end
4866
- * The end of a single range.
4867
- *
4868
- * @private
4869
- */
4870
- function createTimeRanges(start, end) {
4871
- if (Array.isArray(start)) {
4872
- return createTimeRangesObj(start);
4873
- } else if (start === undefined || end === undefined) {
4874
- return createTimeRangesObj();
4875
- }
4876
- return createTimeRangesObj([[start, end]]);
4877
- }
4878
-
4879
- /**
4880
- * @file buffer.js
4881
- * @module buffer
4882
- */
4883
-
4884
- /**
4885
- * Compute the percentage of the media that has been buffered.
4886
- *
4887
- * @param {TimeRange} buffered
4888
- * The current `TimeRange` object representing buffered time ranges
4889
- *
4890
- * @param {number} duration
4891
- * Total duration of the media
4892
- *
4893
- * @return {number}
4894
- * Percent buffered of the total duration in decimal form.
4895
- */
4896
- function bufferedPercent(buffered, duration) {
4897
- var bufferedDuration = 0;
4898
- var start = void 0;
4899
- var end = void 0;
4900
-
4901
- if (!duration) {
4902
- return 0;
4903
- }
4904
-
4905
- if (!buffered || !buffered.length) {
4906
- buffered = createTimeRanges(0, 0);
4907
- }
4908
-
4909
- for (var i = 0; i < buffered.length; i++) {
4910
- start = buffered.start(i);
4911
- end = buffered.end(i);
4912
-
4913
- // buffered end can be bigger than duration by a very small fraction
4914
- if (end > duration) {
4915
- end = duration;
4916
- }
4917
-
4918
- bufferedDuration += end - start;
4919
- }
4920
-
4921
- return bufferedDuration / duration;
4922
- }
4923
-
4924
- /**
4925
- * @file fullscreen-api.js
4926
- * @module fullscreen-api
4927
- * @private
4928
- */
4929
-
4930
- /**
4931
- * Store the browser-specific methods for the fullscreen API.
4932
- *
4933
- * @type {Object}
4934
- * @see [Specification]{@link https://fullscreen.spec.whatwg.org}
4935
- * @see [Map Approach From Screenfull.js]{@link https://github.com/sindresorhus/screenfull.js}
4936
- */
4937
- var FullscreenApi = {};
4938
-
4939
- // browser API methods
4940
- var apiMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'],
4941
- // WebKit
4942
- ['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'],
4943
- // Old WebKit (Safari 5.1)
4944
- ['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'],
4945
- // Mozilla
4946
- ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'],
4947
- // Microsoft
4948
- ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']];
4949
-
4950
- var specApi = apiMap[0];
4951
- var browserApi = void 0;
4952
-
4953
- // determine the supported set of functions
4954
- for (var i = 0; i < apiMap.length; i++) {
4955
- // check for exitFullscreen function
4956
- if (apiMap[i][1] in document_1) {
4957
- browserApi = apiMap[i];
4958
- break;
4959
- }
4960
- }
4961
-
4962
- // map the browser API names to the spec API names
4963
- if (browserApi) {
4964
- for (var _i = 0; _i < browserApi.length; _i++) {
4965
- FullscreenApi[specApi[_i]] = browserApi[_i];
4966
- }
4967
- }
4968
-
4969
- /**
4970
- * @file media-error.js
4971
- */
4972
-
4973
- /**
4974
- * A Custom `MediaError` class which mimics the standard HTML5 `MediaError` class.
4975
- *
4976
- * @param {number|string|Object|MediaError} value
4977
- * This can be of multiple types:
4978
- * - number: should be a standard error code
4979
- * - string: an error message (the code will be 0)
4980
- * - Object: arbitrary properties
4981
- * - `MediaError` (native): used to populate a video.js `MediaError` object
4982
- * - `MediaError` (video.js): will return itself if it's already a
4983
- * video.js `MediaError` object.
4984
- *
4985
- * @see [MediaError Spec]{@link https://dev.w3.org/html5/spec-author-view/video.html#mediaerror}
4986
- * @see [Encrypted MediaError Spec]{@link https://www.w3.org/TR/2013/WD-encrypted-media-20130510/#error-codes}
4987
- *
4988
- * @class MediaError
4989
- */
4990
- function MediaError(value) {
4991
-
4992
- // Allow redundant calls to this constructor to avoid having `instanceof`
4993
- // checks peppered around the code.
4994
- if (value instanceof MediaError) {
4995
- return value;
4996
- }
4997
-
4998
- if (typeof value === 'number') {
4999
- this.code = value;
5000
- } else if (typeof value === 'string') {
5001
- // default code is zero, so this is a custom error
5002
- this.message = value;
5003
- } else if (isObject(value)) {
5004
-
5005
- // We assign the `code` property manually because native `MediaError` objects
5006
- // do not expose it as an own/enumerable property of the object.
5007
- if (typeof value.code === 'number') {
5008
- this.code = value.code;
5009
- }
5010
-
5011
- assign(this, value);
5012
- }
5013
-
5014
- if (!this.message) {
5015
- this.message = MediaError.defaultMessages[this.code] || '';
5016
- }
5017
- }
5018
-
5019
- /**
5020
- * The error code that refers two one of the defined `MediaError` types
5021
- *
5022
- * @type {Number}
5023
- */
5024
- MediaError.prototype.code = 0;
5025
-
5026
- /**
5027
- * An optional message that to show with the error. Message is not part of the HTML5
5028
- * video spec but allows for more informative custom errors.
5029
- *
5030
- * @type {String}
5031
- */
5032
- MediaError.prototype.message = '';
5033
-
5034
- /**
5035
- * An optional status code that can be set by plugins to allow even more detail about
5036
- * the error. For example a plugin might provide a specific HTTP status code and an
5037
- * error message for that code. Then when the plugin gets that error this class will
5038
- * know how to display an error message for it. This allows a custom message to show
5039
- * up on the `Player` error overlay.
5040
- *
5041
- * @type {Array}
5042
- */
5043
- MediaError.prototype.status = null;
5044
-
5045
- /**
5046
- * Errors indexed by the W3C standard. The order **CANNOT CHANGE**! See the
5047
- * specification listed under {@link MediaError} for more information.
5048
- *
5049
- * @enum {array}
5050
- * @readonly
5051
- * @property {string} 0 - MEDIA_ERR_CUSTOM
5052
- * @property {string} 1 - MEDIA_ERR_CUSTOM
5053
- * @property {string} 2 - MEDIA_ERR_ABORTED
5054
- * @property {string} 3 - MEDIA_ERR_NETWORK
5055
- * @property {string} 4 - MEDIA_ERR_SRC_NOT_SUPPORTED
5056
- * @property {string} 5 - MEDIA_ERR_ENCRYPTED
5057
- */
5058
- MediaError.errorTypes = ['MEDIA_ERR_CUSTOM', 'MEDIA_ERR_ABORTED', 'MEDIA_ERR_NETWORK', 'MEDIA_ERR_DECODE', 'MEDIA_ERR_SRC_NOT_SUPPORTED', 'MEDIA_ERR_ENCRYPTED'];
5059
-
5060
- /**
5061
- * The default `MediaError` messages based on the {@link MediaError.errorTypes}.
5062
- *
5063
- * @type {Array}
5064
- * @constant
5065
- */
5066
- MediaError.defaultMessages = {
5067
- 1: 'You aborted the media playback',
5068
- 2: 'A network error caused the media download to fail part-way.',
5069
- 3: 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.',
5070
- 4: 'The media could not be loaded, either because the server or network failed or because the format is not supported.',
5071
- 5: 'The media is encrypted and we do not have the keys to decrypt it.'
5072
- };
5073
-
5074
- // Add types as properties on MediaError
5075
- // e.g. MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
5076
- for (var errNum = 0; errNum < MediaError.errorTypes.length; errNum++) {
5077
- MediaError[MediaError.errorTypes[errNum]] = errNum;
5078
- // values should be accessible on both the class and instance
5079
- MediaError.prototype[MediaError.errorTypes[errNum]] = errNum;
5080
- }
5081
-
5082
- var tuple = SafeParseTuple;
5083
-
5084
- function SafeParseTuple(obj, reviver) {
5085
- var json;
5086
- var error = null;
5087
-
5088
- try {
5089
- json = JSON.parse(obj, reviver);
5090
- } catch (err) {
5091
- error = err;
5092
- }
5093
-
5094
- return [error, json];
5095
- }
5096
-
5097
- /**
5098
- * Returns whether an object is `Promise`-like (i.e. has a `then` method).
5099
- *
5100
- * @param {Object} value
5101
- * An object that may or may not be `Promise`-like.
5102
- *
5103
- * @return {Boolean}
5104
- * Whether or not the object is `Promise`-like.
5105
- */
5106
- function isPromise(value) {
5107
- return value !== undefined && value !== null && typeof value.then === 'function';
5108
- }
5109
-
5110
- /**
5111
- * Silence a Promise-like object.
5112
- *
5113
- * This is useful for avoiding non-harmful, but potentially confusing "uncaught
5114
- * play promise" rejection error messages.
5115
- *
5116
- * @param {Object} value
5117
- * An object that may or may not be `Promise`-like.
5118
- */
5119
- function silencePromise(value) {
5120
- if (isPromise(value)) {
5121
- value.then(null, function (e) {});
5122
- }
5123
- }
5124
-
5125
- /**
5126
- * @file text-track-list-converter.js Utilities for capturing text track state and
5127
- * re-creating tracks based on a capture.
5128
- *
5129
- * @module text-track-list-converter
5130
- */
5131
-
5132
- /**
5133
- * Examine a single {@link TextTrack} and return a JSON-compatible javascript object that
5134
- * represents the {@link TextTrack}'s state.
5135
- *
5136
- * @param {TextTrack} track
5137
- * The text track to query.
5138
- *
5139
- * @return {Object}
5140
- * A serializable javascript representation of the TextTrack.
5141
- * @private
5142
- */
5143
- var trackToJson_ = function trackToJson_(track) {
5144
- var ret = ['kind', 'label', 'language', 'id', 'inBandMetadataTrackDispatchType', 'mode', 'src'].reduce(function (acc, prop, i) {
5145
-
5146
- if (track[prop]) {
5147
- acc[prop] = track[prop];
5148
- }
5149
-
5150
- return acc;
5151
- }, {
5152
- cues: track.cues && Array.prototype.map.call(track.cues, function (cue) {
5153
- return {
5154
- startTime: cue.startTime,
5155
- endTime: cue.endTime,
5156
- text: cue.text,
5157
- id: cue.id
5158
- };
5159
- })
5160
- });
5161
-
5162
- return ret;
5163
- };
5164
-
5165
- /**
5166
- * Examine a {@link Tech} and return a JSON-compatible javascript array that represents the
5167
- * state of all {@link TextTrack}s currently configured. The return array is compatible with
5168
- * {@link text-track-list-converter:jsonToTextTracks}.
5169
- *
5170
- * @param {Tech} tech
5171
- * The tech object to query
5172
- *
5173
- * @return {Array}
5174
- * A serializable javascript representation of the {@link Tech}s
5175
- * {@link TextTrackList}.
5176
- */
5177
- var textTracksToJson = function textTracksToJson(tech) {
5178
-
5179
- var trackEls = tech.$$('track');
5180
-
5181
- var trackObjs = Array.prototype.map.call(trackEls, function (t) {
5182
- return t.track;
5183
- });
5184
- var tracks = Array.prototype.map.call(trackEls, function (trackEl) {
5185
- var json = trackToJson_(trackEl.track);
5186
-
5187
- if (trackEl.src) {
5188
- json.src = trackEl.src;
5189
- }
5190
- return json;
5191
- });
5192
-
5193
- return tracks.concat(Array.prototype.filter.call(tech.textTracks(), function (track) {
5194
- return trackObjs.indexOf(track) === -1;
5195
- }).map(trackToJson_));
5196
- };
5197
-
5198
- /**
5199
- * Create a set of remote {@link TextTrack}s on a {@link Tech} based on an array of javascript
5200
- * object {@link TextTrack} representations.
5201
- *
5202
- * @param {Array} json
5203
- * An array of `TextTrack` representation objects, like those that would be
5204
- * produced by `textTracksToJson`.
5205
- *
5206
- * @param {Tech} tech
5207
- * The `Tech` to create the `TextTrack`s on.
5208
- */
5209
- var jsonToTextTracks = function jsonToTextTracks(json, tech) {
5210
- json.forEach(function (track) {
5211
- var addedTrack = tech.addRemoteTextTrack(track).track;
5212
-
5213
- if (!track.src && track.cues) {
5214
- track.cues.forEach(function (cue) {
5215
- return addedTrack.addCue(cue);
5216
- });
5217
- }
5218
- });
5219
-
5220
- return tech.textTracks();
5221
- };
5222
-
5223
- var textTrackConverter = { textTracksToJson: textTracksToJson, jsonToTextTracks: jsonToTextTracks, trackToJson_: trackToJson_ };
5224
-
5225
- /**
5226
- * @file modal-dialog.js
5227
- */
5228
-
5229
- var MODAL_CLASS_NAME = 'vjs-modal-dialog';
5230
- var ESC = 27;
5231
-
5232
- /**
5233
- * The `ModalDialog` displays over the video and its controls, which blocks
5234
- * interaction with the player until it is closed.
5235
- *
5236
- * Modal dialogs include a "Close" button and will close when that button
5237
- * is activated - or when ESC is pressed anywhere.
5238
- *
5239
- * @extends Component
5240
- */
5241
-
5242
- var ModalDialog = function (_Component) {
5243
- inherits(ModalDialog, _Component);
5244
-
5245
- /**
5246
- * Create an instance of this class.
5247
- *
5248
- * @param {Player} player
5249
- * The `Player` that this class should be attached to.
5250
- *
5251
- * @param {Object} [options]
5252
- * The key/value store of player options.
5253
- *
5254
- * @param {Mixed} [options.content=undefined]
5255
- * Provide customized content for this modal.
5256
- *
5257
- * @param {string} [options.description]
5258
- * A text description for the modal, primarily for accessibility.
5259
- *
5260
- * @param {boolean} [options.fillAlways=false]
5261
- * Normally, modals are automatically filled only the first time
5262
- * they open. This tells the modal to refresh its content
5263
- * every time it opens.
5264
- *
5265
- * @param {string} [options.label]
5266
- * A text label for the modal, primarily for accessibility.
5267
- *
5268
- * @param {boolean} [options.temporary=true]
5269
- * If `true`, the modal can only be opened once; it will be
5270
- * disposed as soon as it's closed.
5271
- *
5272
- * @param {boolean} [options.uncloseable=false]
5273
- * If `true`, the user will not be able to close the modal
5274
- * through the UI in the normal ways. Programmatic closing is
5275
- * still possible.
5276
- */
5277
- function ModalDialog(player, options) {
5278
- classCallCheck(this, ModalDialog);
5279
-
5280
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
5281
-
5282
- _this.opened_ = _this.hasBeenOpened_ = _this.hasBeenFilled_ = false;
5283
-
5284
- _this.closeable(!_this.options_.uncloseable);
5285
- _this.content(_this.options_.content);
5286
-
5287
- // Make sure the contentEl is defined AFTER any children are initialized
5288
- // because we only want the contents of the modal in the contentEl
5289
- // (not the UI elements like the close button).
5290
- _this.contentEl_ = createEl('div', {
5291
- className: MODAL_CLASS_NAME + '-content'
5292
- }, {
5293
- role: 'document'
5294
- });
5295
-
5296
- _this.descEl_ = createEl('p', {
5297
- className: MODAL_CLASS_NAME + '-description vjs-control-text',
5298
- id: _this.el().getAttribute('aria-describedby')
5299
- });
5300
-
5301
- textContent(_this.descEl_, _this.description());
5302
- _this.el_.appendChild(_this.descEl_);
5303
- _this.el_.appendChild(_this.contentEl_);
5304
- return _this;
5305
- }
5306
-
5307
- /**
5308
- * Create the `ModalDialog`'s DOM element
5309
- *
5310
- * @return {Element}
5311
- * The DOM element that gets created.
5312
- */
5313
-
5314
-
5315
- ModalDialog.prototype.createEl = function createEl$$1() {
5316
- return _Component.prototype.createEl.call(this, 'div', {
5317
- className: this.buildCSSClass(),
5318
- tabIndex: -1
5319
- }, {
5320
- 'aria-describedby': this.id() + '_description',
5321
- 'aria-hidden': 'true',
5322
- 'aria-label': this.label(),
5323
- 'role': 'dialog'
5324
- });
5325
- };
5326
-
5327
- ModalDialog.prototype.dispose = function dispose() {
5328
- this.contentEl_ = null;
5329
- this.descEl_ = null;
5330
- this.previouslyActiveEl_ = null;
5331
-
5332
- _Component.prototype.dispose.call(this);
5333
- };
5334
-
5335
- /**
5336
- * Builds the default DOM `className`.
5337
- *
5338
- * @return {string}
5339
- * The DOM `className` for this object.
5340
- */
5341
-
5342
-
5343
- ModalDialog.prototype.buildCSSClass = function buildCSSClass() {
5344
- return MODAL_CLASS_NAME + ' vjs-hidden ' + _Component.prototype.buildCSSClass.call(this);
5345
- };
5346
-
5347
- /**
5348
- * Handles `keydown` events on the document, looking for ESC, which closes
5349
- * the modal.
5350
- *
5351
- * @param {EventTarget~Event} e
5352
- * The keypress that triggered this event.
5353
- *
5354
- * @listens keydown
5355
- */
5356
-
5357
-
5358
- ModalDialog.prototype.handleKeyPress = function handleKeyPress(e) {
5359
- if (e.which === ESC && this.closeable()) {
5360
- this.close();
5361
- }
5362
- };
5363
-
5364
- /**
5365
- * Returns the label string for this modal. Primarily used for accessibility.
5366
- *
5367
- * @return {string}
5368
- * the localized or raw label of this modal.
5369
- */
5370
-
5371
-
5372
- ModalDialog.prototype.label = function label() {
5373
- return this.localize(this.options_.label || 'Modal Window');
5374
- };
5375
-
5376
- /**
5377
- * Returns the description string for this modal. Primarily used for
5378
- * accessibility.
5379
- *
5380
- * @return {string}
5381
- * The localized or raw description of this modal.
5382
- */
5383
-
5384
-
5385
- ModalDialog.prototype.description = function description() {
5386
- var desc = this.options_.description || this.localize('This is a modal window.');
5387
-
5388
- // Append a universal closeability message if the modal is closeable.
5389
- if (this.closeable()) {
5390
- desc += ' ' + this.localize('This modal can be closed by pressing the Escape key or activating the close button.');
5391
- }
5392
-
5393
- return desc;
5394
- };
5395
-
5396
- /**
5397
- * Opens the modal.
5398
- *
5399
- * @fires ModalDialog#beforemodalopen
5400
- * @fires ModalDialog#modalopen
5401
- */
5402
-
5403
-
5404
- ModalDialog.prototype.open = function open() {
5405
- if (!this.opened_) {
5406
- var player = this.player();
5407
-
5408
- /**
5409
- * Fired just before a `ModalDialog` is opened.
5410
- *
5411
- * @event ModalDialog#beforemodalopen
5412
- * @type {EventTarget~Event}
5413
- */
5414
- this.trigger('beforemodalopen');
5415
- this.opened_ = true;
5416
-
5417
- // Fill content if the modal has never opened before and
5418
- // never been filled.
5419
- if (this.options_.fillAlways || !this.hasBeenOpened_ && !this.hasBeenFilled_) {
5420
- this.fill();
5421
- }
5422
-
5423
- // If the player was playing, pause it and take note of its previously
5424
- // playing state.
5425
- this.wasPlaying_ = !player.paused();
5426
-
5427
- if (this.options_.pauseOnOpen && this.wasPlaying_) {
5428
- player.pause();
5429
- }
5430
-
5431
- if (this.closeable()) {
5432
- this.on(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
5433
- }
5434
-
5435
- // Hide controls and note if they were enabled.
5436
- this.hadControls_ = player.controls();
5437
- player.controls(false);
5438
-
5439
- this.show();
5440
- this.conditionalFocus_();
5441
- this.el().setAttribute('aria-hidden', 'false');
5442
-
5443
- /**
5444
- * Fired just after a `ModalDialog` is opened.
5445
- *
5446
- * @event ModalDialog#modalopen
5447
- * @type {EventTarget~Event}
5448
- */
5449
- this.trigger('modalopen');
5450
- this.hasBeenOpened_ = true;
5451
- }
5452
- };
5453
-
5454
- /**
5455
- * If the `ModalDialog` is currently open or closed.
5456
- *
5457
- * @param {boolean} [value]
5458
- * If given, it will open (`true`) or close (`false`) the modal.
5459
- *
5460
- * @return {boolean}
5461
- * the current open state of the modaldialog
5462
- */
5463
-
5464
-
5465
- ModalDialog.prototype.opened = function opened(value) {
5466
- if (typeof value === 'boolean') {
5467
- this[value ? 'open' : 'close']();
5468
- }
5469
- return this.opened_;
5470
- };
5471
-
5472
- /**
5473
- * Closes the modal, does nothing if the `ModalDialog` is
5474
- * not open.
5475
- *
5476
- * @fires ModalDialog#beforemodalclose
5477
- * @fires ModalDialog#modalclose
5478
- */
5479
-
5480
-
5481
- ModalDialog.prototype.close = function close() {
5482
- if (!this.opened_) {
5483
- return;
5484
- }
5485
- var player = this.player();
5486
-
5487
- /**
5488
- * Fired just before a `ModalDialog` is closed.
5489
- *
5490
- * @event ModalDialog#beforemodalclose
5491
- * @type {EventTarget~Event}
5492
- */
5493
- this.trigger('beforemodalclose');
5494
- this.opened_ = false;
5495
-
5496
- if (this.wasPlaying_ && this.options_.pauseOnOpen) {
5497
- player.play();
5498
- }
5499
-
5500
- if (this.closeable()) {
5501
- this.off(this.el_.ownerDocument, 'keydown', bind(this, this.handleKeyPress));
5502
- }
5503
-
5504
- if (this.hadControls_) {
5505
- player.controls(true);
5506
- }
5507
-
5508
- this.hide();
5509
- this.el().setAttribute('aria-hidden', 'true');
5510
-
5511
- /**
5512
- * Fired just after a `ModalDialog` is closed.
5513
- *
5514
- * @event ModalDialog#modalclose
5515
- * @type {EventTarget~Event}
5516
- */
5517
- this.trigger('modalclose');
5518
- this.conditionalBlur_();
5519
-
5520
- if (this.options_.temporary) {
5521
- this.dispose();
5522
- }
5523
- };
5524
-
5525
- /**
5526
- * Check to see if the `ModalDialog` is closeable via the UI.
5527
- *
5528
- * @param {boolean} [value]
5529
- * If given as a boolean, it will set the `closeable` option.
5530
- *
5531
- * @return {boolean}
5532
- * Returns the final value of the closable option.
5533
- */
5534
-
5535
-
5536
- ModalDialog.prototype.closeable = function closeable(value) {
5537
- if (typeof value === 'boolean') {
5538
- var closeable = this.closeable_ = !!value;
5539
- var close = this.getChild('closeButton');
5540
-
5541
- // If this is being made closeable and has no close button, add one.
5542
- if (closeable && !close) {
5543
-
5544
- // The close button should be a child of the modal - not its
5545
- // content element, so temporarily change the content element.
5546
- var temp = this.contentEl_;
5547
-
5548
- this.contentEl_ = this.el_;
5549
- close = this.addChild('closeButton', { controlText: 'Close Modal Dialog' });
5550
- this.contentEl_ = temp;
5551
- this.on(close, 'close', this.close);
5552
- }
5553
-
5554
- // If this is being made uncloseable and has a close button, remove it.
5555
- if (!closeable && close) {
5556
- this.off(close, 'close', this.close);
5557
- this.removeChild(close);
5558
- close.dispose();
5559
- }
5560
- }
5561
- return this.closeable_;
5562
- };
5563
-
5564
- /**
5565
- * Fill the modal's content element with the modal's "content" option.
5566
- * The content element will be emptied before this change takes place.
5567
- */
5568
-
5569
-
5570
- ModalDialog.prototype.fill = function fill() {
5571
- this.fillWith(this.content());
5572
- };
5573
-
5574
- /**
5575
- * Fill the modal's content element with arbitrary content.
5576
- * The content element will be emptied before this change takes place.
5577
- *
5578
- * @fires ModalDialog#beforemodalfill
5579
- * @fires ModalDialog#modalfill
5580
- *
5581
- * @param {Mixed} [content]
5582
- * The same rules apply to this as apply to the `content` option.
5583
- */
5584
-
5585
-
5586
- ModalDialog.prototype.fillWith = function fillWith(content) {
5587
- var contentEl = this.contentEl();
5588
- var parentEl = contentEl.parentNode;
5589
- var nextSiblingEl = contentEl.nextSibling;
5590
-
5591
- /**
5592
- * Fired just before a `ModalDialog` is filled with content.
5593
- *
5594
- * @event ModalDialog#beforemodalfill
5595
- * @type {EventTarget~Event}
5596
- */
5597
- this.trigger('beforemodalfill');
5598
- this.hasBeenFilled_ = true;
5599
-
5600
- // Detach the content element from the DOM before performing
5601
- // manipulation to avoid modifying the live DOM multiple times.
5602
- parentEl.removeChild(contentEl);
5603
- this.empty();
5604
- insertContent(contentEl, content);
5605
- /**
5606
- * Fired just after a `ModalDialog` is filled with content.
5607
- *
5608
- * @event ModalDialog#modalfill
5609
- * @type {EventTarget~Event}
5610
- */
5611
- this.trigger('modalfill');
5612
-
5613
- // Re-inject the re-filled content element.
5614
- if (nextSiblingEl) {
5615
- parentEl.insertBefore(contentEl, nextSiblingEl);
5616
- } else {
5617
- parentEl.appendChild(contentEl);
5618
- }
5619
-
5620
- // make sure that the close button is last in the dialog DOM
5621
- var closeButton = this.getChild('closeButton');
5622
-
5623
- if (closeButton) {
5624
- parentEl.appendChild(closeButton.el_);
5625
- }
5626
- };
5627
-
5628
- /**
5629
- * Empties the content element. This happens anytime the modal is filled.
5630
- *
5631
- * @fires ModalDialog#beforemodalempty
5632
- * @fires ModalDialog#modalempty
5633
- */
5634
-
5635
-
5636
- ModalDialog.prototype.empty = function empty() {
5637
- /**
5638
- * Fired just before a `ModalDialog` is emptied.
5639
- *
5640
- * @event ModalDialog#beforemodalempty
5641
- * @type {EventTarget~Event}
5642
- */
5643
- this.trigger('beforemodalempty');
5644
- emptyEl(this.contentEl());
5645
-
5646
- /**
5647
- * Fired just after a `ModalDialog` is emptied.
5648
- *
5649
- * @event ModalDialog#modalempty
5650
- * @type {EventTarget~Event}
5651
- */
5652
- this.trigger('modalempty');
5653
- };
5654
-
5655
- /**
5656
- * Gets or sets the modal content, which gets normalized before being
5657
- * rendered into the DOM.
5658
- *
5659
- * This does not update the DOM or fill the modal, but it is called during
5660
- * that process.
5661
- *
5662
- * @param {Mixed} [value]
5663
- * If defined, sets the internal content value to be used on the
5664
- * next call(s) to `fill`. This value is normalized before being
5665
- * inserted. To "clear" the internal content value, pass `null`.
5666
- *
5667
- * @return {Mixed}
5668
- * The current content of the modal dialog
5669
- */
5670
-
5671
-
5672
- ModalDialog.prototype.content = function content(value) {
5673
- if (typeof value !== 'undefined') {
5674
- this.content_ = value;
5675
- }
5676
- return this.content_;
5677
- };
5678
-
5679
- /**
5680
- * conditionally focus the modal dialog if focus was previously on the player.
5681
- *
5682
- * @private
5683
- */
5684
-
5685
-
5686
- ModalDialog.prototype.conditionalFocus_ = function conditionalFocus_() {
5687
- var activeEl = document_1.activeElement;
5688
- var playerEl = this.player_.el_;
5689
-
5690
- this.previouslyActiveEl_ = null;
5691
-
5692
- if (playerEl.contains(activeEl) || playerEl === activeEl) {
5693
- this.previouslyActiveEl_ = activeEl;
5694
-
5695
- this.focus();
5696
-
5697
- this.on(document_1, 'keydown', this.handleKeyDown);
5698
- }
5699
- };
5700
-
5701
- /**
5702
- * conditionally blur the element and refocus the last focused element
5703
- *
5704
- * @private
5705
- */
5706
-
5707
-
5708
- ModalDialog.prototype.conditionalBlur_ = function conditionalBlur_() {
5709
- if (this.previouslyActiveEl_) {
5710
- this.previouslyActiveEl_.focus();
5711
- this.previouslyActiveEl_ = null;
5712
- }
5713
-
5714
- this.off(document_1, 'keydown', this.handleKeyDown);
5715
- };
5716
-
5717
- /**
5718
- * Keydown handler. Attached when modal is focused.
5719
- *
5720
- * @listens keydown
5721
- */
5722
-
5723
-
5724
- ModalDialog.prototype.handleKeyDown = function handleKeyDown(event) {
5725
- // exit early if it isn't a tab key
5726
- if (event.which !== 9) {
5727
- return;
5728
- }
5729
-
5730
- var focusableEls = this.focusableEls_();
5731
- var activeEl = this.el_.querySelector(':focus');
5732
- var focusIndex = void 0;
5733
-
5734
- for (var i = 0; i < focusableEls.length; i++) {
5735
- if (activeEl === focusableEls[i]) {
5736
- focusIndex = i;
5737
- break;
5738
- }
5739
- }
5740
-
5741
- if (document_1.activeElement === this.el_) {
5742
- focusIndex = 0;
5743
- }
5744
-
5745
- if (event.shiftKey && focusIndex === 0) {
5746
- focusableEls[focusableEls.length - 1].focus();
5747
- event.preventDefault();
5748
- } else if (!event.shiftKey && focusIndex === focusableEls.length - 1) {
5749
- focusableEls[0].focus();
5750
- event.preventDefault();
5751
- }
5752
- };
5753
-
5754
- /**
5755
- * get all focusable elements
5756
- *
5757
- * @private
5758
- */
5759
-
5760
-
5761
- ModalDialog.prototype.focusableEls_ = function focusableEls_() {
5762
- var allChildren = this.el_.querySelectorAll('*');
5763
-
5764
- return Array.prototype.filter.call(allChildren, function (child) {
5765
- return (child instanceof window_1.HTMLAnchorElement || child instanceof window_1.HTMLAreaElement) && child.hasAttribute('href') || (child instanceof window_1.HTMLInputElement || child instanceof window_1.HTMLSelectElement || child instanceof window_1.HTMLTextAreaElement || child instanceof window_1.HTMLButtonElement) && !child.hasAttribute('disabled') || child instanceof window_1.HTMLIFrameElement || child instanceof window_1.HTMLObjectElement || child instanceof window_1.HTMLEmbedElement || child.hasAttribute('tabindex') && child.getAttribute('tabindex') !== -1 || child.hasAttribute('contenteditable');
5766
- });
5767
- };
5768
-
5769
- return ModalDialog;
5770
- }(Component);
5771
-
5772
- /**
5773
- * Default options for `ModalDialog` default options.
5774
- *
5775
- * @type {Object}
5776
- * @private
5777
- */
5778
-
5779
-
5780
- ModalDialog.prototype.options_ = {
5781
- pauseOnOpen: true,
5782
- temporary: true
5783
- };
5784
-
5785
- Component.registerComponent('ModalDialog', ModalDialog);
5786
-
5787
- /**
5788
- * @file track-list.js
5789
- */
5790
-
5791
- /**
5792
- * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and
5793
- * {@link VideoTrackList}
5794
- *
5795
- * @extends EventTarget
5796
- */
5797
-
5798
- var TrackList = function (_EventTarget) {
5799
- inherits(TrackList, _EventTarget);
5800
-
5801
- /**
5802
- * Create an instance of this class
5803
- *
5804
- * @param {Track[]} tracks
5805
- * A list of tracks to initialize the list with.
5806
- *
5807
- * @abstract
5808
- */
5809
- function TrackList() {
5810
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
5811
- classCallCheck(this, TrackList);
5812
-
5813
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
5814
-
5815
- _this.tracks_ = [];
5816
-
5817
- /**
5818
- * @memberof TrackList
5819
- * @member {number} length
5820
- * The current number of `Track`s in the this Trackist.
5821
- * @instance
5822
- */
5823
- Object.defineProperty(_this, 'length', {
5824
- get: function get$$1() {
5825
- return this.tracks_.length;
5826
- }
5827
- });
5828
-
5829
- for (var i = 0; i < tracks.length; i++) {
5830
- _this.addTrack(tracks[i]);
5831
- }
5832
- return _this;
5833
- }
5834
-
5835
- /**
5836
- * Add a {@link Track} to the `TrackList`
5837
- *
5838
- * @param {Track} track
5839
- * The audio, video, or text track to add to the list.
5840
- *
5841
- * @fires TrackList#addtrack
5842
- */
5843
-
5844
-
5845
- TrackList.prototype.addTrack = function addTrack(track) {
5846
- var index = this.tracks_.length;
5847
-
5848
- if (!('' + index in this)) {
5849
- Object.defineProperty(this, index, {
5850
- get: function get$$1() {
5851
- return this.tracks_[index];
5852
- }
5853
- });
5854
- }
5855
-
5856
- // Do not add duplicate tracks
5857
- if (this.tracks_.indexOf(track) === -1) {
5858
- this.tracks_.push(track);
5859
- /**
5860
- * Triggered when a track is added to a track list.
5861
- *
5862
- * @event TrackList#addtrack
5863
- * @type {EventTarget~Event}
5864
- * @property {Track} track
5865
- * A reference to track that was added.
5866
- */
5867
- this.trigger({
5868
- track: track,
5869
- type: 'addtrack'
5870
- });
5871
- }
5872
- };
5873
-
5874
- /**
5875
- * Remove a {@link Track} from the `TrackList`
5876
- *
5877
- * @param {Track} rtrack
5878
- * The audio, video, or text track to remove from the list.
5879
- *
5880
- * @fires TrackList#removetrack
5881
- */
5882
-
5883
-
5884
- TrackList.prototype.removeTrack = function removeTrack(rtrack) {
5885
- var track = void 0;
5886
-
5887
- for (var i = 0, l = this.length; i < l; i++) {
5888
- if (this[i] === rtrack) {
5889
- track = this[i];
5890
- if (track.off) {
5891
- track.off();
5892
- }
5893
-
5894
- this.tracks_.splice(i, 1);
5895
-
5896
- break;
5897
- }
5898
- }
5899
-
5900
- if (!track) {
5901
- return;
5902
- }
5903
-
5904
- /**
5905
- * Triggered when a track is removed from track list.
5906
- *
5907
- * @event TrackList#removetrack
5908
- * @type {EventTarget~Event}
5909
- * @property {Track} track
5910
- * A reference to track that was removed.
5911
- */
5912
- this.trigger({
5913
- track: track,
5914
- type: 'removetrack'
5915
- });
5916
- };
5917
-
5918
- /**
5919
- * Get a Track from the TrackList by a tracks id
5920
- *
5921
- * @param {String} id - the id of the track to get
5922
- * @method getTrackById
5923
- * @return {Track}
5924
- * @private
5925
- */
5926
-
5927
-
5928
- TrackList.prototype.getTrackById = function getTrackById(id) {
5929
- var result = null;
5930
-
5931
- for (var i = 0, l = this.length; i < l; i++) {
5932
- var track = this[i];
5933
-
5934
- if (track.id === id) {
5935
- result = track;
5936
- break;
5937
- }
5938
- }
5939
-
5940
- return result;
5941
- };
5942
-
5943
- return TrackList;
5944
- }(EventTarget);
5945
-
5946
- /**
5947
- * Triggered when a different track is selected/enabled.
5948
- *
5949
- * @event TrackList#change
5950
- * @type {EventTarget~Event}
5951
- */
5952
-
5953
- /**
5954
- * Events that can be called with on + eventName. See {@link EventHandler}.
5955
- *
5956
- * @property {Object} TrackList#allowedEvents_
5957
- * @private
5958
- */
5959
-
5960
-
5961
- TrackList.prototype.allowedEvents_ = {
5962
- change: 'change',
5963
- addtrack: 'addtrack',
5964
- removetrack: 'removetrack'
5965
- };
5966
-
5967
- // emulate attribute EventHandler support to allow for feature detection
5968
- for (var event in TrackList.prototype.allowedEvents_) {
5969
- TrackList.prototype['on' + event] = null;
5970
- }
5971
-
5972
- /**
5973
- * @file audio-track-list.js
5974
- */
5975
-
5976
- /**
5977
- * Anywhere we call this function we diverge from the spec
5978
- * as we only support one enabled audiotrack at a time
5979
- *
5980
- * @param {AudioTrackList} list
5981
- * list to work on
5982
- *
5983
- * @param {AudioTrack} track
5984
- * The track to skip
5985
- *
5986
- * @private
5987
- */
5988
- var disableOthers = function disableOthers(list, track) {
5989
- for (var i = 0; i < list.length; i++) {
5990
- if (!Object.keys(list[i]).length || track.id === list[i].id) {
5991
- continue;
5992
- }
5993
- // another audio track is enabled, disable it
5994
- list[i].enabled = false;
5995
- }
5996
- };
5997
-
5998
- /**
5999
- * The current list of {@link AudioTrack} for a media file.
6000
- *
6001
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist}
6002
- * @extends TrackList
6003
- */
6004
-
6005
- var AudioTrackList = function (_TrackList) {
6006
- inherits(AudioTrackList, _TrackList);
6007
-
6008
- /**
6009
- * Create an instance of this class.
6010
- *
6011
- * @param {AudioTrack[]} [tracks=[]]
6012
- * A list of `AudioTrack` to instantiate the list with.
6013
- */
6014
- function AudioTrackList() {
6015
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
6016
- classCallCheck(this, AudioTrackList);
6017
-
6018
- // make sure only 1 track is enabled
6019
- // sorted from last index to first index
6020
- for (var i = tracks.length - 1; i >= 0; i--) {
6021
- if (tracks[i].enabled) {
6022
- disableOthers(tracks, tracks[i]);
6023
- break;
6024
- }
6025
- }
6026
-
6027
- var _this = possibleConstructorReturn(this, _TrackList.call(this, tracks));
6028
-
6029
- _this.changing_ = false;
6030
- return _this;
6031
- }
6032
-
6033
- /**
6034
- * Add an {@link AudioTrack} to the `AudioTrackList`.
6035
- *
6036
- * @param {AudioTrack} track
6037
- * The AudioTrack to add to the list
6038
- *
6039
- * @fires TrackList#addtrack
6040
- */
6041
-
6042
-
6043
- AudioTrackList.prototype.addTrack = function addTrack(track) {
6044
- var _this2 = this;
6045
-
6046
- if (track.enabled) {
6047
- disableOthers(this, track);
6048
- }
6049
-
6050
- _TrackList.prototype.addTrack.call(this, track);
6051
- // native tracks don't have this
6052
- if (!track.addEventListener) {
6053
- return;
6054
- }
6055
-
6056
- /**
6057
- * @listens AudioTrack#enabledchange
6058
- * @fires TrackList#change
6059
- */
6060
- track.addEventListener('enabledchange', function () {
6061
- // when we are disabling other tracks (since we don't support
6062
- // more than one track at a time) we will set changing_
6063
- // to true so that we don't trigger additional change events
6064
- if (_this2.changing_) {
6065
- return;
6066
- }
6067
- _this2.changing_ = true;
6068
- disableOthers(_this2, track);
6069
- _this2.changing_ = false;
6070
- _this2.trigger('change');
6071
- });
6072
- };
6073
-
6074
- return AudioTrackList;
6075
- }(TrackList);
6076
-
6077
- /**
6078
- * @file video-track-list.js
6079
- */
6080
-
6081
- /**
6082
- * Un-select all other {@link VideoTrack}s that are selected.
6083
- *
6084
- * @param {VideoTrackList} list
6085
- * list to work on
6086
- *
6087
- * @param {VideoTrack} track
6088
- * The track to skip
6089
- *
6090
- * @private
6091
- */
6092
- var disableOthers$1 = function disableOthers(list, track) {
6093
- for (var i = 0; i < list.length; i++) {
6094
- if (!Object.keys(list[i]).length || track.id === list[i].id) {
6095
- continue;
6096
- }
6097
- // another video track is enabled, disable it
6098
- list[i].selected = false;
6099
- }
6100
- };
6101
-
6102
- /**
6103
- * The current list of {@link VideoTrack} for a video.
6104
- *
6105
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist}
6106
- * @extends TrackList
6107
- */
6108
-
6109
- var VideoTrackList = function (_TrackList) {
6110
- inherits(VideoTrackList, _TrackList);
6111
-
6112
- /**
6113
- * Create an instance of this class.
6114
- *
6115
- * @param {VideoTrack[]} [tracks=[]]
6116
- * A list of `VideoTrack` to instantiate the list with.
6117
- */
6118
- function VideoTrackList() {
6119
- var tracks = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
6120
- classCallCheck(this, VideoTrackList);
6121
-
6122
- // make sure only 1 track is enabled
6123
- // sorted from last index to first index
6124
- for (var i = tracks.length - 1; i >= 0; i--) {
6125
- if (tracks[i].selected) {
6126
- disableOthers$1(tracks, tracks[i]);
6127
- break;
6128
- }
6129
- }
6130
-
6131
- var _this = possibleConstructorReturn(this, _TrackList.call(this, tracks));
6132
-
6133
- _this.changing_ = false;
6134
-
6135
- /**
6136
- * @member {number} VideoTrackList#selectedIndex
6137
- * The current index of the selected {@link VideoTrack`}.
6138
- */
6139
- Object.defineProperty(_this, 'selectedIndex', {
6140
- get: function get$$1() {
6141
- for (var _i = 0; _i < this.length; _i++) {
6142
- if (this[_i].selected) {
6143
- return _i;
6144
- }
6145
- }
6146
- return -1;
6147
- },
6148
- set: function set$$1() {}
6149
- });
6150
- return _this;
6151
- }
6152
-
6153
- /**
6154
- * Add a {@link VideoTrack} to the `VideoTrackList`.
6155
- *
6156
- * @param {VideoTrack} track
6157
- * The VideoTrack to add to the list
6158
- *
6159
- * @fires TrackList#addtrack
6160
- */
6161
-
6162
-
6163
- VideoTrackList.prototype.addTrack = function addTrack(track) {
6164
- var _this2 = this;
6165
-
6166
- if (track.selected) {
6167
- disableOthers$1(this, track);
6168
- }
6169
-
6170
- _TrackList.prototype.addTrack.call(this, track);
6171
- // native tracks don't have this
6172
- if (!track.addEventListener) {
6173
- return;
6174
- }
6175
-
6176
- /**
6177
- * @listens VideoTrack#selectedchange
6178
- * @fires TrackList#change
6179
- */
6180
- track.addEventListener('selectedchange', function () {
6181
- if (_this2.changing_) {
6182
- return;
6183
- }
6184
- _this2.changing_ = true;
6185
- disableOthers$1(_this2, track);
6186
- _this2.changing_ = false;
6187
- _this2.trigger('change');
6188
- });
6189
- };
6190
-
6191
- return VideoTrackList;
6192
- }(TrackList);
6193
-
6194
- /**
6195
- * @file text-track-list.js
6196
- */
6197
-
6198
- /**
6199
- * The current list of {@link TextTrack} for a media file.
6200
- *
6201
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist}
6202
- * @extends TrackList
6203
- */
6204
-
6205
- var TextTrackList = function (_TrackList) {
6206
- inherits(TextTrackList, _TrackList);
6207
-
6208
- function TextTrackList() {
6209
- classCallCheck(this, TextTrackList);
6210
- return possibleConstructorReturn(this, _TrackList.apply(this, arguments));
6211
- }
6212
-
6213
- /**
6214
- * Add a {@link TextTrack} to the `TextTrackList`
6215
- *
6216
- * @param {TextTrack} track
6217
- * The text track to add to the list.
6218
- *
6219
- * @fires TrackList#addtrack
6220
- */
6221
- TextTrackList.prototype.addTrack = function addTrack(track) {
6222
- _TrackList.prototype.addTrack.call(this, track);
6223
-
6224
- /**
6225
- * @listens TextTrack#modechange
6226
- * @fires TrackList#change
6227
- */
6228
- track.addEventListener('modechange', bind(this, function () {
6229
- this.trigger('change');
6230
- }));
6231
-
6232
- var nonLanguageTextTrackKind = ['metadata', 'chapters'];
6233
-
6234
- if (nonLanguageTextTrackKind.indexOf(track.kind) === -1) {
6235
- track.addEventListener('modechange', bind(this, function () {
6236
- this.trigger('selectedlanguagechange');
6237
- }));
6238
- }
6239
- };
6240
-
6241
- return TextTrackList;
6242
- }(TrackList);
6243
-
6244
- /**
6245
- * @file html-track-element-list.js
6246
- */
6247
-
6248
- /**
6249
- * The current list of {@link HtmlTrackElement}s.
6250
- */
6251
- var HtmlTrackElementList = function () {
6252
-
6253
- /**
6254
- * Create an instance of this class.
6255
- *
6256
- * @param {HtmlTrackElement[]} [tracks=[]]
6257
- * A list of `HtmlTrackElement` to instantiate the list with.
6258
- */
6259
- function HtmlTrackElementList() {
6260
- var trackElements = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
6261
- classCallCheck(this, HtmlTrackElementList);
6262
-
6263
- this.trackElements_ = [];
6264
-
6265
- /**
6266
- * @memberof HtmlTrackElementList
6267
- * @member {number} length
6268
- * The current number of `Track`s in the this Trackist.
6269
- * @instance
6270
- */
6271
- Object.defineProperty(this, 'length', {
6272
- get: function get$$1() {
6273
- return this.trackElements_.length;
6274
- }
6275
- });
6276
-
6277
- for (var i = 0, length = trackElements.length; i < length; i++) {
6278
- this.addTrackElement_(trackElements[i]);
6279
- }
6280
- }
6281
-
6282
- /**
6283
- * Add an {@link HtmlTrackElement} to the `HtmlTrackElementList`
6284
- *
6285
- * @param {HtmlTrackElement} trackElement
6286
- * The track element to add to the list.
6287
- *
6288
- * @private
6289
- */
6290
-
6291
-
6292
- HtmlTrackElementList.prototype.addTrackElement_ = function addTrackElement_(trackElement) {
6293
- var index = this.trackElements_.length;
6294
-
6295
- if (!('' + index in this)) {
6296
- Object.defineProperty(this, index, {
6297
- get: function get$$1() {
6298
- return this.trackElements_[index];
6299
- }
6300
- });
6301
- }
6302
-
6303
- // Do not add duplicate elements
6304
- if (this.trackElements_.indexOf(trackElement) === -1) {
6305
- this.trackElements_.push(trackElement);
6306
- }
6307
- };
6308
-
6309
- /**
6310
- * Get an {@link HtmlTrackElement} from the `HtmlTrackElementList` given an
6311
- * {@link TextTrack}.
6312
- *
6313
- * @param {TextTrack} track
6314
- * The track associated with a track element.
6315
- *
6316
- * @return {HtmlTrackElement|undefined}
6317
- * The track element that was found or undefined.
6318
- *
6319
- * @private
6320
- */
6321
-
6322
-
6323
- HtmlTrackElementList.prototype.getTrackElementByTrack_ = function getTrackElementByTrack_(track) {
6324
- var trackElement_ = void 0;
6325
-
6326
- for (var i = 0, length = this.trackElements_.length; i < length; i++) {
6327
- if (track === this.trackElements_[i].track) {
6328
- trackElement_ = this.trackElements_[i];
6329
-
6330
- break;
6331
- }
6332
- }
6333
-
6334
- return trackElement_;
6335
- };
6336
-
6337
- /**
6338
- * Remove a {@link HtmlTrackElement} from the `HtmlTrackElementList`
6339
- *
6340
- * @param {HtmlTrackElement} trackElement
6341
- * The track element to remove from the list.
6342
- *
6343
- * @private
6344
- */
6345
-
6346
-
6347
- HtmlTrackElementList.prototype.removeTrackElement_ = function removeTrackElement_(trackElement) {
6348
- for (var i = 0, length = this.trackElements_.length; i < length; i++) {
6349
- if (trackElement === this.trackElements_[i]) {
6350
- this.trackElements_.splice(i, 1);
6351
-
6352
- break;
6353
- }
6354
- }
6355
- };
6356
-
6357
- return HtmlTrackElementList;
6358
- }();
6359
-
6360
- /**
6361
- * @file text-track-cue-list.js
6362
- */
6363
-
6364
- /**
6365
- * @typedef {Object} TextTrackCueList~TextTrackCue
6366
- *
6367
- * @property {string} id
6368
- * The unique id for this text track cue
6369
- *
6370
- * @property {number} startTime
6371
- * The start time for this text track cue
6372
- *
6373
- * @property {number} endTime
6374
- * The end time for this text track cue
6375
- *
6376
- * @property {boolean} pauseOnExit
6377
- * Pause when the end time is reached if true.
6378
- *
6379
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcue}
6380
- */
6381
-
6382
- /**
6383
- * A List of TextTrackCues.
6384
- *
6385
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist}
6386
- */
6387
- var TextTrackCueList = function () {
6388
-
6389
- /**
6390
- * Create an instance of this class..
6391
- *
6392
- * @param {Array} cues
6393
- * A list of cues to be initialized with
6394
- */
6395
- function TextTrackCueList(cues) {
6396
- classCallCheck(this, TextTrackCueList);
6397
-
6398
- TextTrackCueList.prototype.setCues_.call(this, cues);
6399
-
6400
- /**
6401
- * @memberof TextTrackCueList
6402
- * @member {number} length
6403
- * The current number of `TextTrackCue`s in the TextTrackCueList.
6404
- * @instance
6405
- */
6406
- Object.defineProperty(this, 'length', {
6407
- get: function get$$1() {
6408
- return this.length_;
6409
- }
6410
- });
6411
- }
6412
-
6413
- /**
6414
- * A setter for cues in this list. Creates getters
6415
- * an an index for the cues.
6416
- *
6417
- * @param {Array} cues
6418
- * An array of cues to set
6419
- *
6420
- * @private
6421
- */
6422
-
6423
-
6424
- TextTrackCueList.prototype.setCues_ = function setCues_(cues) {
6425
- var oldLength = this.length || 0;
6426
- var i = 0;
6427
- var l = cues.length;
6428
-
6429
- this.cues_ = cues;
6430
- this.length_ = cues.length;
6431
-
6432
- var defineProp = function defineProp(index) {
6433
- if (!('' + index in this)) {
6434
- Object.defineProperty(this, '' + index, {
6435
- get: function get$$1() {
6436
- return this.cues_[index];
6437
- }
6438
- });
6439
- }
6440
- };
6441
-
6442
- if (oldLength < l) {
6443
- i = oldLength;
6444
-
6445
- for (; i < l; i++) {
6446
- defineProp.call(this, i);
6447
- }
6448
- }
6449
- };
6450
-
6451
- /**
6452
- * Get a `TextTrackCue` that is currently in the `TextTrackCueList` by id.
6453
- *
6454
- * @param {string} id
6455
- * The id of the cue that should be searched for.
6456
- *
6457
- * @return {TextTrackCueList~TextTrackCue|null}
6458
- * A single cue or null if none was found.
6459
- */
6460
-
6461
-
6462
- TextTrackCueList.prototype.getCueById = function getCueById(id) {
6463
- var result = null;
6464
-
6465
- for (var i = 0, l = this.length; i < l; i++) {
6466
- var cue = this[i];
6467
-
6468
- if (cue.id === id) {
6469
- result = cue;
6470
- break;
6471
- }
6472
- }
6473
-
6474
- return result;
6475
- };
6476
-
6477
- return TextTrackCueList;
6478
- }();
6479
-
6480
- /**
6481
- * @file track-kinds.js
6482
- */
6483
-
6484
- /**
6485
- * All possible `VideoTrackKind`s
6486
- *
6487
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-videotrack-kind
6488
- * @typedef VideoTrack~Kind
6489
- * @enum
6490
- */
6491
- var VideoTrackKind = {
6492
- alternative: 'alternative',
6493
- captions: 'captions',
6494
- main: 'main',
6495
- sign: 'sign',
6496
- subtitles: 'subtitles',
6497
- commentary: 'commentary'
6498
- };
6499
-
6500
- /**
6501
- * All possible `AudioTrackKind`s
6502
- *
6503
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-audiotrack-kind
6504
- * @typedef AudioTrack~Kind
6505
- * @enum
6506
- */
6507
- var AudioTrackKind = {
6508
- 'alternative': 'alternative',
6509
- 'descriptions': 'descriptions',
6510
- 'main': 'main',
6511
- 'main-desc': 'main-desc',
6512
- 'translation': 'translation',
6513
- 'commentary': 'commentary'
6514
- };
6515
-
6516
- /**
6517
- * All possible `TextTrackKind`s
6518
- *
6519
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-texttrack-kind
6520
- * @typedef TextTrack~Kind
6521
- * @enum
6522
- */
6523
- var TextTrackKind = {
6524
- subtitles: 'subtitles',
6525
- captions: 'captions',
6526
- descriptions: 'descriptions',
6527
- chapters: 'chapters',
6528
- metadata: 'metadata'
6529
- };
6530
-
6531
- /**
6532
- * All possible `TextTrackMode`s
6533
- *
6534
- * @see https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
6535
- * @typedef TextTrack~Mode
6536
- * @enum
6537
- */
6538
- var TextTrackMode = {
6539
- disabled: 'disabled',
6540
- hidden: 'hidden',
6541
- showing: 'showing'
6542
- };
6543
-
6544
- /**
6545
- * @file track.js
6546
- */
6547
-
6548
- /**
6549
- * A Track class that contains all of the common functionality for {@link AudioTrack},
6550
- * {@link VideoTrack}, and {@link TextTrack}.
6551
- *
6552
- * > Note: This class should not be used directly
6553
- *
6554
- * @see {@link https://html.spec.whatwg.org/multipage/embedded-content.html}
6555
- * @extends EventTarget
6556
- * @abstract
6557
- */
6558
-
6559
- var Track = function (_EventTarget) {
6560
- inherits(Track, _EventTarget);
6561
-
6562
- /**
6563
- * Create an instance of this class.
6564
- *
6565
- * @param {Object} [options={}]
6566
- * Object of option names and values
6567
- *
6568
- * @param {string} [options.kind='']
6569
- * A valid kind for the track type you are creating.
6570
- *
6571
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
6572
- * A unique id for this AudioTrack.
6573
- *
6574
- * @param {string} [options.label='']
6575
- * The menu label for this track.
6576
- *
6577
- * @param {string} [options.language='']
6578
- * A valid two character language code.
6579
- *
6580
- * @abstract
6581
- */
6582
- function Track() {
6583
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6584
- classCallCheck(this, Track);
6585
-
6586
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
6587
-
6588
- var trackProps = {
6589
- id: options.id || 'vjs_track_' + newGUID(),
6590
- kind: options.kind || '',
6591
- label: options.label || '',
6592
- language: options.language || ''
6593
- };
6594
-
6595
- /**
6596
- * @memberof Track
6597
- * @member {string} id
6598
- * The id of this track. Cannot be changed after creation.
6599
- * @instance
6600
- *
6601
- * @readonly
6602
- */
6603
-
6604
- /**
6605
- * @memberof Track
6606
- * @member {string} kind
6607
- * The kind of track that this is. Cannot be changed after creation.
6608
- * @instance
6609
- *
6610
- * @readonly
6611
- */
6612
-
6613
- /**
6614
- * @memberof Track
6615
- * @member {string} label
6616
- * The label of this track. Cannot be changed after creation.
6617
- * @instance
6618
- *
6619
- * @readonly
6620
- */
6621
-
6622
- /**
6623
- * @memberof Track
6624
- * @member {string} language
6625
- * The two letter language code for this track. Cannot be changed after
6626
- * creation.
6627
- * @instance
6628
- *
6629
- * @readonly
6630
- */
6631
-
6632
- var _loop = function _loop(key) {
6633
- Object.defineProperty(_this, key, {
6634
- get: function get$$1() {
6635
- return trackProps[key];
6636
- },
6637
- set: function set$$1() {}
6638
- });
6639
- };
6640
-
6641
- for (var key in trackProps) {
6642
- _loop(key);
6643
- }
6644
- return _this;
6645
- }
6646
-
6647
- return Track;
6648
- }(EventTarget);
6649
-
6650
- /**
6651
- * @file url.js
6652
- * @module url
6653
- */
6654
-
6655
- /**
6656
- * @typedef {Object} url:URLObject
6657
- *
6658
- * @property {string} protocol
6659
- * The protocol of the url that was parsed.
6660
- *
6661
- * @property {string} hostname
6662
- * The hostname of the url that was parsed.
6663
- *
6664
- * @property {string} port
6665
- * The port of the url that was parsed.
6666
- *
6667
- * @property {string} pathname
6668
- * The pathname of the url that was parsed.
6669
- *
6670
- * @property {string} search
6671
- * The search query of the url that was parsed.
6672
- *
6673
- * @property {string} hash
6674
- * The hash of the url that was parsed.
6675
- *
6676
- * @property {string} host
6677
- * The host of the url that was parsed.
6678
- */
6679
-
6680
- /**
6681
- * Resolve and parse the elements of a URL.
6682
- *
6683
- * @param {String} url
6684
- * The url to parse
6685
- *
6686
- * @return {url:URLObject}
6687
- * An object of url details
6688
- */
6689
- var parseUrl = function parseUrl(url) {
6690
- var props = ['protocol', 'hostname', 'port', 'pathname', 'search', 'hash', 'host'];
6691
-
6692
- // add the url to an anchor and let the browser parse the URL
6693
- var a = document_1.createElement('a');
6694
-
6695
- a.href = url;
6696
-
6697
- // IE8 (and 9?) Fix
6698
- // ie8 doesn't parse the URL correctly until the anchor is actually
6699
- // added to the body, and an innerHTML is needed to trigger the parsing
6700
- var addToBody = a.host === '' && a.protocol !== 'file:';
6701
- var div = void 0;
6702
-
6703
- if (addToBody) {
6704
- div = document_1.createElement('div');
6705
- div.innerHTML = '<a href="' + url + '"></a>';
6706
- a = div.firstChild;
6707
- // prevent the div from affecting layout
6708
- div.setAttribute('style', 'display:none; position:absolute;');
6709
- document_1.body.appendChild(div);
6710
- }
6711
-
6712
- // Copy the specific URL properties to a new object
6713
- // This is also needed for IE8 because the anchor loses its
6714
- // properties when it's removed from the dom
6715
- var details = {};
6716
-
6717
- for (var i = 0; i < props.length; i++) {
6718
- details[props[i]] = a[props[i]];
6719
- }
6720
-
6721
- // IE9 adds the port to the host property unlike everyone else. If
6722
- // a port identifier is added for standard ports, strip it.
6723
- if (details.protocol === 'http:') {
6724
- details.host = details.host.replace(/:80$/, '');
6725
- }
6726
-
6727
- if (details.protocol === 'https:') {
6728
- details.host = details.host.replace(/:443$/, '');
6729
- }
6730
-
6731
- if (!details.protocol) {
6732
- details.protocol = window_1.location.protocol;
6733
- }
6734
-
6735
- if (addToBody) {
6736
- document_1.body.removeChild(div);
6737
- }
6738
-
6739
- return details;
6740
- };
6741
-
6742
- /**
6743
- * Get absolute version of relative URL. Used to tell flash correct URL.
6744
- *
6745
- *
6746
- * @param {string} url
6747
- * URL to make absolute
6748
- *
6749
- * @return {string}
6750
- * Absolute URL
6751
- *
6752
- * @see http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
6753
- */
6754
- var getAbsoluteURL = function getAbsoluteURL(url) {
6755
- // Check if absolute URL
6756
- if (!url.match(/^https?:\/\//)) {
6757
- // Convert to absolute URL. Flash hosted off-site needs an absolute URL.
6758
- var div = document_1.createElement('div');
6759
-
6760
- div.innerHTML = '<a href="' + url + '">x</a>';
6761
- url = div.firstChild.href;
6762
- }
6763
-
6764
- return url;
6765
- };
6766
-
6767
- /**
6768
- * Returns the extension of the passed file name. It will return an empty string
6769
- * if passed an invalid path.
6770
- *
6771
- * @param {string} path
6772
- * The fileName path like '/path/to/file.mp4'
6773
- *
6774
- * @returns {string}
6775
- * The extension in lower case or an empty string if no
6776
- * extension could be found.
6777
- */
6778
- var getFileExtension = function getFileExtension(path) {
6779
- if (typeof path === 'string') {
6780
- var splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]+?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
6781
- var pathParts = splitPathRe.exec(path);
6782
-
6783
- if (pathParts) {
6784
- return pathParts.pop().toLowerCase();
6785
- }
6786
- }
6787
-
6788
- return '';
6789
- };
6790
-
6791
- /**
6792
- * Returns whether the url passed is a cross domain request or not.
6793
- *
6794
- * @param {string} url
6795
- * The url to check.
6796
- *
6797
- * @return {boolean}
6798
- * Whether it is a cross domain request or not.
6799
- */
6800
- var isCrossOrigin = function isCrossOrigin(url) {
6801
- var winLoc = window_1.location;
6802
- var urlInfo = parseUrl(url);
6803
-
6804
- // IE8 protocol relative urls will return ':' for protocol
6805
- var srcProtocol = urlInfo.protocol === ':' ? winLoc.protocol : urlInfo.protocol;
6806
-
6807
- // Check if url is for another domain/origin
6808
- // IE8 doesn't know location.origin, so we won't rely on it here
6809
- var crossOrigin = srcProtocol + urlInfo.host !== winLoc.protocol + winLoc.host;
6810
-
6811
- return crossOrigin;
6812
- };
6813
-
6814
- var Url = /*#__PURE__*/Object.freeze({
6815
- parseUrl: parseUrl,
6816
- getAbsoluteURL: getAbsoluteURL,
6817
- getFileExtension: getFileExtension,
6818
- isCrossOrigin: isCrossOrigin
6819
- });
6820
-
6821
- var isFunction_1 = isFunction;
6822
-
6823
- var toString$1 = Object.prototype.toString;
6824
-
6825
- function isFunction(fn) {
6826
- var string = toString$1.call(fn);
6827
- return string === '[object Function]' || typeof fn === 'function' && string !== '[object RegExp]' || typeof window !== 'undefined' && (
6828
- // IE8 and below
6829
- fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt);
6830
- }
6831
-
6832
- var isFunction$1 = /*#__PURE__*/Object.freeze({
6833
- default: isFunction_1,
6834
- __moduleExports: isFunction_1
6835
- });
6836
-
6837
- var trim_1 = createCommonjsModule(function (module, exports) {
6838
- exports = module.exports = trim;
6839
-
6840
- function trim(str) {
6841
- return str.replace(/^\s*|\s*$/g, '');
6842
- }
6843
-
6844
- exports.left = function (str) {
6845
- return str.replace(/^\s*/, '');
6846
- };
6847
-
6848
- exports.right = function (str) {
6849
- return str.replace(/\s*$/, '');
6850
- };
6851
- });
6852
- var trim_2 = trim_1.left;
6853
- var trim_3 = trim_1.right;
6854
-
6855
- var trim = /*#__PURE__*/Object.freeze({
6856
- default: trim_1,
6857
- __moduleExports: trim_1,
6858
- left: trim_2,
6859
- right: trim_3
6860
- });
6861
-
6862
- var isFunction$2 = ( isFunction$1 && isFunction_1 ) || isFunction$1;
6863
-
6864
- var forEach_1 = forEach;
6865
-
6866
- var toString$2 = Object.prototype.toString;
6867
- var hasOwnProperty = Object.prototype.hasOwnProperty;
6868
-
6869
- function forEach(list, iterator, context) {
6870
- if (!isFunction$2(iterator)) {
6871
- throw new TypeError('iterator must be a function');
6872
- }
6873
-
6874
- if (arguments.length < 3) {
6875
- context = this;
6876
- }
6877
-
6878
- if (toString$2.call(list) === '[object Array]') forEachArray(list, iterator, context);else if (typeof list === 'string') forEachString(list, iterator, context);else forEachObject(list, iterator, context);
6879
- }
6880
-
6881
- function forEachArray(array, iterator, context) {
6882
- for (var i = 0, len = array.length; i < len; i++) {
6883
- if (hasOwnProperty.call(array, i)) {
6884
- iterator.call(context, array[i], i, array);
6885
- }
6886
- }
6887
- }
6888
-
6889
- function forEachString(string, iterator, context) {
6890
- for (var i = 0, len = string.length; i < len; i++) {
6891
- // no such thing as a sparse string.
6892
- iterator.call(context, string.charAt(i), i, string);
6893
- }
6894
- }
6895
-
6896
- function forEachObject(object, iterator, context) {
6897
- for (var k in object) {
6898
- if (hasOwnProperty.call(object, k)) {
6899
- iterator.call(context, object[k], k, object);
6900
- }
6901
- }
6902
- }
6903
-
6904
- var forEach$1 = /*#__PURE__*/Object.freeze({
6905
- default: forEach_1,
6906
- __moduleExports: forEach_1
6907
- });
6908
-
6909
- var trim$1 = ( trim && trim_1 ) || trim;
6910
-
6911
- var forEach$2 = ( forEach$1 && forEach_1 ) || forEach$1;
6912
-
6913
- var isArray = function isArray(arg) {
6914
- return Object.prototype.toString.call(arg) === '[object Array]';
6915
- };
6916
-
6917
- var parseHeaders = function parseHeaders(headers) {
6918
- if (!headers) return {};
6919
-
6920
- var result = {};
6921
-
6922
- forEach$2(trim$1(headers).split('\n'), function (row) {
6923
- var index = row.indexOf(':'),
6924
- key = trim$1(row.slice(0, index)).toLowerCase(),
6925
- value = trim$1(row.slice(index + 1));
6926
-
6927
- if (typeof result[key] === 'undefined') {
6928
- result[key] = value;
6929
- } else if (isArray(result[key])) {
6930
- result[key].push(value);
6931
- } else {
6932
- result[key] = [result[key], value];
6933
- }
6934
- });
6935
-
6936
- return result;
6937
- };
6938
-
6939
- var parseHeaders$1 = /*#__PURE__*/Object.freeze({
6940
- default: parseHeaders,
6941
- __moduleExports: parseHeaders
6942
- });
6943
-
6944
- var immutable = extend;
6945
-
6946
- var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
6947
-
6948
- function extend() {
6949
- var target = {};
6950
-
6951
- for (var i = 0; i < arguments.length; i++) {
6952
- var source = arguments[i];
6953
-
6954
- for (var key in source) {
6955
- if (hasOwnProperty$1.call(source, key)) {
6956
- target[key] = source[key];
6957
- }
6958
- }
6959
- }
6960
-
6961
- return target;
6962
- }
6963
-
6964
- var immutable$1 = /*#__PURE__*/Object.freeze({
6965
- default: immutable,
6966
- __moduleExports: immutable
6967
- });
6968
-
6969
- var parseHeaders$2 = ( parseHeaders$1 && parseHeaders ) || parseHeaders$1;
6970
-
6971
- var xtend = ( immutable$1 && immutable ) || immutable$1;
6972
-
6973
- var xhr = createXHR;
6974
- createXHR.XMLHttpRequest = window_1.XMLHttpRequest || noop;
6975
- createXHR.XDomainRequest = "withCredentials" in new createXHR.XMLHttpRequest() ? createXHR.XMLHttpRequest : window_1.XDomainRequest;
6976
-
6977
- forEachArray$1(["get", "put", "post", "patch", "head", "delete"], function (method) {
6978
- createXHR[method === "delete" ? "del" : method] = function (uri, options, callback) {
6979
- options = initParams(uri, options, callback);
6980
- options.method = method.toUpperCase();
6981
- return _createXHR(options);
6982
- };
6983
- });
6984
-
6985
- function forEachArray$1(array, iterator) {
6986
- for (var i = 0; i < array.length; i++) {
6987
- iterator(array[i]);
6988
- }
6989
- }
6990
-
6991
- function isEmpty(obj) {
6992
- for (var i in obj) {
6993
- if (obj.hasOwnProperty(i)) return false;
6994
- }
6995
- return true;
6996
- }
6997
-
6998
- function initParams(uri, options, callback) {
6999
- var params = uri;
7000
-
7001
- if (isFunction$2(options)) {
7002
- callback = options;
7003
- if (typeof uri === "string") {
7004
- params = { uri: uri };
7005
- }
7006
- } else {
7007
- params = xtend(options, { uri: uri });
7008
- }
7009
-
7010
- params.callback = callback;
7011
- return params;
7012
- }
7013
-
7014
- function createXHR(uri, options, callback) {
7015
- options = initParams(uri, options, callback);
7016
- return _createXHR(options);
7017
- }
7018
-
7019
- function _createXHR(options) {
7020
- if (typeof options.callback === "undefined") {
7021
- throw new Error("callback argument missing");
7022
- }
7023
-
7024
- var called = false;
7025
- var callback = function cbOnce(err, response, body) {
7026
- if (!called) {
7027
- called = true;
7028
- options.callback(err, response, body);
7029
- }
7030
- };
7031
-
7032
- function readystatechange() {
7033
- if (xhr.readyState === 4) {
7034
- setTimeout(loadFunc, 0);
7035
- }
7036
- }
7037
-
7038
- function getBody() {
7039
- // Chrome with requestType=blob throws errors arround when even testing access to responseText
7040
- var body = undefined;
7041
-
7042
- if (xhr.response) {
7043
- body = xhr.response;
7044
- } else {
7045
- body = xhr.responseText || getXml(xhr);
7046
- }
7047
-
7048
- if (isJson) {
7049
- try {
7050
- body = JSON.parse(body);
7051
- } catch (e) {}
7052
- }
7053
-
7054
- return body;
7055
- }
7056
-
7057
- function errorFunc(evt) {
7058
- clearTimeout(timeoutTimer);
7059
- if (!(evt instanceof Error)) {
7060
- evt = new Error("" + (evt || "Unknown XMLHttpRequest Error"));
7061
- }
7062
- evt.statusCode = 0;
7063
- return callback(evt, failureResponse);
7064
- }
7065
-
7066
- // will load the data & process the response in a special response object
7067
- function loadFunc() {
7068
- if (aborted) return;
7069
- var status;
7070
- clearTimeout(timeoutTimer);
7071
- if (options.useXDR && xhr.status === undefined) {
7072
- //IE8 CORS GET successful response doesn't have a status field, but body is fine
7073
- status = 200;
7074
- } else {
7075
- status = xhr.status === 1223 ? 204 : xhr.status;
7076
- }
7077
- var response = failureResponse;
7078
- var err = null;
7079
-
7080
- if (status !== 0) {
7081
- response = {
7082
- body: getBody(),
7083
- statusCode: status,
7084
- method: method,
7085
- headers: {},
7086
- url: uri,
7087
- rawRequest: xhr
7088
- };
7089
- if (xhr.getAllResponseHeaders) {
7090
- //remember xhr can in fact be XDR for CORS in IE
7091
- response.headers = parseHeaders$2(xhr.getAllResponseHeaders());
7092
- }
7093
- } else {
7094
- err = new Error("Internal XMLHttpRequest Error");
7095
- }
7096
- return callback(err, response, response.body);
7097
- }
7098
-
7099
- var xhr = options.xhr || null;
7100
-
7101
- if (!xhr) {
7102
- if (options.cors || options.useXDR) {
7103
- xhr = new createXHR.XDomainRequest();
7104
- } else {
7105
- xhr = new createXHR.XMLHttpRequest();
7106
- }
7107
- }
7108
-
7109
- var key;
7110
- var aborted;
7111
- var uri = xhr.url = options.uri || options.url;
7112
- var method = xhr.method = options.method || "GET";
7113
- var body = options.body || options.data;
7114
- var headers = xhr.headers = options.headers || {};
7115
- var sync = !!options.sync;
7116
- var isJson = false;
7117
- var timeoutTimer;
7118
- var failureResponse = {
7119
- body: undefined,
7120
- headers: {},
7121
- statusCode: 0,
7122
- method: method,
7123
- url: uri,
7124
- rawRequest: xhr
7125
- };
7126
-
7127
- if ("json" in options && options.json !== false) {
7128
- isJson = true;
7129
- headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json"); //Don't override existing accept header declared by user
7130
- if (method !== "GET" && method !== "HEAD") {
7131
- headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json"); //Don't override existing accept header declared by user
7132
- body = JSON.stringify(options.json === true ? body : options.json);
7133
- }
7134
- }
7135
-
7136
- xhr.onreadystatechange = readystatechange;
7137
- xhr.onload = loadFunc;
7138
- xhr.onerror = errorFunc;
7139
- // IE9 must have onprogress be set to a unique function.
7140
- xhr.onprogress = function () {
7141
- // IE must die
7142
- };
7143
- xhr.onabort = function () {
7144
- aborted = true;
7145
- };
7146
- xhr.ontimeout = errorFunc;
7147
- xhr.open(method, uri, !sync, options.username, options.password);
7148
- //has to be after open
7149
- if (!sync) {
7150
- xhr.withCredentials = !!options.withCredentials;
7151
- }
7152
- // Cannot set timeout with sync request
7153
- // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
7154
- // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
7155
- if (!sync && options.timeout > 0) {
7156
- timeoutTimer = setTimeout(function () {
7157
- if (aborted) return;
7158
- aborted = true; //IE9 may still call readystatechange
7159
- xhr.abort("timeout");
7160
- var e = new Error("XMLHttpRequest timeout");
7161
- e.code = "ETIMEDOUT";
7162
- errorFunc(e);
7163
- }, options.timeout);
7164
- }
7165
-
7166
- if (xhr.setRequestHeader) {
7167
- for (key in headers) {
7168
- if (headers.hasOwnProperty(key)) {
7169
- xhr.setRequestHeader(key, headers[key]);
7170
- }
7171
- }
7172
- } else if (options.headers && !isEmpty(options.headers)) {
7173
- throw new Error("Headers cannot be set on an XDomainRequest object");
7174
- }
7175
-
7176
- if ("responseType" in options) {
7177
- xhr.responseType = options.responseType;
7178
- }
7179
-
7180
- if ("beforeSend" in options && typeof options.beforeSend === "function") {
7181
- options.beforeSend(xhr);
7182
- }
7183
-
7184
- // Microsoft Edge browser sends "undefined" when send is called with undefined value.
7185
- // XMLHttpRequest spec says to pass null as body to indicate no body
7186
- // See https://github.com/naugtur/xhr/issues/100.
7187
- xhr.send(body || null);
7188
-
7189
- return xhr;
7190
- }
7191
-
7192
- function getXml(xhr) {
7193
- if (xhr.responseType === "document") {
7194
- return xhr.responseXML;
7195
- }
7196
- var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror";
7197
- if (xhr.responseType === "" && !firefoxBugTakenEffect) {
7198
- return xhr.responseXML;
7199
- }
7200
-
7201
- return null;
7202
- }
7203
-
7204
- function noop() {}
7205
-
7206
- /**
7207
- * @file text-track.js
7208
- */
7209
-
7210
- /**
7211
- * Takes a webvtt file contents and parses it into cues
7212
- *
7213
- * @param {string} srcContent
7214
- * webVTT file contents
7215
- *
7216
- * @param {TextTrack} track
7217
- * TextTrack to add cues to. Cues come from the srcContent.
7218
- *
7219
- * @private
7220
- */
7221
- var parseCues = function parseCues(srcContent, track) {
7222
- var parser = new window_1.WebVTT.Parser(window_1, window_1.vttjs, window_1.WebVTT.StringDecoder());
7223
- var errors = [];
7224
-
7225
- parser.oncue = function (cue) {
7226
- track.addCue(cue);
7227
- };
7228
-
7229
- parser.onparsingerror = function (error) {
7230
- errors.push(error);
7231
- };
7232
-
7233
- parser.onflush = function () {
7234
- track.trigger({
7235
- type: 'loadeddata',
7236
- target: track
7237
- });
7238
- };
7239
-
7240
- parser.parse(srcContent);
7241
- if (errors.length > 0) {
7242
- if (window_1.console && window_1.console.groupCollapsed) {
7243
- window_1.console.groupCollapsed('Text Track parsing errors for ' + track.src);
7244
- }
7245
- errors.forEach(function (error) {
7246
- return log$1.error(error);
7247
- });
7248
- if (window_1.console && window_1.console.groupEnd) {
7249
- window_1.console.groupEnd();
7250
- }
7251
- }
7252
-
7253
- parser.flush();
7254
- };
7255
-
7256
- /**
7257
- * Load a `TextTrack` from a specified url.
7258
- *
7259
- * @param {string} src
7260
- * Url to load track from.
7261
- *
7262
- * @param {TextTrack} track
7263
- * Track to add cues to. Comes from the content at the end of `url`.
7264
- *
7265
- * @private
7266
- */
7267
- var loadTrack = function loadTrack(src, track) {
7268
- var opts = {
7269
- uri: src
7270
- };
7271
- var crossOrigin = isCrossOrigin(src);
7272
-
7273
- if (crossOrigin) {
7274
- opts.cors = crossOrigin;
7275
- }
7276
-
7277
- xhr(opts, bind(this, function (err, response, responseBody) {
7278
- if (err) {
7279
- return log$1.error(err, response);
7280
- }
7281
-
7282
- track.loaded_ = true;
7283
-
7284
- // Make sure that vttjs has loaded, otherwise, wait till it finished loading
7285
- // NOTE: this is only used for the alt/video.novtt.js build
7286
- if (typeof window_1.WebVTT !== 'function') {
7287
- if (track.tech_) {
7288
- var loadHandler = function loadHandler() {
7289
- return parseCues(responseBody, track);
7290
- };
7291
-
7292
- track.tech_.on('vttjsloaded', loadHandler);
7293
- track.tech_.on('vttjserror', function () {
7294
- log$1.error('vttjs failed to load, stopping trying to process ' + track.src);
7295
- track.tech_.off('vttjsloaded', loadHandler);
7296
- });
7297
- }
7298
- } else {
7299
- parseCues(responseBody, track);
7300
- }
7301
- }));
7302
- };
7303
-
7304
- /**
7305
- * A representation of a single `TextTrack`.
7306
- *
7307
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack}
7308
- * @extends Track
7309
- */
7310
-
7311
- var TextTrack = function (_Track) {
7312
- inherits(TextTrack, _Track);
7313
-
7314
- /**
7315
- * Create an instance of this class.
7316
- *
7317
- * @param {Object} options={}
7318
- * Object of option names and values
7319
- *
7320
- * @param {Tech} options.tech
7321
- * A reference to the tech that owns this TextTrack.
7322
- *
7323
- * @param {TextTrack~Kind} [options.kind='subtitles']
7324
- * A valid text track kind.
7325
- *
7326
- * @param {TextTrack~Mode} [options.mode='disabled']
7327
- * A valid text track mode.
7328
- *
7329
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
7330
- * A unique id for this TextTrack.
7331
- *
7332
- * @param {string} [options.label='']
7333
- * The menu label for this track.
7334
- *
7335
- * @param {string} [options.language='']
7336
- * A valid two character language code.
7337
- *
7338
- * @param {string} [options.srclang='']
7339
- * A valid two character language code. An alternative, but deprioritized
7340
- * version of `options.language`
7341
- *
7342
- * @param {string} [options.src]
7343
- * A url to TextTrack cues.
7344
- *
7345
- * @param {boolean} [options.default]
7346
- * If this track should default to on or off.
7347
- */
7348
- function TextTrack() {
7349
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7350
- classCallCheck(this, TextTrack);
7351
-
7352
- if (!options.tech) {
7353
- throw new Error('A tech was not provided.');
7354
- }
7355
-
7356
- var settings = mergeOptions(options, {
7357
- kind: TextTrackKind[options.kind] || 'subtitles',
7358
- language: options.language || options.srclang || ''
7359
- });
7360
- var mode = TextTrackMode[settings.mode] || 'disabled';
7361
- var default_ = settings.default;
7362
-
7363
- if (settings.kind === 'metadata' || settings.kind === 'chapters') {
7364
- mode = 'hidden';
7365
- }
7366
-
7367
- var _this = possibleConstructorReturn(this, _Track.call(this, settings));
7368
-
7369
- _this.tech_ = settings.tech;
7370
-
7371
- _this.cues_ = [];
7372
- _this.activeCues_ = [];
7373
-
7374
- var cues = new TextTrackCueList(_this.cues_);
7375
- var activeCues = new TextTrackCueList(_this.activeCues_);
7376
- var changed = false;
7377
- var timeupdateHandler = bind(_this, function () {
7378
-
7379
- // Accessing this.activeCues for the side-effects of updating itself
7380
- // due to it's nature as a getter function. Do not remove or cues will
7381
- // stop updating!
7382
- /* eslint-disable no-unused-expressions */
7383
- this.activeCues;
7384
- /* eslint-enable no-unused-expressions */
7385
- if (changed) {
7386
- this.trigger('cuechange');
7387
- changed = false;
7388
- }
7389
- });
7390
-
7391
- if (mode !== 'disabled') {
7392
- _this.tech_.ready(function () {
7393
- _this.tech_.on('timeupdate', timeupdateHandler);
7394
- }, true);
7395
- }
7396
-
7397
- Object.defineProperties(_this, {
7398
- /**
7399
- * @memberof TextTrack
7400
- * @member {boolean} default
7401
- * If this track was set to be on or off by default. Cannot be changed after
7402
- * creation.
7403
- * @instance
7404
- *
7405
- * @readonly
7406
- */
7407
- default: {
7408
- get: function get$$1() {
7409
- return default_;
7410
- },
7411
- set: function set$$1() {}
7412
- },
7413
-
7414
- /**
7415
- * @memberof TextTrack
7416
- * @member {string} mode
7417
- * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will
7418
- * not be set if setting to an invalid mode.
7419
- * @instance
7420
- *
7421
- * @fires TextTrack#modechange
7422
- */
7423
- mode: {
7424
- get: function get$$1() {
7425
- return mode;
7426
- },
7427
- set: function set$$1(newMode) {
7428
- var _this2 = this;
7429
-
7430
- if (!TextTrackMode[newMode]) {
7431
- return;
7432
- }
7433
- mode = newMode;
7434
- if (mode === 'showing') {
7435
-
7436
- this.tech_.ready(function () {
7437
- _this2.tech_.on('timeupdate', timeupdateHandler);
7438
- }, true);
7439
- }
7440
- /**
7441
- * An event that fires when mode changes on this track. This allows
7442
- * the TextTrackList that holds this track to act accordingly.
7443
- *
7444
- * > Note: This is not part of the spec!
7445
- *
7446
- * @event TextTrack#modechange
7447
- * @type {EventTarget~Event}
7448
- */
7449
- this.trigger('modechange');
7450
- }
7451
- },
7452
-
7453
- /**
7454
- * @memberof TextTrack
7455
- * @member {TextTrackCueList} cues
7456
- * The text track cue list for this TextTrack.
7457
- * @instance
7458
- */
7459
- cues: {
7460
- get: function get$$1() {
7461
- if (!this.loaded_) {
7462
- return null;
7463
- }
7464
-
7465
- return cues;
7466
- },
7467
- set: function set$$1() {}
7468
- },
7469
-
7470
- /**
7471
- * @memberof TextTrack
7472
- * @member {TextTrackCueList} activeCues
7473
- * The list text track cues that are currently active for this TextTrack.
7474
- * @instance
7475
- */
7476
- activeCues: {
7477
- get: function get$$1() {
7478
- if (!this.loaded_) {
7479
- return null;
7480
- }
7481
-
7482
- // nothing to do
7483
- if (this.cues.length === 0) {
7484
- return activeCues;
7485
- }
7486
-
7487
- var ct = this.tech_.currentTime();
7488
- var active = [];
7489
-
7490
- for (var i = 0, l = this.cues.length; i < l; i++) {
7491
- var cue = this.cues[i];
7492
-
7493
- if (cue.startTime <= ct && cue.endTime >= ct) {
7494
- active.push(cue);
7495
- } else if (cue.startTime === cue.endTime && cue.startTime <= ct && cue.startTime + 0.5 >= ct) {
7496
- active.push(cue);
7497
- }
7498
- }
7499
-
7500
- changed = false;
7501
-
7502
- if (active.length !== this.activeCues_.length) {
7503
- changed = true;
7504
- } else {
7505
- for (var _i = 0; _i < active.length; _i++) {
7506
- if (this.activeCues_.indexOf(active[_i]) === -1) {
7507
- changed = true;
7508
- }
7509
- }
7510
- }
7511
-
7512
- this.activeCues_ = active;
7513
- activeCues.setCues_(this.activeCues_);
7514
-
7515
- return activeCues;
7516
- },
7517
- set: function set$$1() {}
7518
- }
7519
- });
7520
-
7521
- if (settings.src) {
7522
- _this.src = settings.src;
7523
- loadTrack(settings.src, _this);
7524
- } else {
7525
- _this.loaded_ = true;
7526
- }
7527
- return _this;
7528
- }
7529
-
7530
- /**
7531
- * Add a cue to the internal list of cues.
7532
- *
7533
- * @param {TextTrack~Cue} cue
7534
- * The cue to add to our internal list
7535
- */
7536
-
7537
-
7538
- TextTrack.prototype.addCue = function addCue(originalCue) {
7539
- var cue = originalCue;
7540
-
7541
- if (window_1.vttjs && !(originalCue instanceof window_1.vttjs.VTTCue)) {
7542
- cue = new window_1.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
7543
-
7544
- for (var prop in originalCue) {
7545
- if (!(prop in cue)) {
7546
- cue[prop] = originalCue[prop];
7547
- }
7548
- }
7549
-
7550
- // make sure that `id` is copied over
7551
- cue.id = originalCue.id;
7552
- cue.originalCue_ = originalCue;
7553
- }
7554
-
7555
- var tracks = this.tech_.textTracks();
7556
-
7557
- for (var i = 0; i < tracks.length; i++) {
7558
- if (tracks[i] !== this) {
7559
- tracks[i].removeCue(cue);
7560
- }
7561
- }
7562
-
7563
- this.cues_.push(cue);
7564
- this.cues.setCues_(this.cues_);
7565
- };
7566
-
7567
- /**
7568
- * Remove a cue from our internal list
7569
- *
7570
- * @param {TextTrack~Cue} removeCue
7571
- * The cue to remove from our internal list
7572
- */
7573
-
7574
-
7575
- TextTrack.prototype.removeCue = function removeCue(_removeCue) {
7576
- var i = this.cues_.length;
7577
-
7578
- while (i--) {
7579
- var cue = this.cues_[i];
7580
-
7581
- if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) {
7582
- this.cues_.splice(i, 1);
7583
- this.cues.setCues_(this.cues_);
7584
- break;
7585
- }
7586
- }
7587
- };
7588
-
7589
- return TextTrack;
7590
- }(Track);
7591
-
7592
- /**
7593
- * cuechange - One or more cues in the track have become active or stopped being active.
7594
- */
7595
-
7596
-
7597
- TextTrack.prototype.allowedEvents_ = {
7598
- cuechange: 'cuechange'
7599
- };
7600
-
7601
- /**
7602
- * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList}
7603
- * only one `AudioTrack` in the list will be enabled at a time.
7604
- *
7605
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotrack}
7606
- * @extends Track
7607
- */
7608
-
7609
- var AudioTrack = function (_Track) {
7610
- inherits(AudioTrack, _Track);
7611
-
7612
- /**
7613
- * Create an instance of this class.
7614
- *
7615
- * @param {Object} [options={}]
7616
- * Object of option names and values
7617
- *
7618
- * @param {AudioTrack~Kind} [options.kind='']
7619
- * A valid audio track kind
7620
- *
7621
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
7622
- * A unique id for this AudioTrack.
7623
- *
7624
- * @param {string} [options.label='']
7625
- * The menu label for this track.
7626
- *
7627
- * @param {string} [options.language='']
7628
- * A valid two character language code.
7629
- *
7630
- * @param {boolean} [options.enabled]
7631
- * If this track is the one that is currently playing. If this track is part of
7632
- * an {@link AudioTrackList}, only one {@link AudioTrack} will be enabled.
7633
- */
7634
- function AudioTrack() {
7635
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7636
- classCallCheck(this, AudioTrack);
7637
-
7638
- var settings = mergeOptions(options, {
7639
- kind: AudioTrackKind[options.kind] || ''
7640
- });
7641
-
7642
- var _this = possibleConstructorReturn(this, _Track.call(this, settings));
7643
-
7644
- var enabled = false;
7645
-
7646
- /**
7647
- * @memberof AudioTrack
7648
- * @member {boolean} enabled
7649
- * If this `AudioTrack` is enabled or not. When setting this will
7650
- * fire {@link AudioTrack#enabledchange} if the state of enabled is changed.
7651
- * @instance
7652
- *
7653
- * @fires VideoTrack#selectedchange
7654
- */
7655
- Object.defineProperty(_this, 'enabled', {
7656
- get: function get$$1() {
7657
- return enabled;
7658
- },
7659
- set: function set$$1(newEnabled) {
7660
- // an invalid or unchanged value
7661
- if (typeof newEnabled !== 'boolean' || newEnabled === enabled) {
7662
- return;
7663
- }
7664
- enabled = newEnabled;
7665
-
7666
- /**
7667
- * An event that fires when enabled changes on this track. This allows
7668
- * the AudioTrackList that holds this track to act accordingly.
7669
- *
7670
- * > Note: This is not part of the spec! Native tracks will do
7671
- * this internally without an event.
7672
- *
7673
- * @event AudioTrack#enabledchange
7674
- * @type {EventTarget~Event}
7675
- */
7676
- this.trigger('enabledchange');
7677
- }
7678
- });
7679
-
7680
- // if the user sets this track to selected then
7681
- // set selected to that true value otherwise
7682
- // we keep it false
7683
- if (settings.enabled) {
7684
- _this.enabled = settings.enabled;
7685
- }
7686
- _this.loaded_ = true;
7687
- return _this;
7688
- }
7689
-
7690
- return AudioTrack;
7691
- }(Track);
7692
-
7693
- /**
7694
- * A representation of a single `VideoTrack`.
7695
- *
7696
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#videotrack}
7697
- * @extends Track
7698
- */
7699
-
7700
- var VideoTrack = function (_Track) {
7701
- inherits(VideoTrack, _Track);
7702
-
7703
- /**
7704
- * Create an instance of this class.
7705
- *
7706
- * @param {Object} [options={}]
7707
- * Object of option names and values
7708
- *
7709
- * @param {string} [options.kind='']
7710
- * A valid {@link VideoTrack~Kind}
7711
- *
7712
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
7713
- * A unique id for this AudioTrack.
7714
- *
7715
- * @param {string} [options.label='']
7716
- * The menu label for this track.
7717
- *
7718
- * @param {string} [options.language='']
7719
- * A valid two character language code.
7720
- *
7721
- * @param {boolean} [options.selected]
7722
- * If this track is the one that is currently playing.
7723
- */
7724
- function VideoTrack() {
7725
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7726
- classCallCheck(this, VideoTrack);
7727
-
7728
- var settings = mergeOptions(options, {
7729
- kind: VideoTrackKind[options.kind] || ''
7730
- });
7731
-
7732
- var _this = possibleConstructorReturn(this, _Track.call(this, settings));
7733
-
7734
- var selected = false;
7735
-
7736
- /**
7737
- * @memberof VideoTrack
7738
- * @member {boolean} selected
7739
- * If this `VideoTrack` is selected or not. When setting this will
7740
- * fire {@link VideoTrack#selectedchange} if the state of selected changed.
7741
- * @instance
7742
- *
7743
- * @fires VideoTrack#selectedchange
7744
- */
7745
- Object.defineProperty(_this, 'selected', {
7746
- get: function get$$1() {
7747
- return selected;
7748
- },
7749
- set: function set$$1(newSelected) {
7750
- // an invalid or unchanged value
7751
- if (typeof newSelected !== 'boolean' || newSelected === selected) {
7752
- return;
7753
- }
7754
- selected = newSelected;
7755
-
7756
- /**
7757
- * An event that fires when selected changes on this track. This allows
7758
- * the VideoTrackList that holds this track to act accordingly.
7759
- *
7760
- * > Note: This is not part of the spec! Native tracks will do
7761
- * this internally without an event.
7762
- *
7763
- * @event VideoTrack#selectedchange
7764
- * @type {EventTarget~Event}
7765
- */
7766
- this.trigger('selectedchange');
7767
- }
7768
- });
7769
-
7770
- // if the user sets this track to selected then
7771
- // set selected to that true value otherwise
7772
- // we keep it false
7773
- if (settings.selected) {
7774
- _this.selected = settings.selected;
7775
- }
7776
- return _this;
7777
- }
7778
-
7779
- return VideoTrack;
7780
- }(Track);
7781
-
7782
- /**
7783
- * @file html-track-element.js
7784
- */
7785
-
7786
- /**
7787
- * @memberof HTMLTrackElement
7788
- * @typedef {HTMLTrackElement~ReadyState}
7789
- * @enum {number}
7790
- */
7791
- var NONE = 0;
7792
- var LOADING = 1;
7793
- var LOADED = 2;
7794
- var ERROR = 3;
7795
-
7796
- /**
7797
- * A single track represented in the DOM.
7798
- *
7799
- * @see [Spec]{@link https://html.spec.whatwg.org/multipage/embedded-content.html#htmltrackelement}
7800
- * @extends EventTarget
7801
- */
7802
-
7803
- var HTMLTrackElement = function (_EventTarget) {
7804
- inherits(HTMLTrackElement, _EventTarget);
7805
-
7806
- /**
7807
- * Create an instance of this class.
7808
- *
7809
- * @param {Object} options={}
7810
- * Object of option names and values
7811
- *
7812
- * @param {Tech} options.tech
7813
- * A reference to the tech that owns this HTMLTrackElement.
7814
- *
7815
- * @param {TextTrack~Kind} [options.kind='subtitles']
7816
- * A valid text track kind.
7817
- *
7818
- * @param {TextTrack~Mode} [options.mode='disabled']
7819
- * A valid text track mode.
7820
- *
7821
- * @param {string} [options.id='vjs_track_' + Guid.newGUID()]
7822
- * A unique id for this TextTrack.
7823
- *
7824
- * @param {string} [options.label='']
7825
- * The menu label for this track.
7826
- *
7827
- * @param {string} [options.language='']
7828
- * A valid two character language code.
7829
- *
7830
- * @param {string} [options.srclang='']
7831
- * A valid two character language code. An alternative, but deprioritized
7832
- * vesion of `options.language`
7833
- *
7834
- * @param {string} [options.src]
7835
- * A url to TextTrack cues.
7836
- *
7837
- * @param {boolean} [options.default]
7838
- * If this track should default to on or off.
7839
- */
7840
- function HTMLTrackElement() {
7841
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7842
- classCallCheck(this, HTMLTrackElement);
7843
-
7844
- var _this = possibleConstructorReturn(this, _EventTarget.call(this));
7845
-
7846
- var readyState = void 0;
7847
-
7848
- var track = new TextTrack(options);
7849
-
7850
- _this.kind = track.kind;
7851
- _this.src = track.src;
7852
- _this.srclang = track.language;
7853
- _this.label = track.label;
7854
- _this.default = track.default;
7855
-
7856
- Object.defineProperties(_this, {
7857
-
7858
- /**
7859
- * @memberof HTMLTrackElement
7860
- * @member {HTMLTrackElement~ReadyState} readyState
7861
- * The current ready state of the track element.
7862
- * @instance
7863
- */
7864
- readyState: {
7865
- get: function get$$1() {
7866
- return readyState;
7867
- }
7868
- },
7869
-
7870
- /**
7871
- * @memberof HTMLTrackElement
7872
- * @member {TextTrack} track
7873
- * The underlying TextTrack object.
7874
- * @instance
7875
- *
7876
- */
7877
- track: {
7878
- get: function get$$1() {
7879
- return track;
7880
- }
7881
- }
7882
- });
7883
-
7884
- readyState = NONE;
7885
-
7886
- /**
7887
- * @listens TextTrack#loadeddata
7888
- * @fires HTMLTrackElement#load
7889
- */
7890
- track.addEventListener('loadeddata', function () {
7891
- readyState = LOADED;
7892
-
7893
- _this.trigger({
7894
- type: 'load',
7895
- target: _this
7896
- });
7897
- });
7898
- return _this;
7899
- }
7900
-
7901
- return HTMLTrackElement;
7902
- }(EventTarget);
7903
-
7904
- HTMLTrackElement.prototype.allowedEvents_ = {
7905
- load: 'load'
7906
- };
7907
-
7908
- HTMLTrackElement.NONE = NONE;
7909
- HTMLTrackElement.LOADING = LOADING;
7910
- HTMLTrackElement.LOADED = LOADED;
7911
- HTMLTrackElement.ERROR = ERROR;
7912
-
7913
- /*
7914
- * This file contains all track properties that are used in
7915
- * player.js, tech.js, html5.js and possibly other techs in the future.
7916
- */
7917
-
7918
- var NORMAL = {
7919
- audio: {
7920
- ListClass: AudioTrackList,
7921
- TrackClass: AudioTrack,
7922
- capitalName: 'Audio'
7923
- },
7924
- video: {
7925
- ListClass: VideoTrackList,
7926
- TrackClass: VideoTrack,
7927
- capitalName: 'Video'
7928
- },
7929
- text: {
7930
- ListClass: TextTrackList,
7931
- TrackClass: TextTrack,
7932
- capitalName: 'Text'
7933
- }
7934
- };
7935
-
7936
- Object.keys(NORMAL).forEach(function (type) {
7937
- NORMAL[type].getterName = type + 'Tracks';
7938
- NORMAL[type].privateName = type + 'Tracks_';
7939
- });
7940
-
7941
- var REMOTE = {
7942
- remoteText: {
7943
- ListClass: TextTrackList,
7944
- TrackClass: TextTrack,
7945
- capitalName: 'RemoteText',
7946
- getterName: 'remoteTextTracks',
7947
- privateName: 'remoteTextTracks_'
7948
- },
7949
- remoteTextEl: {
7950
- ListClass: HtmlTrackElementList,
7951
- TrackClass: HTMLTrackElement,
7952
- capitalName: 'RemoteTextTrackEls',
7953
- getterName: 'remoteTextTrackEls',
7954
- privateName: 'remoteTextTrackEls_'
7955
- }
7956
- };
7957
-
7958
- var ALL = mergeOptions(NORMAL, REMOTE);
7959
-
7960
- REMOTE.names = Object.keys(REMOTE);
7961
- NORMAL.names = Object.keys(NORMAL);
7962
- ALL.names = [].concat(REMOTE.names).concat(NORMAL.names);
7963
-
7964
- /**
7965
- * Copyright 2013 vtt.js Contributors
7966
- *
7967
- * Licensed under the Apache License, Version 2.0 (the "License");
7968
- * you may not use this file except in compliance with the License.
7969
- * You may obtain a copy of the License at
7970
- *
7971
- * http://www.apache.org/licenses/LICENSE-2.0
7972
- *
7973
- * Unless required by applicable law or agreed to in writing, software
7974
- * distributed under the License is distributed on an "AS IS" BASIS,
7975
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7976
- * See the License for the specific language governing permissions and
7977
- * limitations under the License.
7978
- */
7979
-
7980
- /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
7981
- /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
7982
- var _objCreate = Object.create || function () {
7983
- function F() {}
7984
- return function (o) {
7985
- if (arguments.length !== 1) {
7986
- throw new Error('Object.create shim only accepts one parameter.');
7987
- }
7988
- F.prototype = o;
7989
- return new F();
7990
- };
7991
- }();
7992
-
7993
- // Creates a new ParserError object from an errorData object. The errorData
7994
- // object should have default code and message properties. The default message
7995
- // property can be overriden by passing in a message parameter.
7996
- // See ParsingError.Errors below for acceptable errors.
7997
- function ParsingError(errorData, message) {
7998
- this.name = "ParsingError";
7999
- this.code = errorData.code;
8000
- this.message = message || errorData.message;
8001
- }
8002
- ParsingError.prototype = _objCreate(Error.prototype);
8003
- ParsingError.prototype.constructor = ParsingError;
8004
-
8005
- // ParsingError metadata for acceptable ParsingErrors.
8006
- ParsingError.Errors = {
8007
- BadSignature: {
8008
- code: 0,
8009
- message: "Malformed WebVTT signature."
8010
- },
8011
- BadTimeStamp: {
8012
- code: 1,
8013
- message: "Malformed time stamp."
8014
- }
8015
- };
8016
-
8017
- // Try to parse input as a time stamp.
8018
- function parseTimeStamp(input) {
8019
-
8020
- function computeSeconds(h, m, s, f) {
8021
- return (h | 0) * 3600 + (m | 0) * 60 + (s | 0) + (f | 0) / 1000;
8022
- }
8023
-
8024
- var m = input.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);
8025
- if (!m) {
8026
- return null;
8027
- }
8028
-
8029
- if (m[3]) {
8030
- // Timestamp takes the form of [hours]:[minutes]:[seconds].[milliseconds]
8031
- return computeSeconds(m[1], m[2], m[3].replace(":", ""), m[4]);
8032
- } else if (m[1] > 59) {
8033
- // Timestamp takes the form of [hours]:[minutes].[milliseconds]
8034
- // First position is hours as it's over 59.
8035
- return computeSeconds(m[1], m[2], 0, m[4]);
8036
- } else {
8037
- // Timestamp takes the form of [minutes]:[seconds].[milliseconds]
8038
- return computeSeconds(0, m[1], m[2], m[4]);
8039
- }
8040
- }
8041
-
8042
- // A settings object holds key/value pairs and will ignore anything but the first
8043
- // assignment to a specific key.
8044
- function Settings() {
8045
- this.values = _objCreate(null);
8046
- }
8047
-
8048
- Settings.prototype = {
8049
- // Only accept the first assignment to any key.
8050
- set: function set(k, v) {
8051
- if (!this.get(k) && v !== "") {
8052
- this.values[k] = v;
8053
- }
8054
- },
8055
- // Return the value for a key, or a default value.
8056
- // If 'defaultKey' is passed then 'dflt' is assumed to be an object with
8057
- // a number of possible default values as properties where 'defaultKey' is
8058
- // the key of the property that will be chosen; otherwise it's assumed to be
8059
- // a single value.
8060
- get: function get(k, dflt, defaultKey) {
8061
- if (defaultKey) {
8062
- return this.has(k) ? this.values[k] : dflt[defaultKey];
8063
- }
8064
- return this.has(k) ? this.values[k] : dflt;
8065
- },
8066
- // Check whether we have a value for a key.
8067
- has: function has(k) {
8068
- return k in this.values;
8069
- },
8070
- // Accept a setting if its one of the given alternatives.
8071
- alt: function alt(k, v, a) {
8072
- for (var n = 0; n < a.length; ++n) {
8073
- if (v === a[n]) {
8074
- this.set(k, v);
8075
- break;
8076
- }
8077
- }
8078
- },
8079
- // Accept a setting if its a valid (signed) integer.
8080
- integer: function integer(k, v) {
8081
- if (/^-?\d+$/.test(v)) {
8082
- // integer
8083
- this.set(k, parseInt(v, 10));
8084
- }
8085
- },
8086
- // Accept a setting if its a valid percentage.
8087
- percent: function percent(k, v) {
8088
- var m;
8089
- if (m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/)) {
8090
- v = parseFloat(v);
8091
- if (v >= 0 && v <= 100) {
8092
- this.set(k, v);
8093
- return true;
8094
- }
8095
- }
8096
- return false;
8097
- }
8098
- };
8099
-
8100
- // Helper function to parse input into groups separated by 'groupDelim', and
8101
- // interprete each group as a key/value pair separated by 'keyValueDelim'.
8102
- function parseOptions(input, callback, keyValueDelim, groupDelim) {
8103
- var groups = groupDelim ? input.split(groupDelim) : [input];
8104
- for (var i in groups) {
8105
- if (typeof groups[i] !== "string") {
8106
- continue;
8107
- }
8108
- var kv = groups[i].split(keyValueDelim);
8109
- if (kv.length !== 2) {
8110
- continue;
8111
- }
8112
- var k = kv[0];
8113
- var v = kv[1];
8114
- callback(k, v);
8115
- }
8116
- }
8117
-
8118
- function parseCue(input, cue, regionList) {
8119
- // Remember the original input if we need to throw an error.
8120
- var oInput = input;
8121
- // 4.1 WebVTT timestamp
8122
- function consumeTimeStamp() {
8123
- var ts = parseTimeStamp(input);
8124
- if (ts === null) {
8125
- throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed timestamp: " + oInput);
8126
- }
8127
- // Remove time stamp from input.
8128
- input = input.replace(/^[^\sa-zA-Z-]+/, "");
8129
- return ts;
8130
- }
8131
-
8132
- // 4.4.2 WebVTT cue settings
8133
- function consumeCueSettings(input, cue) {
8134
- var settings = new Settings();
8135
-
8136
- parseOptions(input, function (k, v) {
8137
- switch (k) {
8138
- case "region":
8139
- // Find the last region we parsed with the same region id.
8140
- for (var i = regionList.length - 1; i >= 0; i--) {
8141
- if (regionList[i].id === v) {
8142
- settings.set(k, regionList[i].region);
8143
- break;
8144
- }
8145
- }
8146
- break;
8147
- case "vertical":
8148
- settings.alt(k, v, ["rl", "lr"]);
8149
- break;
8150
- case "line":
8151
- var vals = v.split(","),
8152
- vals0 = vals[0];
8153
- settings.integer(k, vals0);
8154
- settings.percent(k, vals0) ? settings.set("snapToLines", false) : null;
8155
- settings.alt(k, vals0, ["auto"]);
8156
- if (vals.length === 2) {
8157
- settings.alt("lineAlign", vals[1], ["start", "middle", "end"]);
8158
- }
8159
- break;
8160
- case "position":
8161
- vals = v.split(",");
8162
- settings.percent(k, vals[0]);
8163
- if (vals.length === 2) {
8164
- settings.alt("positionAlign", vals[1], ["start", "middle", "end"]);
8165
- }
8166
- break;
8167
- case "size":
8168
- settings.percent(k, v);
8169
- break;
8170
- case "align":
8171
- settings.alt(k, v, ["start", "middle", "end", "left", "right"]);
8172
- break;
8173
- }
8174
- }, /:/, /\s/);
8175
-
8176
- // Apply default values for any missing fields.
8177
- cue.region = settings.get("region", null);
8178
- cue.vertical = settings.get("vertical", "");
8179
- cue.line = settings.get("line", "auto");
8180
- cue.lineAlign = settings.get("lineAlign", "start");
8181
- cue.snapToLines = settings.get("snapToLines", true);
8182
- cue.size = settings.get("size", 100);
8183
- cue.align = settings.get("align", "middle");
8184
- cue.position = settings.get("position", {
8185
- start: 0,
8186
- left: 0,
8187
- middle: 50,
8188
- end: 100,
8189
- right: 100
8190
- }, cue.align);
8191
- cue.positionAlign = settings.get("positionAlign", {
8192
- start: "start",
8193
- left: "start",
8194
- middle: "middle",
8195
- end: "end",
8196
- right: "end"
8197
- }, cue.align);
8198
- }
8199
-
8200
- function skipWhitespace() {
8201
- input = input.replace(/^\s+/, "");
8202
- }
8203
-
8204
- // 4.1 WebVTT cue timings.
8205
- skipWhitespace();
8206
- cue.startTime = consumeTimeStamp(); // (1) collect cue start time
8207
- skipWhitespace();
8208
- if (input.substr(0, 3) !== "-->") {
8209
- // (3) next characters must match "-->"
8210
- throw new ParsingError(ParsingError.Errors.BadTimeStamp, "Malformed time stamp (time stamps must be separated by '-->'): " + oInput);
8211
- }
8212
- input = input.substr(3);
8213
- skipWhitespace();
8214
- cue.endTime = consumeTimeStamp(); // (5) collect cue end time
8215
-
8216
- // 4.1 WebVTT cue settings list.
8217
- skipWhitespace();
8218
- consumeCueSettings(input, cue);
8219
- }
8220
-
8221
- var ESCAPE = {
8222
- "&amp;": "&",
8223
- "&lt;": "<",
8224
- "&gt;": ">",
8225
- "&lrm;": "\u200E",
8226
- "&rlm;": "\u200F",
8227
- "&nbsp;": "\xA0"
8228
- };
8229
-
8230
- var TAG_NAME = {
8231
- c: "span",
8232
- i: "i",
8233
- b: "b",
8234
- u: "u",
8235
- ruby: "ruby",
8236
- rt: "rt",
8237
- v: "span",
8238
- lang: "span"
8239
- };
8240
-
8241
- var TAG_ANNOTATION = {
8242
- v: "title",
8243
- lang: "lang"
8244
- };
8245
-
8246
- var NEEDS_PARENT = {
8247
- rt: "ruby"
8248
- };
8249
-
8250
- // Parse content into a document fragment.
8251
- function parseContent(window, input) {
8252
- function nextToken() {
8253
- // Check for end-of-string.
8254
- if (!input) {
8255
- return null;
8256
- }
8257
-
8258
- // Consume 'n' characters from the input.
8259
- function consume(result) {
8260
- input = input.substr(result.length);
8261
- return result;
8262
- }
8263
-
8264
- var m = input.match(/^([^<]*)(<[^>]*>?)?/);
8265
- // If there is some text before the next tag, return it, otherwise return
8266
- // the tag.
8267
- return consume(m[1] ? m[1] : m[2]);
8268
- }
8269
-
8270
- // Unescape a string 's'.
8271
- function unescape1(e) {
8272
- return ESCAPE[e];
8273
- }
8274
- function unescape(s) {
8275
- while (m = s.match(/&(amp|lt|gt|lrm|rlm|nbsp);/)) {
8276
- s = s.replace(m[0], unescape1);
8277
- }
8278
- return s;
8279
- }
8280
-
8281
- function shouldAdd(current, element) {
8282
- return !NEEDS_PARENT[element.localName] || NEEDS_PARENT[element.localName] === current.localName;
8283
- }
8284
-
8285
- // Create an element for this tag.
8286
- function createElement(type, annotation) {
8287
- var tagName = TAG_NAME[type];
8288
- if (!tagName) {
8289
- return null;
8290
- }
8291
- var element = window.document.createElement(tagName);
8292
- element.localName = tagName;
8293
- var name = TAG_ANNOTATION[type];
8294
- if (name && annotation) {
8295
- element[name] = annotation.trim();
8296
- }
8297
- return element;
8298
- }
8299
-
8300
- var rootDiv = window.document.createElement("div"),
8301
- current = rootDiv,
8302
- t,
8303
- tagStack = [];
8304
-
8305
- while ((t = nextToken()) !== null) {
8306
- if (t[0] === '<') {
8307
- if (t[1] === "/") {
8308
- // If the closing tag matches, move back up to the parent node.
8309
- if (tagStack.length && tagStack[tagStack.length - 1] === t.substr(2).replace(">", "")) {
8310
- tagStack.pop();
8311
- current = current.parentNode;
8312
- }
8313
- // Otherwise just ignore the end tag.
8314
- continue;
8315
- }
8316
- var ts = parseTimeStamp(t.substr(1, t.length - 2));
8317
- var node;
8318
- if (ts) {
8319
- // Timestamps are lead nodes as well.
8320
- node = window.document.createProcessingInstruction("timestamp", ts);
8321
- current.appendChild(node);
8322
- continue;
8323
- }
8324
- var m = t.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/);
8325
- // If we can't parse the tag, skip to the next tag.
8326
- if (!m) {
8327
- continue;
8328
- }
8329
- // Try to construct an element, and ignore the tag if we couldn't.
8330
- node = createElement(m[1], m[3]);
8331
- if (!node) {
8332
- continue;
8333
- }
8334
- // Determine if the tag should be added based on the context of where it
8335
- // is placed in the cuetext.
8336
- if (!shouldAdd(current, node)) {
8337
- continue;
8338
- }
8339
- // Set the class list (as a list of classes, separated by space).
8340
- if (m[2]) {
8341
- node.className = m[2].substr(1).replace('.', ' ');
8342
- }
8343
- // Append the node to the current node, and enter the scope of the new
8344
- // node.
8345
- tagStack.push(m[1]);
8346
- current.appendChild(node);
8347
- current = node;
8348
- continue;
8349
- }
8350
-
8351
- // Text nodes are leaf nodes.
8352
- current.appendChild(window.document.createTextNode(unescape(t)));
8353
- }
8354
-
8355
- return rootDiv;
8356
- }
8357
-
8358
- // This is a list of all the Unicode characters that have a strong
8359
- // right-to-left category. What this means is that these characters are
8360
- // written right-to-left for sure. It was generated by pulling all the strong
8361
- // right-to-left characters out of the Unicode data table. That table can
8362
- // found at: http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
8363
- var strongRTLRanges = [[0x5be, 0x5be], [0x5c0, 0x5c0], [0x5c3, 0x5c3], [0x5c6, 0x5c6], [0x5d0, 0x5ea], [0x5f0, 0x5f4], [0x608, 0x608], [0x60b, 0x60b], [0x60d, 0x60d], [0x61b, 0x61b], [0x61e, 0x64a], [0x66d, 0x66f], [0x671, 0x6d5], [0x6e5, 0x6e6], [0x6ee, 0x6ef], [0x6fa, 0x70d], [0x70f, 0x710], [0x712, 0x72f], [0x74d, 0x7a5], [0x7b1, 0x7b1], [0x7c0, 0x7ea], [0x7f4, 0x7f5], [0x7fa, 0x7fa], [0x800, 0x815], [0x81a, 0x81a], [0x824, 0x824], [0x828, 0x828], [0x830, 0x83e], [0x840, 0x858], [0x85e, 0x85e], [0x8a0, 0x8a0], [0x8a2, 0x8ac], [0x200f, 0x200f], [0xfb1d, 0xfb1d], [0xfb1f, 0xfb28], [0xfb2a, 0xfb36], [0xfb38, 0xfb3c], [0xfb3e, 0xfb3e], [0xfb40, 0xfb41], [0xfb43, 0xfb44], [0xfb46, 0xfbc1], [0xfbd3, 0xfd3d], [0xfd50, 0xfd8f], [0xfd92, 0xfdc7], [0xfdf0, 0xfdfc], [0xfe70, 0xfe74], [0xfe76, 0xfefc], [0x10800, 0x10805], [0x10808, 0x10808], [0x1080a, 0x10835], [0x10837, 0x10838], [0x1083c, 0x1083c], [0x1083f, 0x10855], [0x10857, 0x1085f], [0x10900, 0x1091b], [0x10920, 0x10939], [0x1093f, 0x1093f], [0x10980, 0x109b7], [0x109be, 0x109bf], [0x10a00, 0x10a00], [0x10a10, 0x10a13], [0x10a15, 0x10a17], [0x10a19, 0x10a33], [0x10a40, 0x10a47], [0x10a50, 0x10a58], [0x10a60, 0x10a7f], [0x10b00, 0x10b35], [0x10b40, 0x10b55], [0x10b58, 0x10b72], [0x10b78, 0x10b7f], [0x10c00, 0x10c48], [0x1ee00, 0x1ee03], [0x1ee05, 0x1ee1f], [0x1ee21, 0x1ee22], [0x1ee24, 0x1ee24], [0x1ee27, 0x1ee27], [0x1ee29, 0x1ee32], [0x1ee34, 0x1ee37], [0x1ee39, 0x1ee39], [0x1ee3b, 0x1ee3b], [0x1ee42, 0x1ee42], [0x1ee47, 0x1ee47], [0x1ee49, 0x1ee49], [0x1ee4b, 0x1ee4b], [0x1ee4d, 0x1ee4f], [0x1ee51, 0x1ee52], [0x1ee54, 0x1ee54], [0x1ee57, 0x1ee57], [0x1ee59, 0x1ee59], [0x1ee5b, 0x1ee5b], [0x1ee5d, 0x1ee5d], [0x1ee5f, 0x1ee5f], [0x1ee61, 0x1ee62], [0x1ee64, 0x1ee64], [0x1ee67, 0x1ee6a], [0x1ee6c, 0x1ee72], [0x1ee74, 0x1ee77], [0x1ee79, 0x1ee7c], [0x1ee7e, 0x1ee7e], [0x1ee80, 0x1ee89], [0x1ee8b, 0x1ee9b], [0x1eea1, 0x1eea3], [0x1eea5, 0x1eea9], [0x1eeab, 0x1eebb], [0x10fffd, 0x10fffd]];
8364
-
8365
- function isStrongRTLChar(charCode) {
8366
- for (var i = 0; i < strongRTLRanges.length; i++) {
8367
- var currentRange = strongRTLRanges[i];
8368
- if (charCode >= currentRange[0] && charCode <= currentRange[1]) {
8369
- return true;
8370
- }
8371
- }
8372
-
8373
- return false;
8374
- }
8375
-
8376
- function determineBidi(cueDiv) {
8377
- var nodeStack = [],
8378
- text = "",
8379
- charCode;
8380
-
8381
- if (!cueDiv || !cueDiv.childNodes) {
8382
- return "ltr";
8383
- }
8384
-
8385
- function pushNodes(nodeStack, node) {
8386
- for (var i = node.childNodes.length - 1; i >= 0; i--) {
8387
- nodeStack.push(node.childNodes[i]);
8388
- }
8389
- }
8390
-
8391
- function nextTextNode(nodeStack) {
8392
- if (!nodeStack || !nodeStack.length) {
8393
- return null;
8394
- }
8395
-
8396
- var node = nodeStack.pop(),
8397
- text = node.textContent || node.innerText;
8398
- if (text) {
8399
- // TODO: This should match all unicode type B characters (paragraph
8400
- // separator characters). See issue #115.
8401
- var m = text.match(/^.*(\n|\r)/);
8402
- if (m) {
8403
- nodeStack.length = 0;
8404
- return m[0];
8405
- }
8406
- return text;
8407
- }
8408
- if (node.tagName === "ruby") {
8409
- return nextTextNode(nodeStack);
8410
- }
8411
- if (node.childNodes) {
8412
- pushNodes(nodeStack, node);
8413
- return nextTextNode(nodeStack);
8414
- }
8415
- }
8416
-
8417
- pushNodes(nodeStack, cueDiv);
8418
- while (text = nextTextNode(nodeStack)) {
8419
- for (var i = 0; i < text.length; i++) {
8420
- charCode = text.charCodeAt(i);
8421
- if (isStrongRTLChar(charCode)) {
8422
- return "rtl";
8423
- }
8424
- }
8425
- }
8426
- return "ltr";
8427
- }
8428
-
8429
- function computeLinePos(cue) {
8430
- if (typeof cue.line === "number" && (cue.snapToLines || cue.line >= 0 && cue.line <= 100)) {
8431
- return cue.line;
8432
- }
8433
- if (!cue.track || !cue.track.textTrackList || !cue.track.textTrackList.mediaElement) {
8434
- return -1;
8435
- }
8436
- var track = cue.track,
8437
- trackList = track.textTrackList,
8438
- count = 0;
8439
- for (var i = 0; i < trackList.length && trackList[i] !== track; i++) {
8440
- if (trackList[i].mode === "showing") {
8441
- count++;
8442
- }
8443
- }
8444
- return ++count * -1;
8445
- }
8446
-
8447
- function StyleBox() {}
8448
-
8449
- // Apply styles to a div. If there is no div passed then it defaults to the
8450
- // div on 'this'.
8451
- StyleBox.prototype.applyStyles = function (styles, div) {
8452
- div = div || this.div;
8453
- for (var prop in styles) {
8454
- if (styles.hasOwnProperty(prop)) {
8455
- div.style[prop] = styles[prop];
8456
- }
8457
- }
8458
- };
8459
-
8460
- StyleBox.prototype.formatStyle = function (val, unit) {
8461
- return val === 0 ? 0 : val + unit;
8462
- };
8463
-
8464
- // Constructs the computed display state of the cue (a div). Places the div
8465
- // into the overlay which should be a block level element (usually a div).
8466
- function CueStyleBox(window, cue, styleOptions) {
8467
- StyleBox.call(this);
8468
- this.cue = cue;
8469
-
8470
- // Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will
8471
- // have inline positioning and will function as the cue background box.
8472
- this.cueDiv = parseContent(window, cue.text);
8473
- var styles = {
8474
- color: "rgba(255, 255, 255, 1)",
8475
- backgroundColor: "rgba(0, 0, 0, 0.8)",
8476
- position: "relative",
8477
- left: 0,
8478
- right: 0,
8479
- top: 0,
8480
- bottom: 0,
8481
- display: "inline",
8482
- writingMode: cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl",
8483
- unicodeBidi: "plaintext"
8484
- };
8485
-
8486
- this.applyStyles(styles, this.cueDiv);
8487
-
8488
- // Create an absolutely positioned div that will be used to position the cue
8489
- // div. Note, all WebVTT cue-setting alignments are equivalent to the CSS
8490
- // mirrors of them except "middle" which is "center" in CSS.
8491
- this.div = window.document.createElement("div");
8492
- styles = {
8493
- direction: determineBidi(this.cueDiv),
8494
- writingMode: cue.vertical === "" ? "horizontal-tb" : cue.vertical === "lr" ? "vertical-lr" : "vertical-rl",
8495
- unicodeBidi: "plaintext",
8496
- textAlign: cue.align === "middle" ? "center" : cue.align,
8497
- font: styleOptions.font,
8498
- whiteSpace: "pre-line",
8499
- position: "absolute"
8500
- };
8501
-
8502
- this.applyStyles(styles);
8503
- this.div.appendChild(this.cueDiv);
8504
-
8505
- // Calculate the distance from the reference edge of the viewport to the text
8506
- // position of the cue box. The reference edge will be resolved later when
8507
- // the box orientation styles are applied.
8508
- var textPos = 0;
8509
- switch (cue.positionAlign) {
8510
- case "start":
8511
- textPos = cue.position;
8512
- break;
8513
- case "middle":
8514
- textPos = cue.position - cue.size / 2;
8515
- break;
8516
- case "end":
8517
- textPos = cue.position - cue.size;
8518
- break;
8519
- }
8520
-
8521
- // Horizontal box orientation; textPos is the distance from the left edge of the
8522
- // area to the left edge of the box and cue.size is the distance extending to
8523
- // the right from there.
8524
- if (cue.vertical === "") {
8525
- this.applyStyles({
8526
- left: this.formatStyle(textPos, "%"),
8527
- width: this.formatStyle(cue.size, "%")
8528
- });
8529
- // Vertical box orientation; textPos is the distance from the top edge of the
8530
- // area to the top edge of the box and cue.size is the height extending
8531
- // downwards from there.
8532
- } else {
8533
- this.applyStyles({
8534
- top: this.formatStyle(textPos, "%"),
8535
- height: this.formatStyle(cue.size, "%")
8536
- });
8537
- }
8538
-
8539
- this.move = function (box) {
8540
- this.applyStyles({
8541
- top: this.formatStyle(box.top, "px"),
8542
- bottom: this.formatStyle(box.bottom, "px"),
8543
- left: this.formatStyle(box.left, "px"),
8544
- right: this.formatStyle(box.right, "px"),
8545
- height: this.formatStyle(box.height, "px"),
8546
- width: this.formatStyle(box.width, "px")
8547
- });
8548
- };
8549
- }
8550
- CueStyleBox.prototype = _objCreate(StyleBox.prototype);
8551
- CueStyleBox.prototype.constructor = CueStyleBox;
8552
-
8553
- // Represents the co-ordinates of an Element in a way that we can easily
8554
- // compute things with such as if it overlaps or intersects with another Element.
8555
- // Can initialize it with either a StyleBox or another BoxPosition.
8556
- function BoxPosition(obj) {
8557
- // Either a BoxPosition was passed in and we need to copy it, or a StyleBox
8558
- // was passed in and we need to copy the results of 'getBoundingClientRect'
8559
- // as the object returned is readonly. All co-ordinate values are in reference
8560
- // to the viewport origin (top left).
8561
- var lh, height, width, top;
8562
- if (obj.div) {
8563
- height = obj.div.offsetHeight;
8564
- width = obj.div.offsetWidth;
8565
- top = obj.div.offsetTop;
8566
-
8567
- var rects = (rects = obj.div.childNodes) && (rects = rects[0]) && rects.getClientRects && rects.getClientRects();
8568
- obj = obj.div.getBoundingClientRect();
8569
- // In certain cases the outter div will be slightly larger then the sum of
8570
- // the inner div's lines. This could be due to bold text, etc, on some platforms.
8571
- // In this case we should get the average line height and use that. This will
8572
- // result in the desired behaviour.
8573
- lh = rects ? Math.max(rects[0] && rects[0].height || 0, obj.height / rects.length) : 0;
8574
- }
8575
- this.left = obj.left;
8576
- this.right = obj.right;
8577
- this.top = obj.top || top;
8578
- this.height = obj.height || height;
8579
- this.bottom = obj.bottom || top + (obj.height || height);
8580
- this.width = obj.width || width;
8581
- this.lineHeight = lh !== undefined ? lh : obj.lineHeight;
8582
- }
8583
-
8584
- // Move the box along a particular axis. Optionally pass in an amount to move
8585
- // the box. If no amount is passed then the default is the line height of the
8586
- // box.
8587
- BoxPosition.prototype.move = function (axis, toMove) {
8588
- toMove = toMove !== undefined ? toMove : this.lineHeight;
8589
- switch (axis) {
8590
- case "+x":
8591
- this.left += toMove;
8592
- this.right += toMove;
8593
- break;
8594
- case "-x":
8595
- this.left -= toMove;
8596
- this.right -= toMove;
8597
- break;
8598
- case "+y":
8599
- this.top += toMove;
8600
- this.bottom += toMove;
8601
- break;
8602
- case "-y":
8603
- this.top -= toMove;
8604
- this.bottom -= toMove;
8605
- break;
8606
- }
8607
- };
8608
-
8609
- // Check if this box overlaps another box, b2.
8610
- BoxPosition.prototype.overlaps = function (b2) {
8611
- return this.left < b2.right && this.right > b2.left && this.top < b2.bottom && this.bottom > b2.top;
8612
- };
8613
-
8614
- // Check if this box overlaps any other boxes in boxes.
8615
- BoxPosition.prototype.overlapsAny = function (boxes) {
8616
- for (var i = 0; i < boxes.length; i++) {
8617
- if (this.overlaps(boxes[i])) {
8618
- return true;
8619
- }
8620
- }
8621
- return false;
8622
- };
8623
-
8624
- // Check if this box is within another box.
8625
- BoxPosition.prototype.within = function (container) {
8626
- return this.top >= container.top && this.bottom <= container.bottom && this.left >= container.left && this.right <= container.right;
8627
- };
8628
-
8629
- // Check if this box is entirely within the container or it is overlapping
8630
- // on the edge opposite of the axis direction passed. For example, if "+x" is
8631
- // passed and the box is overlapping on the left edge of the container, then
8632
- // return true.
8633
- BoxPosition.prototype.overlapsOppositeAxis = function (container, axis) {
8634
- switch (axis) {
8635
- case "+x":
8636
- return this.left < container.left;
8637
- case "-x":
8638
- return this.right > container.right;
8639
- case "+y":
8640
- return this.top < container.top;
8641
- case "-y":
8642
- return this.bottom > container.bottom;
8643
- }
8644
- };
8645
-
8646
- // Find the percentage of the area that this box is overlapping with another
8647
- // box.
8648
- BoxPosition.prototype.intersectPercentage = function (b2) {
8649
- var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)),
8650
- y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)),
8651
- intersectArea = x * y;
8652
- return intersectArea / (this.height * this.width);
8653
- };
8654
-
8655
- // Convert the positions from this box to CSS compatible positions using
8656
- // the reference container's positions. This has to be done because this
8657
- // box's positions are in reference to the viewport origin, whereas, CSS
8658
- // values are in referecne to their respective edges.
8659
- BoxPosition.prototype.toCSSCompatValues = function (reference) {
8660
- return {
8661
- top: this.top - reference.top,
8662
- bottom: reference.bottom - this.bottom,
8663
- left: this.left - reference.left,
8664
- right: reference.right - this.right,
8665
- height: this.height,
8666
- width: this.width
8667
- };
8668
- };
8669
-
8670
- // Get an object that represents the box's position without anything extra.
8671
- // Can pass a StyleBox, HTMLElement, or another BoxPositon.
8672
- BoxPosition.getSimpleBoxPosition = function (obj) {
8673
- var height = obj.div ? obj.div.offsetHeight : obj.tagName ? obj.offsetHeight : 0;
8674
- var width = obj.div ? obj.div.offsetWidth : obj.tagName ? obj.offsetWidth : 0;
8675
- var top = obj.div ? obj.div.offsetTop : obj.tagName ? obj.offsetTop : 0;
8676
-
8677
- obj = obj.div ? obj.div.getBoundingClientRect() : obj.tagName ? obj.getBoundingClientRect() : obj;
8678
- var ret = {
8679
- left: obj.left,
8680
- right: obj.right,
8681
- top: obj.top || top,
8682
- height: obj.height || height,
8683
- bottom: obj.bottom || top + (obj.height || height),
8684
- width: obj.width || width
8685
- };
8686
- return ret;
8687
- };
8688
-
8689
- // Move a StyleBox to its specified, or next best, position. The containerBox
8690
- // is the box that contains the StyleBox, such as a div. boxPositions are
8691
- // a list of other boxes that the styleBox can't overlap with.
8692
- function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {
8693
-
8694
- // Find the best position for a cue box, b, on the video. The axis parameter
8695
- // is a list of axis, the order of which, it will move the box along. For example:
8696
- // Passing ["+x", "-x"] will move the box first along the x axis in the positive
8697
- // direction. If it doesn't find a good position for it there it will then move
8698
- // it along the x axis in the negative direction.
8699
- function findBestPosition(b, axis) {
8700
- var bestPosition,
8701
- specifiedPosition = new BoxPosition(b),
8702
- percentage = 1; // Highest possible so the first thing we get is better.
8703
-
8704
- for (var i = 0; i < axis.length; i++) {
8705
- while (b.overlapsOppositeAxis(containerBox, axis[i]) || b.within(containerBox) && b.overlapsAny(boxPositions)) {
8706
- b.move(axis[i]);
8707
- }
8708
- // We found a spot where we aren't overlapping anything. This is our
8709
- // best position.
8710
- if (b.within(containerBox)) {
8711
- return b;
8712
- }
8713
- var p = b.intersectPercentage(containerBox);
8714
- // If we're outside the container box less then we were on our last try
8715
- // then remember this position as the best position.
8716
- if (percentage > p) {
8717
- bestPosition = new BoxPosition(b);
8718
- percentage = p;
8719
- }
8720
- // Reset the box position to the specified position.
8721
- b = new BoxPosition(specifiedPosition);
8722
- }
8723
- return bestPosition || specifiedPosition;
8724
- }
8725
-
8726
- var boxPosition = new BoxPosition(styleBox),
8727
- cue = styleBox.cue,
8728
- linePos = computeLinePos(cue),
8729
- axis = [];
8730
-
8731
- // If we have a line number to align the cue to.
8732
- if (cue.snapToLines) {
8733
- var size;
8734
- switch (cue.vertical) {
8735
- case "":
8736
- axis = ["+y", "-y"];
8737
- size = "height";
8738
- break;
8739
- case "rl":
8740
- axis = ["+x", "-x"];
8741
- size = "width";
8742
- break;
8743
- case "lr":
8744
- axis = ["-x", "+x"];
8745
- size = "width";
8746
- break;
8747
- }
8748
-
8749
- var step = boxPosition.lineHeight,
8750
- position = step * Math.round(linePos),
8751
- maxPosition = containerBox[size] + step,
8752
- initialAxis = axis[0];
8753
-
8754
- // If the specified intial position is greater then the max position then
8755
- // clamp the box to the amount of steps it would take for the box to
8756
- // reach the max position.
8757
- if (Math.abs(position) > maxPosition) {
8758
- position = position < 0 ? -1 : 1;
8759
- position *= Math.ceil(maxPosition / step) * step;
8760
- }
8761
-
8762
- // If computed line position returns negative then line numbers are
8763
- // relative to the bottom of the video instead of the top. Therefore, we
8764
- // need to increase our initial position by the length or width of the
8765
- // video, depending on the writing direction, and reverse our axis directions.
8766
- if (linePos < 0) {
8767
- position += cue.vertical === "" ? containerBox.height : containerBox.width;
8768
- axis = axis.reverse();
8769
- }
8770
-
8771
- // Move the box to the specified position. This may not be its best
8772
- // position.
8773
- boxPosition.move(initialAxis, position);
8774
- } else {
8775
- // If we have a percentage line value for the cue.
8776
- var calculatedPercentage = boxPosition.lineHeight / containerBox.height * 100;
8777
-
8778
- switch (cue.lineAlign) {
8779
- case "middle":
8780
- linePos -= calculatedPercentage / 2;
8781
- break;
8782
- case "end":
8783
- linePos -= calculatedPercentage;
8784
- break;
8785
- }
8786
-
8787
- // Apply initial line position to the cue box.
8788
- switch (cue.vertical) {
8789
- case "":
8790
- styleBox.applyStyles({
8791
- top: styleBox.formatStyle(linePos, "%")
8792
- });
8793
- break;
8794
- case "rl":
8795
- styleBox.applyStyles({
8796
- left: styleBox.formatStyle(linePos, "%")
8797
- });
8798
- break;
8799
- case "lr":
8800
- styleBox.applyStyles({
8801
- right: styleBox.formatStyle(linePos, "%")
8802
- });
8803
- break;
8804
- }
8805
-
8806
- axis = ["+y", "-x", "+x", "-y"];
8807
-
8808
- // Get the box position again after we've applied the specified positioning
8809
- // to it.
8810
- boxPosition = new BoxPosition(styleBox);
8811
- }
8812
-
8813
- var bestPosition = findBestPosition(boxPosition, axis);
8814
- styleBox.move(bestPosition.toCSSCompatValues(containerBox));
8815
- }
8816
-
8817
- function WebVTT$1() {}
8818
- // Nothing
8819
-
8820
-
8821
- // Helper to allow strings to be decoded instead of the default binary utf8 data.
8822
- WebVTT$1.StringDecoder = function () {
8823
- return {
8824
- decode: function decode(data) {
8825
- if (!data) {
8826
- return "";
8827
- }
8828
- if (typeof data !== "string") {
8829
- throw new Error("Error - expected string data.");
8830
- }
8831
- return decodeURIComponent(encodeURIComponent(data));
8832
- }
8833
- };
8834
- };
8835
-
8836
- WebVTT$1.convertCueToDOMTree = function (window, cuetext) {
8837
- if (!window || !cuetext) {
8838
- return null;
8839
- }
8840
- return parseContent(window, cuetext);
8841
- };
8842
-
8843
- var FONT_SIZE_PERCENT = 0.05;
8844
- var FONT_STYLE = "sans-serif";
8845
- var CUE_BACKGROUND_PADDING = "1.5%";
8846
-
8847
- // Runs the processing model over the cues and regions passed to it.
8848
- // @param overlay A block level element (usually a div) that the computed cues
8849
- // and regions will be placed into.
8850
- WebVTT$1.processCues = function (window, cues, overlay) {
8851
- if (!window || !cues || !overlay) {
8852
- return null;
8853
- }
8854
-
8855
- // Remove all previous children.
8856
- while (overlay.firstChild) {
8857
- overlay.removeChild(overlay.firstChild);
8858
- }
8859
-
8860
- var paddedOverlay = window.document.createElement("div");
8861
- paddedOverlay.style.position = "absolute";
8862
- paddedOverlay.style.left = "0";
8863
- paddedOverlay.style.right = "0";
8864
- paddedOverlay.style.top = "0";
8865
- paddedOverlay.style.bottom = "0";
8866
- paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;
8867
- overlay.appendChild(paddedOverlay);
8868
-
8869
- // Determine if we need to compute the display states of the cues. This could
8870
- // be the case if a cue's state has been changed since the last computation or
8871
- // if it has not been computed yet.
8872
- function shouldCompute(cues) {
8873
- for (var i = 0; i < cues.length; i++) {
8874
- if (cues[i].hasBeenReset || !cues[i].displayState) {
8875
- return true;
8876
- }
8877
- }
8878
- return false;
8879
- }
8880
-
8881
- // We don't need to recompute the cues' display states. Just reuse them.
8882
- if (!shouldCompute(cues)) {
8883
- for (var i = 0; i < cues.length; i++) {
8884
- paddedOverlay.appendChild(cues[i].displayState);
8885
- }
8886
- return;
8887
- }
8888
-
8889
- var boxPositions = [],
8890
- containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay),
8891
- fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;
8892
- var styleOptions = {
8893
- font: fontSize + "px " + FONT_STYLE
8894
- };
8895
-
8896
- (function () {
8897
- var styleBox, cue;
8898
-
8899
- for (var i = 0; i < cues.length; i++) {
8900
- cue = cues[i];
8901
-
8902
- // Compute the intial position and styles of the cue div.
8903
- styleBox = new CueStyleBox(window, cue, styleOptions);
8904
- paddedOverlay.appendChild(styleBox.div);
8905
-
8906
- // Move the cue div to it's correct line position.
8907
- moveBoxToLinePosition(window, styleBox, containerBox, boxPositions);
8908
-
8909
- // Remember the computed div so that we don't have to recompute it later
8910
- // if we don't have too.
8911
- cue.displayState = styleBox.div;
8912
-
8913
- boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));
8914
- }
8915
- })();
8916
- };
8917
-
8918
- WebVTT$1.Parser = function (window, vttjs, decoder) {
8919
- if (!decoder) {
8920
- decoder = vttjs;
8921
- vttjs = {};
8922
- }
8923
- if (!vttjs) {
8924
- vttjs = {};
8925
- }
8926
-
8927
- this.window = window;
8928
- this.vttjs = vttjs;
8929
- this.state = "INITIAL";
8930
- this.buffer = "";
8931
- this.decoder = decoder || new TextDecoder("utf8");
8932
- this.regionList = [];
8933
- };
8934
-
8935
- WebVTT$1.Parser.prototype = {
8936
- // If the error is a ParsingError then report it to the consumer if
8937
- // possible. If it's not a ParsingError then throw it like normal.
8938
- reportOrThrowError: function reportOrThrowError(e) {
8939
- if (e instanceof ParsingError) {
8940
- this.onparsingerror && this.onparsingerror(e);
8941
- } else {
8942
- throw e;
8943
- }
8944
- },
8945
- parse: function parse(data) {
8946
- var self = this;
8947
-
8948
- // If there is no data then we won't decode it, but will just try to parse
8949
- // whatever is in buffer already. This may occur in circumstances, for
8950
- // example when flush() is called.
8951
- if (data) {
8952
- // Try to decode the data that we received.
8953
- self.buffer += self.decoder.decode(data, { stream: true });
8954
- }
8955
-
8956
- function collectNextLine() {
8957
- var buffer = self.buffer;
8958
- var pos = 0;
8959
- while (pos < buffer.length && buffer[pos] !== '\r' && buffer[pos] !== '\n') {
8960
- ++pos;
8961
- }
8962
- var line = buffer.substr(0, pos);
8963
- // Advance the buffer early in case we fail below.
8964
- if (buffer[pos] === '\r') {
8965
- ++pos;
8966
- }
8967
- if (buffer[pos] === '\n') {
8968
- ++pos;
8969
- }
8970
- self.buffer = buffer.substr(pos);
8971
- return line;
8972
- }
8973
-
8974
- // 3.4 WebVTT region and WebVTT region settings syntax
8975
- function parseRegion(input) {
8976
- var settings = new Settings();
8977
-
8978
- parseOptions(input, function (k, v) {
8979
- switch (k) {
8980
- case "id":
8981
- settings.set(k, v);
8982
- break;
8983
- case "width":
8984
- settings.percent(k, v);
8985
- break;
8986
- case "lines":
8987
- settings.integer(k, v);
8988
- break;
8989
- case "regionanchor":
8990
- case "viewportanchor":
8991
- var xy = v.split(',');
8992
- if (xy.length !== 2) {
8993
- break;
8994
- }
8995
- // We have to make sure both x and y parse, so use a temporary
8996
- // settings object here.
8997
- var anchor = new Settings();
8998
- anchor.percent("x", xy[0]);
8999
- anchor.percent("y", xy[1]);
9000
- if (!anchor.has("x") || !anchor.has("y")) {
9001
- break;
9002
- }
9003
- settings.set(k + "X", anchor.get("x"));
9004
- settings.set(k + "Y", anchor.get("y"));
9005
- break;
9006
- case "scroll":
9007
- settings.alt(k, v, ["up"]);
9008
- break;
9009
- }
9010
- }, /=/, /\s/);
9011
-
9012
- // Create the region, using default values for any values that were not
9013
- // specified.
9014
- if (settings.has("id")) {
9015
- var region = new (self.vttjs.VTTRegion || self.window.VTTRegion)();
9016
- region.width = settings.get("width", 100);
9017
- region.lines = settings.get("lines", 3);
9018
- region.regionAnchorX = settings.get("regionanchorX", 0);
9019
- region.regionAnchorY = settings.get("regionanchorY", 100);
9020
- region.viewportAnchorX = settings.get("viewportanchorX", 0);
9021
- region.viewportAnchorY = settings.get("viewportanchorY", 100);
9022
- region.scroll = settings.get("scroll", "");
9023
- // Register the region.
9024
- self.onregion && self.onregion(region);
9025
- // Remember the VTTRegion for later in case we parse any VTTCues that
9026
- // reference it.
9027
- self.regionList.push({
9028
- id: settings.get("id"),
9029
- region: region
9030
- });
9031
- }
9032
- }
9033
-
9034
- // draft-pantos-http-live-streaming-20
9035
- // https://tools.ietf.org/html/draft-pantos-http-live-streaming-20#section-3.5
9036
- // 3.5 WebVTT
9037
- function parseTimestampMap(input) {
9038
- var settings = new Settings();
9039
-
9040
- parseOptions(input, function (k, v) {
9041
- switch (k) {
9042
- case "MPEGT":
9043
- settings.integer(k + 'S', v);
9044
- break;
9045
- case "LOCA":
9046
- settings.set(k + 'L', parseTimeStamp(v));
9047
- break;
9048
- }
9049
- }, /[^\d]:/, /,/);
9050
-
9051
- self.ontimestampmap && self.ontimestampmap({
9052
- "MPEGTS": settings.get("MPEGTS"),
9053
- "LOCAL": settings.get("LOCAL")
9054
- });
9055
- }
9056
-
9057
- // 3.2 WebVTT metadata header syntax
9058
- function parseHeader(input) {
9059
- if (input.match(/X-TIMESTAMP-MAP/)) {
9060
- // This line contains HLS X-TIMESTAMP-MAP metadata
9061
- parseOptions(input, function (k, v) {
9062
- switch (k) {
9063
- case "X-TIMESTAMP-MAP":
9064
- parseTimestampMap(v);
9065
- break;
9066
- }
9067
- }, /=/);
9068
- } else {
9069
- parseOptions(input, function (k, v) {
9070
- switch (k) {
9071
- case "Region":
9072
- // 3.3 WebVTT region metadata header syntax
9073
- parseRegion(v);
9074
- break;
9075
- }
9076
- }, /:/);
9077
- }
9078
- }
9079
-
9080
- // 5.1 WebVTT file parsing.
9081
- try {
9082
- var line;
9083
- if (self.state === "INITIAL") {
9084
- // We can't start parsing until we have the first line.
9085
- if (!/\r\n|\n/.test(self.buffer)) {
9086
- return this;
9087
- }
9088
-
9089
- line = collectNextLine();
9090
-
9091
- var m = line.match(/^WEBVTT([ \t].*)?$/);
9092
- if (!m || !m[0]) {
9093
- throw new ParsingError(ParsingError.Errors.BadSignature);
9094
- }
9095
-
9096
- self.state = "HEADER";
9097
- }
9098
-
9099
- var alreadyCollectedLine = false;
9100
- while (self.buffer) {
9101
- // We can't parse a line until we have the full line.
9102
- if (!/\r\n|\n/.test(self.buffer)) {
9103
- return this;
9104
- }
9105
-
9106
- if (!alreadyCollectedLine) {
9107
- line = collectNextLine();
9108
- } else {
9109
- alreadyCollectedLine = false;
9110
- }
9111
-
9112
- switch (self.state) {
9113
- case "HEADER":
9114
- // 13-18 - Allow a header (metadata) under the WEBVTT line.
9115
- if (/:/.test(line)) {
9116
- parseHeader(line);
9117
- } else if (!line) {
9118
- // An empty line terminates the header and starts the body (cues).
9119
- self.state = "ID";
9120
- }
9121
- continue;
9122
- case "NOTE":
9123
- // Ignore NOTE blocks.
9124
- if (!line) {
9125
- self.state = "ID";
9126
- }
9127
- continue;
9128
- case "ID":
9129
- // Check for the start of NOTE blocks.
9130
- if (/^NOTE($|[ \t])/.test(line)) {
9131
- self.state = "NOTE";
9132
- break;
9133
- }
9134
- // 19-29 - Allow any number of line terminators, then initialize new cue values.
9135
- if (!line) {
9136
- continue;
9137
- }
9138
- self.cue = new (self.vttjs.VTTCue || self.window.VTTCue)(0, 0, "");
9139
- self.state = "CUE";
9140
- // 30-39 - Check if self line contains an optional identifier or timing data.
9141
- if (line.indexOf("-->") === -1) {
9142
- self.cue.id = line;
9143
- continue;
9144
- }
9145
- // Process line as start of a cue.
9146
- /*falls through*/
9147
- case "CUE":
9148
- // 40 - Collect cue timings and settings.
9149
- try {
9150
- parseCue(line, self.cue, self.regionList);
9151
- } catch (e) {
9152
- self.reportOrThrowError(e);
9153
- // In case of an error ignore rest of the cue.
9154
- self.cue = null;
9155
- self.state = "BADCUE";
9156
- continue;
9157
- }
9158
- self.state = "CUETEXT";
9159
- continue;
9160
- case "CUETEXT":
9161
- var hasSubstring = line.indexOf("-->") !== -1;
9162
- // 34 - If we have an empty line then report the cue.
9163
- // 35 - If we have the special substring '-->' then report the cue,
9164
- // but do not collect the line as we need to process the current
9165
- // one as a new cue.
9166
- if (!line || hasSubstring && (alreadyCollectedLine = true)) {
9167
- // We are done parsing self cue.
9168
- self.oncue && self.oncue(self.cue);
9169
- self.cue = null;
9170
- self.state = "ID";
9171
- continue;
9172
- }
9173
- if (self.cue.text) {
9174
- self.cue.text += "\n";
9175
- }
9176
- self.cue.text += line;
9177
- continue;
9178
- case "BADCUE":
9179
- // BADCUE
9180
- // 54-62 - Collect and discard the remaining cue.
9181
- if (!line) {
9182
- self.state = "ID";
9183
- }
9184
- continue;
9185
- }
9186
- }
9187
- } catch (e) {
9188
- self.reportOrThrowError(e);
9189
-
9190
- // If we are currently parsing a cue, report what we have.
9191
- if (self.state === "CUETEXT" && self.cue && self.oncue) {
9192
- self.oncue(self.cue);
9193
- }
9194
- self.cue = null;
9195
- // Enter BADWEBVTT state if header was not parsed correctly otherwise
9196
- // another exception occurred so enter BADCUE state.
9197
- self.state = self.state === "INITIAL" ? "BADWEBVTT" : "BADCUE";
9198
- }
9199
- return this;
9200
- },
9201
- flush: function flush() {
9202
- var self = this;
9203
- try {
9204
- // Finish decoding the stream.
9205
- self.buffer += self.decoder.decode();
9206
- // Synthesize the end of the current cue or region.
9207
- if (self.cue || self.state === "HEADER") {
9208
- self.buffer += "\n\n";
9209
- self.parse();
9210
- }
9211
- // If we've flushed, parsed, and we're still on the INITIAL state then
9212
- // that means we don't have enough of the stream to parse the first
9213
- // line.
9214
- if (self.state === "INITIAL") {
9215
- throw new ParsingError(ParsingError.Errors.BadSignature);
9216
- }
9217
- } catch (e) {
9218
- self.reportOrThrowError(e);
9219
- }
9220
- self.onflush && self.onflush();
9221
- return this;
9222
- }
9223
- };
9224
-
9225
- var vtt = WebVTT$1;
9226
-
9227
- var vtt$1 = /*#__PURE__*/Object.freeze({
9228
- default: vtt,
9229
- __moduleExports: vtt
9230
- });
9231
-
9232
- /**
9233
- * Copyright 2013 vtt.js Contributors
9234
- *
9235
- * Licensed under the Apache License, Version 2.0 (the "License");
9236
- * you may not use this file except in compliance with the License.
9237
- * You may obtain a copy of the License at
9238
- *
9239
- * http://www.apache.org/licenses/LICENSE-2.0
9240
- *
9241
- * Unless required by applicable law or agreed to in writing, software
9242
- * distributed under the License is distributed on an "AS IS" BASIS,
9243
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9244
- * See the License for the specific language governing permissions and
9245
- * limitations under the License.
9246
- */
9247
-
9248
- var autoKeyword = "auto";
9249
- var directionSetting = {
9250
- "": 1,
9251
- "lr": 1,
9252
- "rl": 1
9253
- };
9254
- var alignSetting = {
9255
- "start": 1,
9256
- "middle": 1,
9257
- "end": 1,
9258
- "left": 1,
9259
- "right": 1
9260
- };
9261
-
9262
- function findDirectionSetting(value) {
9263
- if (typeof value !== "string") {
9264
- return false;
9265
- }
9266
- var dir = directionSetting[value.toLowerCase()];
9267
- return dir ? value.toLowerCase() : false;
9268
- }
9269
-
9270
- function findAlignSetting(value) {
9271
- if (typeof value !== "string") {
9272
- return false;
9273
- }
9274
- var align = alignSetting[value.toLowerCase()];
9275
- return align ? value.toLowerCase() : false;
9276
- }
9277
-
9278
- function VTTCue(startTime, endTime, text) {
9279
- /**
9280
- * Shim implementation specific properties. These properties are not in
9281
- * the spec.
9282
- */
9283
-
9284
- // Lets us know when the VTTCue's data has changed in such a way that we need
9285
- // to recompute its display state. This lets us compute its display state
9286
- // lazily.
9287
- this.hasBeenReset = false;
9288
-
9289
- /**
9290
- * VTTCue and TextTrackCue properties
9291
- * http://dev.w3.org/html5/webvtt/#vttcue-interface
9292
- */
9293
-
9294
- var _id = "";
9295
- var _pauseOnExit = false;
9296
- var _startTime = startTime;
9297
- var _endTime = endTime;
9298
- var _text = text;
9299
- var _region = null;
9300
- var _vertical = "";
9301
- var _snapToLines = true;
9302
- var _line = "auto";
9303
- var _lineAlign = "start";
9304
- var _position = 50;
9305
- var _positionAlign = "middle";
9306
- var _size = 50;
9307
- var _align = "middle";
9308
-
9309
- Object.defineProperties(this, {
9310
- "id": {
9311
- enumerable: true,
9312
- get: function get() {
9313
- return _id;
9314
- },
9315
- set: function set(value) {
9316
- _id = "" + value;
9317
- }
9318
- },
9319
-
9320
- "pauseOnExit": {
9321
- enumerable: true,
9322
- get: function get() {
9323
- return _pauseOnExit;
9324
- },
9325
- set: function set(value) {
9326
- _pauseOnExit = !!value;
9327
- }
9328
- },
9329
-
9330
- "startTime": {
9331
- enumerable: true,
9332
- get: function get() {
9333
- return _startTime;
9334
- },
9335
- set: function set(value) {
9336
- if (typeof value !== "number") {
9337
- throw new TypeError("Start time must be set to a number.");
9338
- }
9339
- _startTime = value;
9340
- this.hasBeenReset = true;
9341
- }
9342
- },
9343
-
9344
- "endTime": {
9345
- enumerable: true,
9346
- get: function get() {
9347
- return _endTime;
9348
- },
9349
- set: function set(value) {
9350
- if (typeof value !== "number") {
9351
- throw new TypeError("End time must be set to a number.");
9352
- }
9353
- _endTime = value;
9354
- this.hasBeenReset = true;
9355
- }
9356
- },
9357
-
9358
- "text": {
9359
- enumerable: true,
9360
- get: function get() {
9361
- return _text;
9362
- },
9363
- set: function set(value) {
9364
- _text = "" + value;
9365
- this.hasBeenReset = true;
9366
- }
9367
- },
9368
-
9369
- "region": {
9370
- enumerable: true,
9371
- get: function get() {
9372
- return _region;
9373
- },
9374
- set: function set(value) {
9375
- _region = value;
9376
- this.hasBeenReset = true;
9377
- }
9378
- },
9379
-
9380
- "vertical": {
9381
- enumerable: true,
9382
- get: function get() {
9383
- return _vertical;
9384
- },
9385
- set: function set(value) {
9386
- var setting = findDirectionSetting(value);
9387
- // Have to check for false because the setting an be an empty string.
9388
- if (setting === false) {
9389
- throw new SyntaxError("An invalid or illegal string was specified.");
9390
- }
9391
- _vertical = setting;
9392
- this.hasBeenReset = true;
9393
- }
9394
- },
9395
-
9396
- "snapToLines": {
9397
- enumerable: true,
9398
- get: function get() {
9399
- return _snapToLines;
9400
- },
9401
- set: function set(value) {
9402
- _snapToLines = !!value;
9403
- this.hasBeenReset = true;
9404
- }
9405
- },
9406
-
9407
- "line": {
9408
- enumerable: true,
9409
- get: function get() {
9410
- return _line;
9411
- },
9412
- set: function set(value) {
9413
- if (typeof value !== "number" && value !== autoKeyword) {
9414
- throw new SyntaxError("An invalid number or illegal string was specified.");
9415
- }
9416
- _line = value;
9417
- this.hasBeenReset = true;
9418
- }
9419
- },
9420
-
9421
- "lineAlign": {
9422
- enumerable: true,
9423
- get: function get() {
9424
- return _lineAlign;
9425
- },
9426
- set: function set(value) {
9427
- var setting = findAlignSetting(value);
9428
- if (!setting) {
9429
- throw new SyntaxError("An invalid or illegal string was specified.");
9430
- }
9431
- _lineAlign = setting;
9432
- this.hasBeenReset = true;
9433
- }
9434
- },
9435
-
9436
- "position": {
9437
- enumerable: true,
9438
- get: function get() {
9439
- return _position;
9440
- },
9441
- set: function set(value) {
9442
- if (value < 0 || value > 100) {
9443
- throw new Error("Position must be between 0 and 100.");
9444
- }
9445
- _position = value;
9446
- this.hasBeenReset = true;
9447
- }
9448
- },
9449
-
9450
- "positionAlign": {
9451
- enumerable: true,
9452
- get: function get() {
9453
- return _positionAlign;
9454
- },
9455
- set: function set(value) {
9456
- var setting = findAlignSetting(value);
9457
- if (!setting) {
9458
- throw new SyntaxError("An invalid or illegal string was specified.");
9459
- }
9460
- _positionAlign = setting;
9461
- this.hasBeenReset = true;
9462
- }
9463
- },
9464
-
9465
- "size": {
9466
- enumerable: true,
9467
- get: function get() {
9468
- return _size;
9469
- },
9470
- set: function set(value) {
9471
- if (value < 0 || value > 100) {
9472
- throw new Error("Size must be between 0 and 100.");
9473
- }
9474
- _size = value;
9475
- this.hasBeenReset = true;
9476
- }
9477
- },
9478
-
9479
- "align": {
9480
- enumerable: true,
9481
- get: function get() {
9482
- return _align;
9483
- },
9484
- set: function set(value) {
9485
- var setting = findAlignSetting(value);
9486
- if (!setting) {
9487
- throw new SyntaxError("An invalid or illegal string was specified.");
9488
- }
9489
- _align = setting;
9490
- this.hasBeenReset = true;
9491
- }
9492
- }
9493
- });
9494
-
9495
- /**
9496
- * Other <track> spec defined properties
9497
- */
9498
-
9499
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-video-element.html#text-track-cue-display-state
9500
- this.displayState = undefined;
9501
- }
9502
-
9503
- /**
9504
- * VTTCue methods
9505
- */
9506
-
9507
- VTTCue.prototype.getCueAsHTML = function () {
9508
- // Assume WebVTT.convertCueToDOMTree is on the global.
9509
- return WebVTT.convertCueToDOMTree(window, this.text);
9510
- };
9511
-
9512
- var vttcue = VTTCue;
9513
-
9514
- var vttcue$1 = /*#__PURE__*/Object.freeze({
9515
- default: vttcue,
9516
- __moduleExports: vttcue
9517
- });
9518
-
9519
- /**
9520
- * Copyright 2013 vtt.js Contributors
9521
- *
9522
- * Licensed under the Apache License, Version 2.0 (the "License");
9523
- * you may not use this file except in compliance with the License.
9524
- * You may obtain a copy of the License at
9525
- *
9526
- * http://www.apache.org/licenses/LICENSE-2.0
9527
- *
9528
- * Unless required by applicable law or agreed to in writing, software
9529
- * distributed under the License is distributed on an "AS IS" BASIS,
9530
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9531
- * See the License for the specific language governing permissions and
9532
- * limitations under the License.
9533
- */
9534
-
9535
- var scrollSetting = {
9536
- "": true,
9537
- "up": true
9538
- };
9539
-
9540
- function findScrollSetting(value) {
9541
- if (typeof value !== "string") {
9542
- return false;
9543
- }
9544
- var scroll = scrollSetting[value.toLowerCase()];
9545
- return scroll ? value.toLowerCase() : false;
9546
- }
9547
-
9548
- function isValidPercentValue(value) {
9549
- return typeof value === "number" && value >= 0 && value <= 100;
9550
- }
9551
-
9552
- // VTTRegion shim http://dev.w3.org/html5/webvtt/#vttregion-interface
9553
- function VTTRegion() {
9554
- var _width = 100;
9555
- var _lines = 3;
9556
- var _regionAnchorX = 0;
9557
- var _regionAnchorY = 100;
9558
- var _viewportAnchorX = 0;
9559
- var _viewportAnchorY = 100;
9560
- var _scroll = "";
9561
-
9562
- Object.defineProperties(this, {
9563
- "width": {
9564
- enumerable: true,
9565
- get: function get() {
9566
- return _width;
9567
- },
9568
- set: function set(value) {
9569
- if (!isValidPercentValue(value)) {
9570
- throw new Error("Width must be between 0 and 100.");
9571
- }
9572
- _width = value;
9573
- }
9574
- },
9575
- "lines": {
9576
- enumerable: true,
9577
- get: function get() {
9578
- return _lines;
9579
- },
9580
- set: function set(value) {
9581
- if (typeof value !== "number") {
9582
- throw new TypeError("Lines must be set to a number.");
9583
- }
9584
- _lines = value;
9585
- }
9586
- },
9587
- "regionAnchorY": {
9588
- enumerable: true,
9589
- get: function get() {
9590
- return _regionAnchorY;
9591
- },
9592
- set: function set(value) {
9593
- if (!isValidPercentValue(value)) {
9594
- throw new Error("RegionAnchorX must be between 0 and 100.");
9595
- }
9596
- _regionAnchorY = value;
9597
- }
9598
- },
9599
- "regionAnchorX": {
9600
- enumerable: true,
9601
- get: function get() {
9602
- return _regionAnchorX;
9603
- },
9604
- set: function set(value) {
9605
- if (!isValidPercentValue(value)) {
9606
- throw new Error("RegionAnchorY must be between 0 and 100.");
9607
- }
9608
- _regionAnchorX = value;
9609
- }
9610
- },
9611
- "viewportAnchorY": {
9612
- enumerable: true,
9613
- get: function get() {
9614
- return _viewportAnchorY;
9615
- },
9616
- set: function set(value) {
9617
- if (!isValidPercentValue(value)) {
9618
- throw new Error("ViewportAnchorY must be between 0 and 100.");
9619
- }
9620
- _viewportAnchorY = value;
9621
- }
9622
- },
9623
- "viewportAnchorX": {
9624
- enumerable: true,
9625
- get: function get() {
9626
- return _viewportAnchorX;
9627
- },
9628
- set: function set(value) {
9629
- if (!isValidPercentValue(value)) {
9630
- throw new Error("ViewportAnchorX must be between 0 and 100.");
9631
- }
9632
- _viewportAnchorX = value;
9633
- }
9634
- },
9635
- "scroll": {
9636
- enumerable: true,
9637
- get: function get() {
9638
- return _scroll;
9639
- },
9640
- set: function set(value) {
9641
- var setting = findScrollSetting(value);
9642
- // Have to check for false as an empty string is a legal value.
9643
- if (setting === false) {
9644
- throw new SyntaxError("An invalid or illegal string was specified.");
9645
- }
9646
- _scroll = setting;
9647
- }
9648
- }
9649
- });
9650
- }
9651
-
9652
- var vttregion = VTTRegion;
9653
-
9654
- var vttregion$1 = /*#__PURE__*/Object.freeze({
9655
- default: vttregion,
9656
- __moduleExports: vttregion
9657
- });
9658
-
9659
- var require$$0 = ( vtt$1 && vtt ) || vtt$1;
9660
-
9661
- var require$$1 = ( vttcue$1 && vttcue ) || vttcue$1;
9662
-
9663
- var require$$2 = ( vttregion$1 && vttregion ) || vttregion$1;
9664
-
9665
- var browserIndex = createCommonjsModule(function (module) {
9666
- /**
9667
- * Copyright 2013 vtt.js Contributors
9668
- *
9669
- * Licensed under the Apache License, Version 2.0 (the "License");
9670
- * you may not use this file except in compliance with the License.
9671
- * You may obtain a copy of the License at
9672
- *
9673
- * http://www.apache.org/licenses/LICENSE-2.0
9674
- *
9675
- * Unless required by applicable law or agreed to in writing, software
9676
- * distributed under the License is distributed on an "AS IS" BASIS,
9677
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9678
- * See the License for the specific language governing permissions and
9679
- * limitations under the License.
9680
- */
9681
-
9682
- // Default exports for Node. Export the extended versions of VTTCue and
9683
- // VTTRegion in Node since we likely want the capability to convert back and
9684
- // forth between JSON. If we don't then it's not that big of a deal since we're
9685
- // off browser.
9686
-
9687
-
9688
- var vttjs = module.exports = {
9689
- WebVTT: require$$0,
9690
- VTTCue: require$$1,
9691
- VTTRegion: require$$2
9692
- };
9693
-
9694
- window_1.vttjs = vttjs;
9695
- window_1.WebVTT = vttjs.WebVTT;
9696
-
9697
- var cueShim = vttjs.VTTCue;
9698
- var regionShim = vttjs.VTTRegion;
9699
- var nativeVTTCue = window_1.VTTCue;
9700
- var nativeVTTRegion = window_1.VTTRegion;
9701
-
9702
- vttjs.shim = function () {
9703
- window_1.VTTCue = cueShim;
9704
- window_1.VTTRegion = regionShim;
9705
- };
9706
-
9707
- vttjs.restore = function () {
9708
- window_1.VTTCue = nativeVTTCue;
9709
- window_1.VTTRegion = nativeVTTRegion;
9710
- };
9711
-
9712
- if (!window_1.VTTCue) {
9713
- vttjs.shim();
9714
- }
9715
- });
9716
- var browserIndex_1 = browserIndex.WebVTT;
9717
- var browserIndex_2 = browserIndex.VTTCue;
9718
- var browserIndex_3 = browserIndex.VTTRegion;
9719
-
9720
- /**
9721
- * @file tech.js
9722
- */
9723
-
9724
- /**
9725
- * An Object containing a structure like: `{src: 'url', type: 'mimetype'}` or string
9726
- * that just contains the src url alone.
9727
- * * `var SourceObject = {src: 'http://ex.com/video.mp4', type: 'video/mp4'};`
9728
- * `var SourceString = 'http://example.com/some-video.mp4';`
9729
- *
9730
- * @typedef {Object|string} Tech~SourceObject
9731
- *
9732
- * @property {string} src
9733
- * The url to the source
9734
- *
9735
- * @property {string} type
9736
- * The mime type of the source
9737
- */
9738
-
9739
- /**
9740
- * A function used by {@link Tech} to create a new {@link TextTrack}.
9741
- *
9742
- * @private
9743
- *
9744
- * @param {Tech} self
9745
- * An instance of the Tech class.
9746
- *
9747
- * @param {string} kind
9748
- * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
9749
- *
9750
- * @param {string} [label]
9751
- * Label to identify the text track
9752
- *
9753
- * @param {string} [language]
9754
- * Two letter language abbreviation
9755
- *
9756
- * @param {Object} [options={}]
9757
- * An object with additional text track options
9758
- *
9759
- * @return {TextTrack}
9760
- * The text track that was created.
9761
- */
9762
- function createTrackHelper(self, kind, label, language) {
9763
- var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
9764
-
9765
- var tracks = self.textTracks();
9766
-
9767
- options.kind = kind;
9768
-
9769
- if (label) {
9770
- options.label = label;
9771
- }
9772
- if (language) {
9773
- options.language = language;
9774
- }
9775
- options.tech = self;
9776
-
9777
- var track = new ALL.text.TrackClass(options);
9778
-
9779
- tracks.addTrack(track);
9780
-
9781
- return track;
9782
- }
9783
-
9784
- /**
9785
- * This is the base class for media playback technology controllers, such as
9786
- * {@link Flash} and {@link HTML5}
9787
- *
9788
- * @extends Component
9789
- */
9790
-
9791
- var Tech = function (_Component) {
9792
- inherits(Tech, _Component);
9793
-
9794
- /**
9795
- * Create an instance of this Tech.
9796
- *
9797
- * @param {Object} [options]
9798
- * The key/value store of player options.
9799
- *
9800
- * @param {Component~ReadyCallback} ready
9801
- * Callback function to call when the `HTML5` Tech is ready.
9802
- */
9803
- function Tech() {
9804
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
9805
- var ready = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
9806
- classCallCheck(this, Tech);
9807
-
9808
- // we don't want the tech to report user activity automatically.
9809
- // This is done manually in addControlsListeners
9810
- options.reportTouchActivity = false;
9811
-
9812
- // keep track of whether the current source has played at all to
9813
- // implement a very limited played()
9814
- var _this = possibleConstructorReturn(this, _Component.call(this, null, options, ready));
9815
-
9816
- _this.hasStarted_ = false;
9817
- _this.on('playing', function () {
9818
- this.hasStarted_ = true;
9819
- });
9820
- _this.on('loadstart', function () {
9821
- this.hasStarted_ = false;
9822
- });
9823
-
9824
- ALL.names.forEach(function (name) {
9825
- var props = ALL[name];
9826
-
9827
- if (options && options[props.getterName]) {
9828
- _this[props.privateName] = options[props.getterName];
9829
- }
9830
- });
9831
-
9832
- // Manually track progress in cases where the browser/flash player doesn't report it.
9833
- if (!_this.featuresProgressEvents) {
9834
- _this.manualProgressOn();
9835
- }
9836
-
9837
- // Manually track timeupdates in cases where the browser/flash player doesn't report it.
9838
- if (!_this.featuresTimeupdateEvents) {
9839
- _this.manualTimeUpdatesOn();
9840
- }
9841
-
9842
- ['Text', 'Audio', 'Video'].forEach(function (track) {
9843
- if (options['native' + track + 'Tracks'] === false) {
9844
- _this['featuresNative' + track + 'Tracks'] = false;
9845
- }
9846
- });
9847
-
9848
- if (options.nativeCaptions === false || options.nativeTextTracks === false) {
9849
- _this.featuresNativeTextTracks = false;
9850
- } else if (options.nativeCaptions === true || options.nativeTextTracks === true) {
9851
- _this.featuresNativeTextTracks = true;
9852
- }
9853
-
9854
- if (!_this.featuresNativeTextTracks) {
9855
- _this.emulateTextTracks();
9856
- }
9857
-
9858
- _this.autoRemoteTextTracks_ = new ALL.text.ListClass();
9859
-
9860
- _this.initTrackListeners();
9861
-
9862
- // Turn on component tap events only if not using native controls
9863
- if (!options.nativeControlsForTouch) {
9864
- _this.emitTapEvents();
9865
- }
9866
-
9867
- if (_this.constructor) {
9868
- _this.name_ = _this.constructor.name || 'Unknown Tech';
9869
- }
9870
- return _this;
9871
- }
9872
-
9873
- /**
9874
- * A special function to trigger source set in a way that will allow player
9875
- * to re-trigger if the player or tech are not ready yet.
9876
- *
9877
- * @fires Tech#sourceset
9878
- * @param {string} src The source string at the time of the source changing.
9879
- */
9880
-
9881
-
9882
- Tech.prototype.triggerSourceset = function triggerSourceset(src) {
9883
- var _this2 = this;
9884
-
9885
- if (!this.isReady_) {
9886
- // on initial ready we have to trigger source set
9887
- // 1ms after ready so that player can watch for it.
9888
- this.one('ready', function () {
9889
- return _this2.setTimeout(function () {
9890
- return _this2.triggerSourceset(src);
9891
- }, 1);
9892
- });
9893
- }
9894
-
9895
- /**
9896
- * Fired when the source is set on the tech causing the media element
9897
- * to reload.
9898
- *
9899
- * @see {@link Player#event:sourceset}
9900
- * @event Tech#sourceset
9901
- * @type {EventTarget~Event}
9902
- */
9903
- this.trigger({
9904
- src: src,
9905
- type: 'sourceset'
9906
- });
9907
- };
9908
-
9909
- /* Fallbacks for unsupported event types
9910
- ================================================================================ */
9911
-
9912
- /**
9913
- * Polyfill the `progress` event for browsers that don't support it natively.
9914
- *
9915
- * @see {@link Tech#trackProgress}
9916
- */
9917
-
9918
-
9919
- Tech.prototype.manualProgressOn = function manualProgressOn() {
9920
- this.on('durationchange', this.onDurationChange);
9921
-
9922
- this.manualProgress = true;
9923
-
9924
- // Trigger progress watching when a source begins loading
9925
- this.one('ready', this.trackProgress);
9926
- };
9927
-
9928
- /**
9929
- * Turn off the polyfill for `progress` events that was created in
9930
- * {@link Tech#manualProgressOn}
9931
- */
9932
-
9933
-
9934
- Tech.prototype.manualProgressOff = function manualProgressOff() {
9935
- this.manualProgress = false;
9936
- this.stopTrackingProgress();
9937
-
9938
- this.off('durationchange', this.onDurationChange);
9939
- };
9940
-
9941
- /**
9942
- * This is used to trigger a `progress` event when the buffered percent changes. It
9943
- * sets an interval function that will be called every 500 milliseconds to check if the
9944
- * buffer end percent has changed.
9945
- *
9946
- * > This function is called by {@link Tech#manualProgressOn}
9947
- *
9948
- * @param {EventTarget~Event} event
9949
- * The `ready` event that caused this to run.
9950
- *
9951
- * @listens Tech#ready
9952
- * @fires Tech#progress
9953
- */
9954
-
9955
-
9956
- Tech.prototype.trackProgress = function trackProgress(event) {
9957
- this.stopTrackingProgress();
9958
- this.progressInterval = this.setInterval(bind(this, function () {
9959
- // Don't trigger unless buffered amount is greater than last time
9960
-
9961
- var numBufferedPercent = this.bufferedPercent();
9962
-
9963
- if (this.bufferedPercent_ !== numBufferedPercent) {
9964
- /**
9965
- * See {@link Player#progress}
9966
- *
9967
- * @event Tech#progress
9968
- * @type {EventTarget~Event}
9969
- */
9970
- this.trigger('progress');
9971
- }
9972
-
9973
- this.bufferedPercent_ = numBufferedPercent;
9974
-
9975
- if (numBufferedPercent === 1) {
9976
- this.stopTrackingProgress();
9977
- }
9978
- }), 500);
9979
- };
9980
-
9981
- /**
9982
- * Update our internal duration on a `durationchange` event by calling
9983
- * {@link Tech#duration}.
9984
- *
9985
- * @param {EventTarget~Event} event
9986
- * The `durationchange` event that caused this to run.
9987
- *
9988
- * @listens Tech#durationchange
9989
- */
9990
-
9991
-
9992
- Tech.prototype.onDurationChange = function onDurationChange(event) {
9993
- this.duration_ = this.duration();
9994
- };
9995
-
9996
- /**
9997
- * Get and create a `TimeRange` object for buffering.
9998
- *
9999
- * @return {TimeRange}
10000
- * The time range object that was created.
10001
- */
10002
-
10003
-
10004
- Tech.prototype.buffered = function buffered() {
10005
- return createTimeRanges(0, 0);
10006
- };
10007
-
10008
- /**
10009
- * Get the percentage of the current video that is currently buffered.
10010
- *
10011
- * @return {number}
10012
- * A number from 0 to 1 that represents the decimal percentage of the
10013
- * video that is buffered.
10014
- *
10015
- */
10016
-
10017
-
10018
- Tech.prototype.bufferedPercent = function bufferedPercent$$1() {
10019
- return bufferedPercent(this.buffered(), this.duration_);
10020
- };
10021
-
10022
- /**
10023
- * Turn off the polyfill for `progress` events that was created in
10024
- * {@link Tech#manualProgressOn}
10025
- * Stop manually tracking progress events by clearing the interval that was set in
10026
- * {@link Tech#trackProgress}.
10027
- */
10028
-
10029
-
10030
- Tech.prototype.stopTrackingProgress = function stopTrackingProgress() {
10031
- this.clearInterval(this.progressInterval);
10032
- };
10033
-
10034
- /**
10035
- * Polyfill the `timeupdate` event for browsers that don't support it.
10036
- *
10037
- * @see {@link Tech#trackCurrentTime}
10038
- */
10039
-
10040
-
10041
- Tech.prototype.manualTimeUpdatesOn = function manualTimeUpdatesOn() {
10042
- this.manualTimeUpdates = true;
10043
-
10044
- this.on('play', this.trackCurrentTime);
10045
- this.on('pause', this.stopTrackingCurrentTime);
10046
- };
10047
-
10048
- /**
10049
- * Turn off the polyfill for `timeupdate` events that was created in
10050
- * {@link Tech#manualTimeUpdatesOn}
10051
- */
10052
-
10053
-
10054
- Tech.prototype.manualTimeUpdatesOff = function manualTimeUpdatesOff() {
10055
- this.manualTimeUpdates = false;
10056
- this.stopTrackingCurrentTime();
10057
- this.off('play', this.trackCurrentTime);
10058
- this.off('pause', this.stopTrackingCurrentTime);
10059
- };
10060
-
10061
- /**
10062
- * Sets up an interval function to track current time and trigger `timeupdate` every
10063
- * 250 milliseconds.
10064
- *
10065
- * @listens Tech#play
10066
- * @triggers Tech#timeupdate
10067
- */
10068
-
10069
-
10070
- Tech.prototype.trackCurrentTime = function trackCurrentTime() {
10071
- if (this.currentTimeInterval) {
10072
- this.stopTrackingCurrentTime();
10073
- }
10074
- this.currentTimeInterval = this.setInterval(function () {
10075
- /**
10076
- * Triggered at an interval of 250ms to indicated that time is passing in the video.
10077
- *
10078
- * @event Tech#timeupdate
10079
- * @type {EventTarget~Event}
10080
- */
10081
- this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
10082
-
10083
- // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
10084
- }, 250);
10085
- };
10086
-
10087
- /**
10088
- * Stop the interval function created in {@link Tech#trackCurrentTime} so that the
10089
- * `timeupdate` event is no longer triggered.
10090
- *
10091
- * @listens {Tech#pause}
10092
- */
10093
-
10094
-
10095
- Tech.prototype.stopTrackingCurrentTime = function stopTrackingCurrentTime() {
10096
- this.clearInterval(this.currentTimeInterval);
10097
-
10098
- // #1002 - if the video ends right before the next timeupdate would happen,
10099
- // the progress bar won't make it all the way to the end
10100
- this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
10101
- };
10102
-
10103
- /**
10104
- * Turn off all event polyfills, clear the `Tech`s {@link AudioTrackList},
10105
- * {@link VideoTrackList}, and {@link TextTrackList}, and dispose of this Tech.
10106
- *
10107
- * @fires Component#dispose
10108
- */
10109
-
10110
-
10111
- Tech.prototype.dispose = function dispose() {
10112
-
10113
- // clear out all tracks because we can't reuse them between techs
10114
- this.clearTracks(NORMAL.names);
10115
-
10116
- // Turn off any manual progress or timeupdate tracking
10117
- if (this.manualProgress) {
10118
- this.manualProgressOff();
10119
- }
10120
-
10121
- if (this.manualTimeUpdates) {
10122
- this.manualTimeUpdatesOff();
10123
- }
10124
-
10125
- _Component.prototype.dispose.call(this);
10126
- };
10127
-
10128
- /**
10129
- * Clear out a single `TrackList` or an array of `TrackLists` given their names.
10130
- *
10131
- * > Note: Techs without source handlers should call this between sources for `video`
10132
- * & `audio` tracks. You don't want to use them between tracks!
10133
- *
10134
- * @param {string[]|string} types
10135
- * TrackList names to clear, valid names are `video`, `audio`, and
10136
- * `text`.
10137
- */
10138
-
10139
-
10140
- Tech.prototype.clearTracks = function clearTracks(types) {
10141
- var _this3 = this;
10142
-
10143
- types = [].concat(types);
10144
- // clear out all tracks because we can't reuse them between techs
10145
- types.forEach(function (type) {
10146
- var list = _this3[type + 'Tracks']() || [];
10147
- var i = list.length;
10148
-
10149
- while (i--) {
10150
- var track = list[i];
10151
-
10152
- if (type === 'text') {
10153
- _this3.removeRemoteTextTrack(track);
10154
- }
10155
- list.removeTrack(track);
10156
- }
10157
- });
10158
- };
10159
-
10160
- /**
10161
- * Remove any TextTracks added via addRemoteTextTrack that are
10162
- * flagged for automatic garbage collection
10163
- */
10164
-
10165
-
10166
- Tech.prototype.cleanupAutoTextTracks = function cleanupAutoTextTracks() {
10167
- var list = this.autoRemoteTextTracks_ || [];
10168
- var i = list.length;
10169
-
10170
- while (i--) {
10171
- var track = list[i];
10172
-
10173
- this.removeRemoteTextTrack(track);
10174
- }
10175
- };
10176
-
10177
- /**
10178
- * Reset the tech, which will removes all sources and reset the internal readyState.
10179
- *
10180
- * @abstract
10181
- */
10182
-
10183
-
10184
- Tech.prototype.reset = function reset() {};
10185
-
10186
- /**
10187
- * Get or set an error on the Tech.
10188
- *
10189
- * @param {MediaError} [err]
10190
- * Error to set on the Tech
10191
- *
10192
- * @return {MediaError|null}
10193
- * The current error object on the tech, or null if there isn't one.
10194
- */
10195
-
10196
-
10197
- Tech.prototype.error = function error(err) {
10198
- if (err !== undefined) {
10199
- this.error_ = new MediaError(err);
10200
- this.trigger('error');
10201
- }
10202
- return this.error_;
10203
- };
10204
-
10205
- /**
10206
- * Returns the `TimeRange`s that have been played through for the current source.
10207
- *
10208
- * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`.
10209
- * It only checks whether the source has played at all or not.
10210
- *
10211
- * @return {TimeRange}
10212
- * - A single time range if this video has played
10213
- * - An empty set of ranges if not.
10214
- */
10215
-
10216
-
10217
- Tech.prototype.played = function played() {
10218
- if (this.hasStarted_) {
10219
- return createTimeRanges(0, 0);
10220
- }
10221
- return createTimeRanges();
10222
- };
10223
-
10224
- /**
10225
- * Causes a manual time update to occur if {@link Tech#manualTimeUpdatesOn} was
10226
- * previously called.
10227
- *
10228
- * @fires Tech#timeupdate
10229
- */
10230
-
10231
-
10232
- Tech.prototype.setCurrentTime = function setCurrentTime() {
10233
- // improve the accuracy of manual timeupdates
10234
- if (this.manualTimeUpdates) {
10235
- /**
10236
- * A manual `timeupdate` event.
10237
- *
10238
- * @event Tech#timeupdate
10239
- * @type {EventTarget~Event}
10240
- */
10241
- this.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
10242
- }
10243
- };
10244
-
10245
- /**
10246
- * Turn on listeners for {@link VideoTrackList}, {@link {AudioTrackList}, and
10247
- * {@link TextTrackList} events.
10248
- *
10249
- * This adds {@link EventTarget~EventListeners} for `addtrack`, and `removetrack`.
10250
- *
10251
- * @fires Tech#audiotrackchange
10252
- * @fires Tech#videotrackchange
10253
- * @fires Tech#texttrackchange
10254
- */
10255
-
10256
-
10257
- Tech.prototype.initTrackListeners = function initTrackListeners() {
10258
- var _this4 = this;
10259
-
10260
- /**
10261
- * Triggered when tracks are added or removed on the Tech {@link AudioTrackList}
10262
- *
10263
- * @event Tech#audiotrackchange
10264
- * @type {EventTarget~Event}
10265
- */
10266
-
10267
- /**
10268
- * Triggered when tracks are added or removed on the Tech {@link VideoTrackList}
10269
- *
10270
- * @event Tech#videotrackchange
10271
- * @type {EventTarget~Event}
10272
- */
10273
-
10274
- /**
10275
- * Triggered when tracks are added or removed on the Tech {@link TextTrackList}
10276
- *
10277
- * @event Tech#texttrackchange
10278
- * @type {EventTarget~Event}
10279
- */
10280
- NORMAL.names.forEach(function (name) {
10281
- var props = NORMAL[name];
10282
- var trackListChanges = function trackListChanges() {
10283
- _this4.trigger(name + 'trackchange');
10284
- };
10285
-
10286
- var tracks = _this4[props.getterName]();
10287
-
10288
- tracks.addEventListener('removetrack', trackListChanges);
10289
- tracks.addEventListener('addtrack', trackListChanges);
10290
-
10291
- _this4.on('dispose', function () {
10292
- tracks.removeEventListener('removetrack', trackListChanges);
10293
- tracks.removeEventListener('addtrack', trackListChanges);
10294
- });
10295
- });
10296
- };
10297
-
10298
- /**
10299
- * Emulate TextTracks using vtt.js if necessary
10300
- *
10301
- * @fires Tech#vttjsloaded
10302
- * @fires Tech#vttjserror
10303
- */
10304
-
10305
-
10306
- Tech.prototype.addWebVttScript_ = function addWebVttScript_() {
10307
- var _this5 = this;
10308
-
10309
- if (window_1.WebVTT) {
10310
- return;
10311
- }
10312
-
10313
- // Initially, Tech.el_ is a child of a dummy-div wait until the Component system
10314
- // signals that the Tech is ready at which point Tech.el_ is part of the DOM
10315
- // before inserting the WebVTT script
10316
- if (document_1.body.contains(this.el())) {
10317
-
10318
- // load via require if available and vtt.js script location was not passed in
10319
- // as an option. novtt builds will turn the above require call into an empty object
10320
- // which will cause this if check to always fail.
10321
- if (!this.options_['vtt.js'] && isPlain(browserIndex) && Object.keys(browserIndex).length > 0) {
10322
- this.trigger('vttjsloaded');
10323
- return;
10324
- }
10325
-
10326
- // load vtt.js via the script location option or the cdn of no location was
10327
- // passed in
10328
- var script = document_1.createElement('script');
10329
-
10330
- script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.14.1/vtt.min.js';
10331
- script.onload = function () {
10332
- /**
10333
- * Fired when vtt.js is loaded.
10334
- *
10335
- * @event Tech#vttjsloaded
10336
- * @type {EventTarget~Event}
10337
- */
10338
- _this5.trigger('vttjsloaded');
10339
- };
10340
- script.onerror = function () {
10341
- /**
10342
- * Fired when vtt.js was not loaded due to an error
10343
- *
10344
- * @event Tech#vttjsloaded
10345
- * @type {EventTarget~Event}
10346
- */
10347
- _this5.trigger('vttjserror');
10348
- };
10349
- this.on('dispose', function () {
10350
- script.onload = null;
10351
- script.onerror = null;
10352
- });
10353
- // but have not loaded yet and we set it to true before the inject so that
10354
- // we don't overwrite the injected window.WebVTT if it loads right away
10355
- window_1.WebVTT = true;
10356
- this.el().parentNode.appendChild(script);
10357
- } else {
10358
- this.ready(this.addWebVttScript_);
10359
- }
10360
- };
10361
-
10362
- /**
10363
- * Emulate texttracks
10364
- *
10365
- */
10366
-
10367
-
10368
- Tech.prototype.emulateTextTracks = function emulateTextTracks() {
10369
- var _this6 = this;
10370
-
10371
- var tracks = this.textTracks();
10372
- var remoteTracks = this.remoteTextTracks();
10373
- var handleAddTrack = function handleAddTrack(e) {
10374
- return tracks.addTrack(e.track);
10375
- };
10376
- var handleRemoveTrack = function handleRemoveTrack(e) {
10377
- return tracks.removeTrack(e.track);
10378
- };
10379
-
10380
- remoteTracks.on('addtrack', handleAddTrack);
10381
- remoteTracks.on('removetrack', handleRemoveTrack);
10382
-
10383
- this.addWebVttScript_();
10384
-
10385
- var updateDisplay = function updateDisplay() {
10386
- return _this6.trigger('texttrackchange');
10387
- };
10388
-
10389
- var textTracksChanges = function textTracksChanges() {
10390
- updateDisplay();
10391
-
10392
- for (var i = 0; i < tracks.length; i++) {
10393
- var track = tracks[i];
10394
-
10395
- track.removeEventListener('cuechange', updateDisplay);
10396
- if (track.mode === 'showing') {
10397
- track.addEventListener('cuechange', updateDisplay);
10398
- }
10399
- }
10400
- };
10401
-
10402
- textTracksChanges();
10403
- tracks.addEventListener('change', textTracksChanges);
10404
- tracks.addEventListener('addtrack', textTracksChanges);
10405
- tracks.addEventListener('removetrack', textTracksChanges);
10406
-
10407
- this.on('dispose', function () {
10408
- remoteTracks.off('addtrack', handleAddTrack);
10409
- remoteTracks.off('removetrack', handleRemoveTrack);
10410
- tracks.removeEventListener('change', textTracksChanges);
10411
- tracks.removeEventListener('addtrack', textTracksChanges);
10412
- tracks.removeEventListener('removetrack', textTracksChanges);
10413
-
10414
- for (var i = 0; i < tracks.length; i++) {
10415
- var track = tracks[i];
10416
-
10417
- track.removeEventListener('cuechange', updateDisplay);
10418
- }
10419
- });
10420
- };
10421
-
10422
- /**
10423
- * Create and returns a remote {@link TextTrack} object.
10424
- *
10425
- * @param {string} kind
10426
- * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
10427
- *
10428
- * @param {string} [label]
10429
- * Label to identify the text track
10430
- *
10431
- * @param {string} [language]
10432
- * Two letter language abbreviation
10433
- *
10434
- * @return {TextTrack}
10435
- * The TextTrack that gets created.
10436
- */
10437
-
10438
-
10439
- Tech.prototype.addTextTrack = function addTextTrack(kind, label, language) {
10440
- if (!kind) {
10441
- throw new Error('TextTrack kind is required but was not provided');
10442
- }
10443
-
10444
- return createTrackHelper(this, kind, label, language);
10445
- };
10446
-
10447
- /**
10448
- * Create an emulated TextTrack for use by addRemoteTextTrack
10449
- *
10450
- * This is intended to be overridden by classes that inherit from
10451
- * Tech in order to create native or custom TextTracks.
10452
- *
10453
- * @param {Object} options
10454
- * The object should contain the options to initialize the TextTrack with.
10455
- *
10456
- * @param {string} [options.kind]
10457
- * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
10458
- *
10459
- * @param {string} [options.label].
10460
- * Label to identify the text track
10461
- *
10462
- * @param {string} [options.language]
10463
- * Two letter language abbreviation.
10464
- *
10465
- * @return {HTMLTrackElement}
10466
- * The track element that gets created.
10467
- */
10468
-
10469
-
10470
- Tech.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
10471
- var track = mergeOptions(options, {
10472
- tech: this
10473
- });
10474
-
10475
- return new REMOTE.remoteTextEl.TrackClass(track);
10476
- };
10477
-
10478
- /**
10479
- * Creates a remote text track object and returns an html track element.
10480
- *
10481
- * > Note: This can be an emulated {@link HTMLTrackElement} or a native one.
10482
- *
10483
- * @param {Object} options
10484
- * See {@link Tech#createRemoteTextTrack} for more detailed properties.
10485
- *
10486
- * @param {boolean} [manualCleanup=true]
10487
- * - When false: the TextTrack will be automatically removed from the video
10488
- * element whenever the source changes
10489
- * - When True: The TextTrack will have to be cleaned up manually
10490
- *
10491
- * @return {HTMLTrackElement}
10492
- * An Html Track Element.
10493
- *
10494
- * @deprecated The default functionality for this function will be equivalent
10495
- * to "manualCleanup=false" in the future. The manualCleanup parameter will
10496
- * also be removed.
10497
- */
10498
-
10499
-
10500
- Tech.prototype.addRemoteTextTrack = function addRemoteTextTrack() {
10501
- var _this7 = this;
10502
-
10503
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
10504
- var manualCleanup = arguments[1];
10505
-
10506
- var htmlTrackElement = this.createRemoteTextTrack(options);
10507
-
10508
- if (manualCleanup !== true && manualCleanup !== false) {
10509
- // deprecation warning
10510
- log$1.warn('Calling addRemoteTextTrack without explicitly setting the "manualCleanup" parameter to `true` is deprecated and default to `false` in future version of video.js');
10511
- manualCleanup = true;
10512
- }
10513
-
10514
- // store HTMLTrackElement and TextTrack to remote list
10515
- this.remoteTextTrackEls().addTrackElement_(htmlTrackElement);
10516
- this.remoteTextTracks().addTrack(htmlTrackElement.track);
10517
-
10518
- if (manualCleanup !== true) {
10519
- // create the TextTrackList if it doesn't exist
10520
- this.ready(function () {
10521
- return _this7.autoRemoteTextTracks_.addTrack(htmlTrackElement.track);
10522
- });
10523
- }
10524
-
10525
- return htmlTrackElement;
10526
- };
10527
-
10528
- /**
10529
- * Remove a remote text track from the remote `TextTrackList`.
10530
- *
10531
- * @param {TextTrack} track
10532
- * `TextTrack` to remove from the `TextTrackList`
10533
- */
10534
-
10535
-
10536
- Tech.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
10537
- var trackElement = this.remoteTextTrackEls().getTrackElementByTrack_(track);
10538
-
10539
- // remove HTMLTrackElement and TextTrack from remote list
10540
- this.remoteTextTrackEls().removeTrackElement_(trackElement);
10541
- this.remoteTextTracks().removeTrack(track);
10542
- this.autoRemoteTextTracks_.removeTrack(track);
10543
- };
10544
-
10545
- /**
10546
- * Gets available media playback quality metrics as specified by the W3C's Media
10547
- * Playback Quality API.
10548
- *
10549
- * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
10550
- *
10551
- * @return {Object}
10552
- * An object with supported media playback quality metrics
10553
- *
10554
- * @abstract
10555
- */
10556
-
10557
-
10558
- Tech.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
10559
- return {};
10560
- };
10561
-
10562
- /**
10563
- * A method to set a poster from a `Tech`.
10564
- *
10565
- * @abstract
10566
- */
10567
-
10568
-
10569
- Tech.prototype.setPoster = function setPoster() {};
10570
-
10571
- /**
10572
- * A method to check for the presence of the 'playsinline' <video> attribute.
10573
- *
10574
- * @abstract
10575
- */
10576
-
10577
-
10578
- Tech.prototype.playsinline = function playsinline() {};
10579
-
10580
- /**
10581
- * A method to set or unset the 'playsinline' <video> attribute.
10582
- *
10583
- * @abstract
10584
- */
10585
-
10586
-
10587
- Tech.prototype.setPlaysinline = function setPlaysinline() {};
10588
-
10589
- /**
10590
- * Attempt to force override of native audio tracks.
10591
- *
10592
- * @param {Boolean} override - If set to true native audio will be overridden,
10593
- * otherwise native audio will potentially be used.
10594
- *
10595
- * @abstract
10596
- */
10597
-
10598
-
10599
- Tech.prototype.overrideNativeAudioTracks = function overrideNativeAudioTracks() {};
10600
-
10601
- /**
10602
- * Attempt to force override of native video tracks.
10603
- *
10604
- * @param {Boolean} override - If set to true native video will be overridden,
10605
- * otherwise native video will potentially be used.
10606
- *
10607
- * @abstract
10608
- */
10609
-
10610
-
10611
- Tech.prototype.overrideNativeVideoTracks = function overrideNativeVideoTracks() {};
10612
-
10613
- /*
10614
- * Check if the tech can support the given mime-type.
10615
- *
10616
- * The base tech does not support any type, but source handlers might
10617
- * overwrite this.
10618
- *
10619
- * @param {string} type
10620
- * The mimetype to check for support
10621
- *
10622
- * @return {string}
10623
- * 'probably', 'maybe', or empty string
10624
- *
10625
- * @see [Spec]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canPlayType}
10626
- *
10627
- * @abstract
10628
- */
10629
-
10630
-
10631
- Tech.prototype.canPlayType = function canPlayType() {
10632
- return '';
10633
- };
10634
-
10635
- /**
10636
- * Check if the type is supported by this tech.
10637
- *
10638
- * The base tech does not support any type, but source handlers might
10639
- * overwrite this.
10640
- *
10641
- * @param {string} type
10642
- * The media type to check
10643
- * @return {string} Returns the native video element's response
10644
- */
10645
-
10646
-
10647
- Tech.canPlayType = function canPlayType() {
10648
- return '';
10649
- };
10650
-
10651
- /**
10652
- * Check if the tech can support the given source
10653
- * @param {Object} srcObj
10654
- * The source object
10655
- * @param {Object} options
10656
- * The options passed to the tech
10657
- * @return {string} 'probably', 'maybe', or '' (empty string)
10658
- */
10659
-
10660
-
10661
- Tech.canPlaySource = function canPlaySource(srcObj, options) {
10662
- return Tech.canPlayType(srcObj.type);
10663
- };
10664
-
10665
- /*
10666
- * Return whether the argument is a Tech or not.
10667
- * Can be passed either a Class like `Html5` or a instance like `player.tech_`
10668
- *
10669
- * @param {Object} component
10670
- * The item to check
10671
- *
10672
- * @return {boolean}
10673
- * Whether it is a tech or not
10674
- * - True if it is a tech
10675
- * - False if it is not
10676
- */
10677
-
10678
-
10679
- Tech.isTech = function isTech(component) {
10680
- return component.prototype instanceof Tech || component instanceof Tech || component === Tech;
10681
- };
10682
-
10683
- /**
10684
- * Registers a `Tech` into a shared list for videojs.
10685
- *
10686
- * @param {string} name
10687
- * Name of the `Tech` to register.
10688
- *
10689
- * @param {Object} tech
10690
- * The `Tech` class to register.
10691
- */
10692
-
10693
-
10694
- Tech.registerTech = function registerTech(name, tech) {
10695
- if (!Tech.techs_) {
10696
- Tech.techs_ = {};
10697
- }
10698
-
10699
- if (!Tech.isTech(tech)) {
10700
- throw new Error('Tech ' + name + ' must be a Tech');
10701
- }
10702
-
10703
- if (!Tech.canPlayType) {
10704
- throw new Error('Techs must have a static canPlayType method on them');
10705
- }
10706
- if (!Tech.canPlaySource) {
10707
- throw new Error('Techs must have a static canPlaySource method on them');
10708
- }
10709
-
10710
- name = toTitleCase(name);
10711
-
10712
- Tech.techs_[name] = tech;
10713
- if (name !== 'Tech') {
10714
- // camel case the techName for use in techOrder
10715
- Tech.defaultTechOrder_.push(name);
10716
- }
10717
- return tech;
10718
- };
10719
-
10720
- /**
10721
- * Get a `Tech` from the shared list by name.
10722
- *
10723
- * @param {string} name
10724
- * `camelCase` or `TitleCase` name of the Tech to get
10725
- *
10726
- * @return {Tech|undefined}
10727
- * The `Tech` or undefined if there was no tech with the name requested.
10728
- */
10729
-
10730
-
10731
- Tech.getTech = function getTech(name) {
10732
- if (!name) {
10733
- return;
10734
- }
10735
-
10736
- name = toTitleCase(name);
10737
-
10738
- if (Tech.techs_ && Tech.techs_[name]) {
10739
- return Tech.techs_[name];
10740
- }
10741
-
10742
- if (window_1 && window_1.videojs && window_1.videojs[name]) {
10743
- log$1.warn('The ' + name + ' tech was added to the videojs object when it should be registered using videojs.registerTech(name, tech)');
10744
- return window_1.videojs[name];
10745
- }
10746
- };
10747
-
10748
- return Tech;
10749
- }(Component);
10750
-
10751
- /**
10752
- * Get the {@link VideoTrackList}
10753
- *
10754
- * @returns {VideoTrackList}
10755
- * @method Tech.prototype.videoTracks
10756
- */
10757
-
10758
- /**
10759
- * Get the {@link AudioTrackList}
10760
- *
10761
- * @returns {AudioTrackList}
10762
- * @method Tech.prototype.audioTracks
10763
- */
10764
-
10765
- /**
10766
- * Get the {@link TextTrackList}
10767
- *
10768
- * @returns {TextTrackList}
10769
- * @method Tech.prototype.textTracks
10770
- */
10771
-
10772
- /**
10773
- * Get the remote element {@link TextTrackList}
10774
- *
10775
- * @returns {TextTrackList}
10776
- * @method Tech.prototype.remoteTextTracks
10777
- */
10778
-
10779
- /**
10780
- * Get the remote element {@link HtmlTrackElementList}
10781
- *
10782
- * @returns {HtmlTrackElementList}
10783
- * @method Tech.prototype.remoteTextTrackEls
10784
- */
10785
-
10786
- ALL.names.forEach(function (name) {
10787
- var props = ALL[name];
10788
-
10789
- Tech.prototype[props.getterName] = function () {
10790
- this[props.privateName] = this[props.privateName] || new props.ListClass();
10791
- return this[props.privateName];
10792
- };
10793
- });
10794
-
10795
- /**
10796
- * List of associated text tracks
10797
- *
10798
- * @type {TextTrackList}
10799
- * @private
10800
- * @property Tech#textTracks_
10801
- */
10802
-
10803
- /**
10804
- * List of associated audio tracks.
10805
- *
10806
- * @type {AudioTrackList}
10807
- * @private
10808
- * @property Tech#audioTracks_
10809
- */
10810
-
10811
- /**
10812
- * List of associated video tracks.
10813
- *
10814
- * @type {VideoTrackList}
10815
- * @private
10816
- * @property Tech#videoTracks_
10817
- */
10818
-
10819
- /**
10820
- * Boolean indicating whether the `Tech` supports volume control.
10821
- *
10822
- * @type {boolean}
10823
- * @default
10824
- */
10825
- Tech.prototype.featuresVolumeControl = true;
10826
-
10827
- /**
10828
- * Boolean indicating whether the `Tech` supports muting volume.
10829
- *
10830
- * @type {bolean}
10831
- * @default
10832
- */
10833
- Tech.prototype.featuresMuteControl = true;
10834
-
10835
- /**
10836
- * Boolean indicating whether the `Tech` supports fullscreen resize control.
10837
- * Resizing plugins using request fullscreen reloads the plugin
10838
- *
10839
- * @type {boolean}
10840
- * @default
10841
- */
10842
- Tech.prototype.featuresFullscreenResize = false;
10843
-
10844
- /**
10845
- * Boolean indicating whether the `Tech` supports changing the speed at which the video
10846
- * plays. Examples:
10847
- * - Set player to play 2x (twice) as fast
10848
- * - Set player to play 0.5x (half) as fast
10849
- *
10850
- * @type {boolean}
10851
- * @default
10852
- */
10853
- Tech.prototype.featuresPlaybackRate = false;
10854
-
10855
- /**
10856
- * Boolean indicating whether the `Tech` supports the `progress` event. This is currently
10857
- * not triggered by video-js-swf. This will be used to determine if
10858
- * {@link Tech#manualProgressOn} should be called.
10859
- *
10860
- * @type {boolean}
10861
- * @default
10862
- */
10863
- Tech.prototype.featuresProgressEvents = false;
10864
-
10865
- /**
10866
- * Boolean indicating whether the `Tech` supports the `sourceset` event.
10867
- *
10868
- * A tech should set this to `true` and then use {@link Tech#triggerSourceset}
10869
- * to trigger a {@link Tech#event:sourceset} at the earliest time after getting
10870
- * a new source.
10871
- *
10872
- * @type {boolean}
10873
- * @default
10874
- */
10875
- Tech.prototype.featuresSourceset = false;
10876
-
10877
- /**
10878
- * Boolean indicating whether the `Tech` supports the `timeupdate` event. This is currently
10879
- * not triggered by video-js-swf. This will be used to determine if
10880
- * {@link Tech#manualTimeUpdates} should be called.
10881
- *
10882
- * @type {boolean}
10883
- * @default
10884
- */
10885
- Tech.prototype.featuresTimeupdateEvents = false;
10886
-
10887
- /**
10888
- * Boolean indicating whether the `Tech` supports the native `TextTrack`s.
10889
- * This will help us integrate with native `TextTrack`s if the browser supports them.
10890
- *
10891
- * @type {boolean}
10892
- * @default
10893
- */
10894
- Tech.prototype.featuresNativeTextTracks = false;
10895
-
10896
- /**
10897
- * A functional mixin for techs that want to use the Source Handler pattern.
10898
- * Source handlers are scripts for handling specific formats.
10899
- * The source handler pattern is used for adaptive formats (HLS, DASH) that
10900
- * manually load video data and feed it into a Source Buffer (Media Source Extensions)
10901
- * Example: `Tech.withSourceHandlers.call(MyTech);`
10902
- *
10903
- * @param {Tech} _Tech
10904
- * The tech to add source handler functions to.
10905
- *
10906
- * @mixes Tech~SourceHandlerAdditions
10907
- */
10908
- Tech.withSourceHandlers = function (_Tech) {
10909
-
10910
- /**
10911
- * Register a source handler
10912
- *
10913
- * @param {Function} handler
10914
- * The source handler class
10915
- *
10916
- * @param {number} [index]
10917
- * Register it at the following index
10918
- */
10919
- _Tech.registerSourceHandler = function (handler, index) {
10920
- var handlers = _Tech.sourceHandlers;
10921
-
10922
- if (!handlers) {
10923
- handlers = _Tech.sourceHandlers = [];
10924
- }
10925
-
10926
- if (index === undefined) {
10927
- // add to the end of the list
10928
- index = handlers.length;
10929
- }
10930
-
10931
- handlers.splice(index, 0, handler);
10932
- };
10933
-
10934
- /**
10935
- * Check if the tech can support the given type. Also checks the
10936
- * Techs sourceHandlers.
10937
- *
10938
- * @param {string} type
10939
- * The mimetype to check.
10940
- *
10941
- * @return {string}
10942
- * 'probably', 'maybe', or '' (empty string)
10943
- */
10944
- _Tech.canPlayType = function (type) {
10945
- var handlers = _Tech.sourceHandlers || [];
10946
- var can = void 0;
10947
-
10948
- for (var i = 0; i < handlers.length; i++) {
10949
- can = handlers[i].canPlayType(type);
10950
-
10951
- if (can) {
10952
- return can;
10953
- }
10954
- }
10955
-
10956
- return '';
10957
- };
10958
-
10959
- /**
10960
- * Returns the first source handler that supports the source.
10961
- *
10962
- * TODO: Answer question: should 'probably' be prioritized over 'maybe'
10963
- *
10964
- * @param {Tech~SourceObject} source
10965
- * The source object
10966
- *
10967
- * @param {Object} options
10968
- * The options passed to the tech
10969
- *
10970
- * @return {SourceHandler|null}
10971
- * The first source handler that supports the source or null if
10972
- * no SourceHandler supports the source
10973
- */
10974
- _Tech.selectSourceHandler = function (source, options) {
10975
- var handlers = _Tech.sourceHandlers || [];
10976
- var can = void 0;
10977
-
10978
- for (var i = 0; i < handlers.length; i++) {
10979
- can = handlers[i].canHandleSource(source, options);
10980
-
10981
- if (can) {
10982
- return handlers[i];
10983
- }
10984
- }
10985
-
10986
- return null;
10987
- };
10988
-
10989
- /**
10990
- * Check if the tech can support the given source.
10991
- *
10992
- * @param {Tech~SourceObject} srcObj
10993
- * The source object
10994
- *
10995
- * @param {Object} options
10996
- * The options passed to the tech
10997
- *
10998
- * @return {string}
10999
- * 'probably', 'maybe', or '' (empty string)
11000
- */
11001
- _Tech.canPlaySource = function (srcObj, options) {
11002
- var sh = _Tech.selectSourceHandler(srcObj, options);
11003
-
11004
- if (sh) {
11005
- return sh.canHandleSource(srcObj, options);
11006
- }
11007
-
11008
- return '';
11009
- };
11010
-
11011
- /**
11012
- * When using a source handler, prefer its implementation of
11013
- * any function normally provided by the tech.
11014
- */
11015
- var deferrable = ['seekable', 'seeking', 'duration'];
11016
-
11017
- /**
11018
- * A wrapper around {@link Tech#seekable} that will call a `SourceHandler`s seekable
11019
- * function if it exists, with a fallback to the Techs seekable function.
11020
- *
11021
- * @method _Tech.seekable
11022
- */
11023
-
11024
- /**
11025
- * A wrapper around {@link Tech#duration} that will call a `SourceHandler`s duration
11026
- * function if it exists, otherwise it will fallback to the techs duration function.
11027
- *
11028
- * @method _Tech.duration
11029
- */
11030
-
11031
- deferrable.forEach(function (fnName) {
11032
- var originalFn = this[fnName];
11033
-
11034
- if (typeof originalFn !== 'function') {
11035
- return;
11036
- }
11037
-
11038
- this[fnName] = function () {
11039
- if (this.sourceHandler_ && this.sourceHandler_[fnName]) {
11040
- return this.sourceHandler_[fnName].apply(this.sourceHandler_, arguments);
11041
- }
11042
- return originalFn.apply(this, arguments);
11043
- };
11044
- }, _Tech.prototype);
11045
-
11046
- /**
11047
- * Create a function for setting the source using a source object
11048
- * and source handlers.
11049
- * Should never be called unless a source handler was found.
11050
- *
11051
- * @param {Tech~SourceObject} source
11052
- * A source object with src and type keys
11053
- */
11054
- _Tech.prototype.setSource = function (source) {
11055
- var sh = _Tech.selectSourceHandler(source, this.options_);
11056
-
11057
- if (!sh) {
11058
- // Fall back to a native source hander when unsupported sources are
11059
- // deliberately set
11060
- if (_Tech.nativeSourceHandler) {
11061
- sh = _Tech.nativeSourceHandler;
11062
- } else {
11063
- log$1.error('No source handler found for the current source.');
11064
- }
11065
- }
11066
-
11067
- // Dispose any existing source handler
11068
- this.disposeSourceHandler();
11069
- this.off('dispose', this.disposeSourceHandler);
11070
-
11071
- if (sh !== _Tech.nativeSourceHandler) {
11072
- this.currentSource_ = source;
11073
- }
11074
-
11075
- this.sourceHandler_ = sh.handleSource(source, this, this.options_);
11076
- this.on('dispose', this.disposeSourceHandler);
11077
- };
11078
-
11079
- /**
11080
- * Clean up any existing SourceHandlers and listeners when the Tech is disposed.
11081
- *
11082
- * @listens Tech#dispose
11083
- */
11084
- _Tech.prototype.disposeSourceHandler = function () {
11085
- // if we have a source and get another one
11086
- // then we are loading something new
11087
- // than clear all of our current tracks
11088
- if (this.currentSource_) {
11089
- this.clearTracks(['audio', 'video']);
11090
- this.currentSource_ = null;
11091
- }
11092
-
11093
- // always clean up auto-text tracks
11094
- this.cleanupAutoTextTracks();
11095
-
11096
- if (this.sourceHandler_) {
11097
-
11098
- if (this.sourceHandler_.dispose) {
11099
- this.sourceHandler_.dispose();
11100
- }
11101
-
11102
- this.sourceHandler_ = null;
11103
- }
11104
- };
11105
- };
11106
-
11107
- // The base Tech class needs to be registered as a Component. It is the only
11108
- // Tech that can be registered as a Component.
11109
- Component.registerComponent('Tech', Tech);
11110
- Tech.registerTech('Tech', Tech);
11111
-
11112
- /**
11113
- * A list of techs that should be added to techOrder on Players
11114
- *
11115
- * @private
11116
- */
11117
- Tech.defaultTechOrder_ = [];
11118
-
11119
- var middlewares = {};
11120
- var middlewareInstances = {};
11121
-
11122
- var TERMINATOR = {};
11123
-
11124
- function use(type, middleware) {
11125
- middlewares[type] = middlewares[type] || [];
11126
- middlewares[type].push(middleware);
11127
- }
11128
-
11129
- function setSource(player, src, next) {
11130
- player.setTimeout(function () {
11131
- return setSourceHelper(src, middlewares[src.type], next, player);
11132
- }, 1);
11133
- }
11134
-
11135
- function setTech(middleware, tech) {
11136
- middleware.forEach(function (mw) {
11137
- return mw.setTech && mw.setTech(tech);
11138
- });
11139
- }
11140
-
11141
- /**
11142
- * Calls a getter on the tech first, through each middleware
11143
- * from right to left to the player.
11144
- */
11145
- function get$1(middleware, tech, method) {
11146
- return middleware.reduceRight(middlewareIterator(method), tech[method]());
11147
- }
11148
-
11149
- /**
11150
- * Takes the argument given to the player and calls the setter method on each
11151
- * middleware from left to right to the tech.
11152
- */
11153
- function set$1(middleware, tech, method, arg) {
11154
- return tech[method](middleware.reduce(middlewareIterator(method), arg));
11155
- }
11156
-
11157
- /**
11158
- * Takes the argument given to the player and calls the `call` version of the method
11159
- * on each middleware from left to right.
11160
- * Then, call the passed in method on the tech and return the result unchanged
11161
- * back to the player, through middleware, this time from right to left.
11162
- */
11163
- function mediate(middleware, tech, method) {
11164
- var arg = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
11165
-
11166
- var callMethod = 'call' + toTitleCase(method);
11167
- var middlewareValue = middleware.reduce(middlewareIterator(callMethod), arg);
11168
- var terminated = middlewareValue === TERMINATOR;
11169
- var returnValue = terminated ? null : tech[method](middlewareValue);
11170
-
11171
- executeRight(middleware, method, returnValue, terminated);
11172
-
11173
- return returnValue;
11174
- }
11175
-
11176
- var allowedGetters = {
11177
- buffered: 1,
11178
- currentTime: 1,
11179
- duration: 1,
11180
- seekable: 1,
11181
- played: 1,
11182
- paused: 1
11183
- };
11184
-
11185
- var allowedSetters = {
11186
- setCurrentTime: 1
11187
- };
11188
-
11189
- var allowedMediators = {
11190
- play: 1,
11191
- pause: 1
11192
- };
11193
-
11194
- function middlewareIterator(method) {
11195
- return function (value, mw) {
11196
- // if the previous middleware terminated, pass along the termination
11197
- if (value === TERMINATOR) {
11198
- return TERMINATOR;
11199
- }
11200
-
11201
- if (mw[method]) {
11202
- return mw[method](value);
11203
- }
11204
-
11205
- return value;
11206
- };
11207
- }
11208
-
11209
- function executeRight(mws, method, value, terminated) {
11210
- for (var i = mws.length - 1; i >= 0; i--) {
11211
- var mw = mws[i];
11212
-
11213
- if (mw[method]) {
11214
- mw[method](terminated, value);
11215
- }
11216
- }
11217
- }
11218
-
11219
- function clearCacheForPlayer(player) {
11220
- middlewareInstances[player.id()] = null;
11221
- }
11222
-
11223
- /**
11224
- * {
11225
- * [playerId]: [[mwFactory, mwInstance], ...]
11226
- * }
11227
- */
11228
- function getOrCreateFactory(player, mwFactory) {
11229
- var mws = middlewareInstances[player.id()];
11230
- var mw = null;
11231
-
11232
- if (mws === undefined || mws === null) {
11233
- mw = mwFactory(player);
11234
- middlewareInstances[player.id()] = [[mwFactory, mw]];
11235
- return mw;
11236
- }
11237
-
11238
- for (var i = 0; i < mws.length; i++) {
11239
- var _mws$i = mws[i],
11240
- mwf = _mws$i[0],
11241
- mwi = _mws$i[1];
11242
-
11243
-
11244
- if (mwf !== mwFactory) {
11245
- continue;
11246
- }
11247
-
11248
- mw = mwi;
11249
- }
11250
-
11251
- if (mw === null) {
11252
- mw = mwFactory(player);
11253
- mws.push([mwFactory, mw]);
11254
- }
11255
-
11256
- return mw;
11257
- }
11258
-
11259
- function setSourceHelper() {
11260
- var src = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
11261
- var middleware = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
11262
- var next = arguments[2];
11263
- var player = arguments[3];
11264
- var acc = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : [];
11265
- var lastRun = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false;
11266
- var mwFactory = middleware[0],
11267
- mwrest = middleware.slice(1);
11268
-
11269
- // if mwFactory is a string, then we're at a fork in the road
11270
-
11271
- if (typeof mwFactory === 'string') {
11272
- setSourceHelper(src, middlewares[mwFactory], next, player, acc, lastRun);
11273
-
11274
- // if we have an mwFactory, call it with the player to get the mw,
11275
- // then call the mw's setSource method
11276
- } else if (mwFactory) {
11277
- var mw = getOrCreateFactory(player, mwFactory);
11278
-
11279
- // if setSource isn't present, implicitly select this middleware
11280
- if (!mw.setSource) {
11281
- acc.push(mw);
11282
- return setSourceHelper(src, mwrest, next, player, acc, lastRun);
11283
- }
11284
-
11285
- mw.setSource(assign({}, src), function (err, _src) {
11286
-
11287
- // something happened, try the next middleware on the current level
11288
- // make sure to use the old src
11289
- if (err) {
11290
- return setSourceHelper(src, mwrest, next, player, acc, lastRun);
11291
- }
11292
-
11293
- // we've succeeded, now we need to go deeper
11294
- acc.push(mw);
11295
-
11296
- // if it's the same type, continue down the current chain
11297
- // otherwise, we want to go down the new chain
11298
- setSourceHelper(_src, src.type === _src.type ? mwrest : middlewares[_src.type], next, player, acc, lastRun);
11299
- });
11300
- } else if (mwrest.length) {
11301
- setSourceHelper(src, mwrest, next, player, acc, lastRun);
11302
- } else if (lastRun) {
11303
- next(src, acc);
11304
- } else {
11305
- setSourceHelper(src, middlewares['*'], next, player, acc, true);
11306
- }
11307
- }
11308
-
11309
- /**
11310
- * Mimetypes
11311
- *
11312
- * @see http://hul.harvard.edu/ois/////systems/wax/wax-public-help/mimetypes.htm
11313
- * @typedef Mimetypes~Kind
11314
- * @enum
11315
- */
11316
- var MimetypesKind = {
11317
- opus: 'video/ogg',
11318
- ogv: 'video/ogg',
11319
- mp4: 'video/mp4',
11320
- mov: 'video/mp4',
11321
- m4v: 'video/mp4',
11322
- mkv: 'video/x-matroska',
11323
- mp3: 'audio/mpeg',
11324
- aac: 'audio/aac',
11325
- oga: 'audio/ogg',
11326
- m3u8: 'application/x-mpegURL'
11327
- };
11328
-
11329
- /**
11330
- * Get the mimetype of a given src url if possible
11331
- *
11332
- * @param {string} src
11333
- * The url to the src
11334
- *
11335
- * @return {string}
11336
- * return the mimetype if it was known or empty string otherwise
11337
- */
11338
- var getMimetype = function getMimetype() {
11339
- var src = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
11340
-
11341
- var ext = getFileExtension(src);
11342
- var mimetype = MimetypesKind[ext.toLowerCase()];
11343
-
11344
- return mimetype || '';
11345
- };
11346
-
11347
- /**
11348
- * Find the mime type of a given source string if possible. Uses the player
11349
- * source cache.
11350
- *
11351
- * @param {Player} player
11352
- * The player object
11353
- *
11354
- * @param {string} src
11355
- * The source string
11356
- *
11357
- * @return {string}
11358
- * The type that was found
11359
- */
11360
- var findMimetype = function findMimetype(player, src) {
11361
- if (!src) {
11362
- return '';
11363
- }
11364
-
11365
- // 1. check for the type in the `source` cache
11366
- if (player.cache_.source.src === src && player.cache_.source.type) {
11367
- return player.cache_.source.type;
11368
- }
11369
-
11370
- // 2. see if we have this source in our `currentSources` cache
11371
- var matchingSources = player.cache_.sources.filter(function (s) {
11372
- return s.src === src;
11373
- });
11374
-
11375
- if (matchingSources.length) {
11376
- return matchingSources[0].type;
11377
- }
11378
-
11379
- // 3. look for the src url in source elements and use the type there
11380
- var sources = player.$$('source');
11381
-
11382
- for (var i = 0; i < sources.length; i++) {
11383
- var s = sources[i];
11384
-
11385
- if (s.type && s.src && s.src === src) {
11386
- return s.type;
11387
- }
11388
- }
11389
-
11390
- // 4. finally fallback to our list of mime types based on src url extension
11391
- return getMimetype(src);
11392
- };
11393
-
11394
- /**
11395
- * @module filter-source
11396
- */
11397
-
11398
- /**
11399
- * Filter out single bad source objects or multiple source objects in an
11400
- * array. Also flattens nested source object arrays into a 1 dimensional
11401
- * array of source objects.
11402
- *
11403
- * @param {Tech~SourceObject|Tech~SourceObject[]} src
11404
- * The src object to filter
11405
- *
11406
- * @return {Tech~SourceObject[]}
11407
- * An array of sourceobjects containing only valid sources
11408
- *
11409
- * @private
11410
- */
11411
- var filterSource = function filterSource(src) {
11412
- // traverse array
11413
- if (Array.isArray(src)) {
11414
- var newsrc = [];
11415
-
11416
- src.forEach(function (srcobj) {
11417
- srcobj = filterSource(srcobj);
11418
-
11419
- if (Array.isArray(srcobj)) {
11420
- newsrc = newsrc.concat(srcobj);
11421
- } else if (isObject(srcobj)) {
11422
- newsrc.push(srcobj);
11423
- }
11424
- });
11425
-
11426
- src = newsrc;
11427
- } else if (typeof src === 'string' && src.trim()) {
11428
- // convert string into object
11429
- src = [fixSource({ src: src })];
11430
- } else if (isObject(src) && typeof src.src === 'string' && src.src && src.src.trim()) {
11431
- // src is already valid
11432
- src = [fixSource(src)];
11433
- } else {
11434
- // invalid source, turn it into an empty array
11435
- src = [];
11436
- }
11437
-
11438
- return src;
11439
- };
11440
-
11441
- /**
11442
- * Checks src mimetype, adding it when possible
11443
- *
11444
- * @param {Tech~SourceObject} src
11445
- * The src object to check
11446
- * @return {Tech~SourceObject}
11447
- * src Object with known type
11448
- */
11449
- function fixSource(src) {
11450
- var mimetype = getMimetype(src.src);
11451
-
11452
- if (!src.type && mimetype) {
11453
- src.type = mimetype;
11454
- }
11455
-
11456
- return src;
11457
- }
11458
-
11459
- /**
11460
- * @file loader.js
11461
- */
11462
-
11463
- /**
11464
- * The `MediaLoader` is the `Component` that decides which playback technology to load
11465
- * when a player is initialized.
11466
- *
11467
- * @extends Component
11468
- */
11469
-
11470
- var MediaLoader = function (_Component) {
11471
- inherits(MediaLoader, _Component);
11472
-
11473
- /**
11474
- * Create an instance of this class.
11475
- *
11476
- * @param {Player} player
11477
- * The `Player` that this class should attach to.
11478
- *
11479
- * @param {Object} [options]
11480
- * The key/value store of player options.
11481
- *
11482
- * @param {Component~ReadyCallback} [ready]
11483
- * The function that is run when this component is ready.
11484
- */
11485
- function MediaLoader(player, options, ready) {
11486
- classCallCheck(this, MediaLoader);
11487
-
11488
- // MediaLoader has no element
11489
- var options_ = mergeOptions({ createEl: false }, options);
11490
-
11491
- // If there are no sources when the player is initialized,
11492
- // load the first supported playback technology.
11493
-
11494
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options_, ready));
11495
-
11496
- if (!options.playerOptions.sources || options.playerOptions.sources.length === 0) {
11497
- for (var i = 0, j = options.playerOptions.techOrder; i < j.length; i++) {
11498
- var techName = toTitleCase(j[i]);
11499
- var tech = Tech.getTech(techName);
11500
-
11501
- // Support old behavior of techs being registered as components.
11502
- // Remove once that deprecated behavior is removed.
11503
- if (!techName) {
11504
- tech = Component.getComponent(techName);
11505
- }
11506
-
11507
- // Check if the browser supports this technology
11508
- if (tech && tech.isSupported()) {
11509
- player.loadTech_(techName);
11510
- break;
11511
- }
11512
- }
11513
- } else {
11514
- // Loop through playback technologies (HTML5, Flash) and check for support.
11515
- // Then load the best source.
11516
- // A few assumptions here:
11517
- // All playback technologies respect preload false.
11518
- player.src(options.playerOptions.sources);
11519
- }
11520
- return _this;
11521
- }
11522
-
11523
- return MediaLoader;
11524
- }(Component);
11525
-
11526
- Component.registerComponent('MediaLoader', MediaLoader);
11527
-
11528
- /**
11529
- * @file clickable-component.js
11530
- */
11531
-
11532
- /**
11533
- * Clickable Component which is clickable or keyboard actionable,
11534
- * but is not a native HTML button.
11535
- *
11536
- * @extends Component
11537
- */
11538
-
11539
- var ClickableComponent = function (_Component) {
11540
- inherits(ClickableComponent, _Component);
11541
-
11542
- /**
11543
- * Creates an instance of this class.
11544
- *
11545
- * @param {Player} player
11546
- * The `Player` that this class should be attached to.
11547
- *
11548
- * @param {Object} [options]
11549
- * The key/value store of player options.
11550
- */
11551
- function ClickableComponent(player, options) {
11552
- classCallCheck(this, ClickableComponent);
11553
-
11554
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
11555
-
11556
- _this.emitTapEvents();
11557
-
11558
- _this.enable();
11559
- return _this;
11560
- }
11561
-
11562
- /**
11563
- * Create the `Component`s DOM element.
11564
- *
11565
- * @param {string} [tag=div]
11566
- * The element's node type.
11567
- *
11568
- * @param {Object} [props={}]
11569
- * An object of properties that should be set on the element.
11570
- *
11571
- * @param {Object} [attributes={}]
11572
- * An object of attributes that should be set on the element.
11573
- *
11574
- * @return {Element}
11575
- * The element that gets created.
11576
- */
11577
-
11578
-
11579
- ClickableComponent.prototype.createEl = function createEl$$1() {
11580
- var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
11581
- var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
11582
- var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
11583
-
11584
- props = assign({
11585
- innerHTML: '<span aria-hidden="true" class="vjs-icon-placeholder"></span>',
11586
- className: this.buildCSSClass(),
11587
- tabIndex: 0
11588
- }, props);
11589
-
11590
- if (tag === 'button') {
11591
- log$1.error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.');
11592
- }
11593
-
11594
- // Add ARIA attributes for clickable element which is not a native HTML button
11595
- attributes = assign({
11596
- role: 'button'
11597
- }, attributes);
11598
-
11599
- this.tabIndex_ = props.tabIndex;
11600
-
11601
- var el = _Component.prototype.createEl.call(this, tag, props, attributes);
11602
-
11603
- this.createControlTextEl(el);
11604
-
11605
- return el;
11606
- };
11607
-
11608
- ClickableComponent.prototype.dispose = function dispose() {
11609
- // remove controlTextEl_ on dispose
11610
- this.controlTextEl_ = null;
11611
-
11612
- _Component.prototype.dispose.call(this);
11613
- };
11614
-
11615
- /**
11616
- * Create a control text element on this `Component`
11617
- *
11618
- * @param {Element} [el]
11619
- * Parent element for the control text.
11620
- *
11621
- * @return {Element}
11622
- * The control text element that gets created.
11623
- */
11624
-
11625
-
11626
- ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) {
11627
- this.controlTextEl_ = createEl('span', {
11628
- className: 'vjs-control-text'
11629
- }, {
11630
- // let the screen reader user know that the text of the element may change
11631
- 'aria-live': 'polite'
11632
- });
11633
-
11634
- if (el) {
11635
- el.appendChild(this.controlTextEl_);
11636
- }
11637
-
11638
- this.controlText(this.controlText_, el);
11639
-
11640
- return this.controlTextEl_;
11641
- };
11642
-
11643
- /**
11644
- * Get or set the localize text to use for the controls on the `Component`.
11645
- *
11646
- * @param {string} [text]
11647
- * Control text for element.
11648
- *
11649
- * @param {Element} [el=this.el()]
11650
- * Element to set the title on.
11651
- *
11652
- * @return {string}
11653
- * - The control text when getting
11654
- */
11655
-
11656
-
11657
- ClickableComponent.prototype.controlText = function controlText(text) {
11658
- var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el();
11659
-
11660
- if (text === undefined) {
11661
- return this.controlText_ || 'Need Text';
11662
- }
11663
-
11664
- var localizedText = this.localize(text);
11665
-
11666
- this.controlText_ = text;
11667
- textContent(this.controlTextEl_, localizedText);
11668
- if (!this.nonIconControl) {
11669
- // Set title attribute if only an icon is shown
11670
- el.setAttribute('title', localizedText);
11671
- }
11672
- };
11673
-
11674
- /**
11675
- * Builds the default DOM `className`.
11676
- *
11677
- * @return {string}
11678
- * The DOM `className` for this object.
11679
- */
11680
-
11681
-
11682
- ClickableComponent.prototype.buildCSSClass = function buildCSSClass() {
11683
- return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this);
11684
- };
11685
-
11686
- /**
11687
- * Enable this `Component`s element.
11688
- */
11689
-
11690
-
11691
- ClickableComponent.prototype.enable = function enable() {
11692
- if (!this.enabled_) {
11693
- this.enabled_ = true;
11694
- this.removeClass('vjs-disabled');
11695
- this.el_.setAttribute('aria-disabled', 'false');
11696
- if (typeof this.tabIndex_ !== 'undefined') {
11697
- this.el_.setAttribute('tabIndex', this.tabIndex_);
11698
- }
11699
- this.on(['tap', 'click'], this.handleClick);
11700
- this.on('focus', this.handleFocus);
11701
- this.on('blur', this.handleBlur);
11702
- }
11703
- };
11704
-
11705
- /**
11706
- * Disable this `Component`s element.
11707
- */
11708
-
11709
-
11710
- ClickableComponent.prototype.disable = function disable() {
11711
- this.enabled_ = false;
11712
- this.addClass('vjs-disabled');
11713
- this.el_.setAttribute('aria-disabled', 'true');
11714
- if (typeof this.tabIndex_ !== 'undefined') {
11715
- this.el_.removeAttribute('tabIndex');
11716
- }
11717
- this.off(['tap', 'click'], this.handleClick);
11718
- this.off('focus', this.handleFocus);
11719
- this.off('blur', this.handleBlur);
11720
- };
11721
-
11722
- /**
11723
- * This gets called when a `ClickableComponent` gets:
11724
- * - Clicked (via the `click` event, listening starts in the constructor)
11725
- * - Tapped (via the `tap` event, listening starts in the constructor)
11726
- * - The following things happen in order:
11727
- * 1. {@link ClickableComponent#handleFocus} is called via a `focus` event on the
11728
- * `ClickableComponent`.
11729
- * 2. {@link ClickableComponent#handleFocus} adds a listener for `keydown` on using
11730
- * {@link ClickableComponent#handleKeyPress}.
11731
- * 3. `ClickableComponent` has not had a `blur` event (`blur` means that focus was lost). The user presses
11732
- * the space or enter key.
11733
- * 4. {@link ClickableComponent#handleKeyPress} calls this function with the `keydown`
11734
- * event as a parameter.
11735
- *
11736
- * @param {EventTarget~Event} event
11737
- * The `keydown`, `tap`, or `click` event that caused this function to be
11738
- * called.
11739
- *
11740
- * @listens tap
11741
- * @listens click
11742
- * @abstract
11743
- */
11744
-
11745
-
11746
- ClickableComponent.prototype.handleClick = function handleClick(event) {};
11747
-
11748
- /**
11749
- * This gets called when a `ClickableComponent` gains focus via a `focus` event.
11750
- * Turns on listening for `keydown` events. When they happen it
11751
- * calls `this.handleKeyPress`.
11752
- *
11753
- * @param {EventTarget~Event} event
11754
- * The `focus` event that caused this function to be called.
11755
- *
11756
- * @listens focus
11757
- */
11758
-
11759
-
11760
- ClickableComponent.prototype.handleFocus = function handleFocus(event) {
11761
- on(document_1, 'keydown', bind(this, this.handleKeyPress));
11762
- };
11763
-
11764
- /**
11765
- * Called when this ClickableComponent has focus and a key gets pressed down. By
11766
- * default it will call `this.handleClick` when the key is space or enter.
11767
- *
11768
- * @param {EventTarget~Event} event
11769
- * The `keydown` event that caused this function to be called.
11770
- *
11771
- * @listens keydown
11772
- */
11773
-
11774
-
11775
- ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) {
11776
-
11777
- // Support Space (32) or Enter (13) key operation to fire a click event
11778
- if (event.which === 32 || event.which === 13) {
11779
- event.preventDefault();
11780
- this.trigger('click');
11781
- } else if (_Component.prototype.handleKeyPress) {
11782
-
11783
- // Pass keypress handling up for unsupported keys
11784
- _Component.prototype.handleKeyPress.call(this, event);
11785
- }
11786
- };
11787
-
11788
- /**
11789
- * Called when a `ClickableComponent` loses focus. Turns off the listener for
11790
- * `keydown` events. Which Stops `this.handleKeyPress` from getting called.
11791
- *
11792
- * @param {EventTarget~Event} event
11793
- * The `blur` event that caused this function to be called.
11794
- *
11795
- * @listens blur
11796
- */
11797
-
11798
-
11799
- ClickableComponent.prototype.handleBlur = function handleBlur(event) {
11800
- off(document_1, 'keydown', bind(this, this.handleKeyPress));
11801
- };
11802
-
11803
- return ClickableComponent;
11804
- }(Component);
11805
-
11806
- Component.registerComponent('ClickableComponent', ClickableComponent);
11807
-
11808
- /**
11809
- * @file poster-image.js
11810
- */
11811
-
11812
- /**
11813
- * A `ClickableComponent` that handles showing the poster image for the player.
11814
- *
11815
- * @extends ClickableComponent
11816
- */
11817
-
11818
- var PosterImage = function (_ClickableComponent) {
11819
- inherits(PosterImage, _ClickableComponent);
11820
-
11821
- /**
11822
- * Create an instance of this class.
11823
- *
11824
- * @param {Player} player
11825
- * The `Player` that this class should attach to.
11826
- *
11827
- * @param {Object} [options]
11828
- * The key/value store of player options.
11829
- */
11830
- function PosterImage(player, options) {
11831
- classCallCheck(this, PosterImage);
11832
-
11833
- var _this = possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
11834
-
11835
- _this.update();
11836
- player.on('posterchange', bind(_this, _this.update));
11837
- return _this;
11838
- }
11839
-
11840
- /**
11841
- * Clean up and dispose of the `PosterImage`.
11842
- */
11843
-
11844
-
11845
- PosterImage.prototype.dispose = function dispose() {
11846
- this.player().off('posterchange', this.update);
11847
- _ClickableComponent.prototype.dispose.call(this);
11848
- };
11849
-
11850
- /**
11851
- * Create the `PosterImage`s DOM element.
11852
- *
11853
- * @return {Element}
11854
- * The element that gets created.
11855
- */
11856
-
11857
-
11858
- PosterImage.prototype.createEl = function createEl$$1() {
11859
- var el = createEl('div', {
11860
- className: 'vjs-poster',
11861
-
11862
- // Don't want poster to be tabbable.
11863
- tabIndex: -1
11864
- });
11865
-
11866
- return el;
11867
- };
11868
-
11869
- /**
11870
- * An {@link EventTarget~EventListener} for {@link Player#posterchange} events.
11871
- *
11872
- * @listens Player#posterchange
11873
- *
11874
- * @param {EventTarget~Event} [event]
11875
- * The `Player#posterchange` event that triggered this function.
11876
- */
11877
-
11878
-
11879
- PosterImage.prototype.update = function update(event) {
11880
- var url = this.player().poster();
11881
-
11882
- this.setSrc(url);
11883
-
11884
- // If there's no poster source we should display:none on this component
11885
- // so it's not still clickable or right-clickable
11886
- if (url) {
11887
- this.show();
11888
- } else {
11889
- this.hide();
11890
- }
11891
- };
11892
-
11893
- /**
11894
- * Set the source of the `PosterImage` depending on the display method.
11895
- *
11896
- * @param {string} url
11897
- * The URL to the source for the `PosterImage`.
11898
- */
11899
-
11900
-
11901
- PosterImage.prototype.setSrc = function setSrc(url) {
11902
- var backgroundImage = '';
11903
-
11904
- // Any falsy value should stay as an empty string, otherwise
11905
- // this will throw an extra error
11906
- if (url) {
11907
- backgroundImage = 'url("' + url + '")';
11908
- }
11909
-
11910
- this.el_.style.backgroundImage = backgroundImage;
11911
- };
11912
-
11913
- /**
11914
- * An {@link EventTarget~EventListener} for clicks on the `PosterImage`. See
11915
- * {@link ClickableComponent#handleClick} for instances where this will be triggered.
11916
- *
11917
- * @listens tap
11918
- * @listens click
11919
- * @listens keydown
11920
- *
11921
- * @param {EventTarget~Event} event
11922
- + The `click`, `tap` or `keydown` event that caused this function to be called.
11923
- */
11924
-
11925
-
11926
- PosterImage.prototype.handleClick = function handleClick(event) {
11927
- // We don't want a click to trigger playback when controls are disabled
11928
- if (!this.player_.controls()) {
11929
- return;
11930
- }
11931
-
11932
- if (this.player_.paused()) {
11933
- silencePromise(this.player_.play());
11934
- } else {
11935
- this.player_.pause();
11936
- }
11937
- };
11938
-
11939
- return PosterImage;
11940
- }(ClickableComponent);
11941
-
11942
- Component.registerComponent('PosterImage', PosterImage);
11943
-
11944
- /**
11945
- * @file text-track-display.js
11946
- */
11947
-
11948
- var darkGray = '#222';
11949
- var lightGray = '#ccc';
11950
- var fontMap = {
11951
- monospace: 'monospace',
11952
- sansSerif: 'sans-serif',
11953
- serif: 'serif',
11954
- monospaceSansSerif: '"Andale Mono", "Lucida Console", monospace',
11955
- monospaceSerif: '"Courier New", monospace',
11956
- proportionalSansSerif: 'sans-serif',
11957
- proportionalSerif: 'serif',
11958
- casual: '"Comic Sans MS", Impact, fantasy',
11959
- script: '"Monotype Corsiva", cursive',
11960
- smallcaps: '"Andale Mono", "Lucida Console", monospace, sans-serif'
11961
- };
11962
-
11963
- /**
11964
- * Construct an rgba color from a given hex color code.
11965
- *
11966
- * @param {number} color
11967
- * Hex number for color, like #f0e or #f604e2.
11968
- *
11969
- * @param {number} opacity
11970
- * Value for opacity, 0.0 - 1.0.
11971
- *
11972
- * @return {string}
11973
- * The rgba color that was created, like 'rgba(255, 0, 0, 0.3)'.
11974
- */
11975
- function constructColor(color, opacity) {
11976
- var hex = void 0;
11977
-
11978
- if (color.length === 4) {
11979
- // color looks like "#f0e"
11980
- hex = color[1] + color[1] + color[2] + color[2] + color[3] + color[3];
11981
- } else if (color.length === 7) {
11982
- // color looks like "#f604e2"
11983
- hex = color.slice(1);
11984
- } else {
11985
- throw new Error('Invalid color code provided, ' + color + '; must be formatted as e.g. #f0e or #f604e2.');
11986
- }
11987
- return 'rgba(' + parseInt(hex.slice(0, 2), 16) + ',' + parseInt(hex.slice(2, 4), 16) + ',' + parseInt(hex.slice(4, 6), 16) + ',' + opacity + ')';
11988
- }
11989
-
11990
- /**
11991
- * Try to update the style of a DOM element. Some style changes will throw an error,
11992
- * particularly in IE8. Those should be noops.
11993
- *
11994
- * @param {Element} el
11995
- * The DOM element to be styled.
11996
- *
11997
- * @param {string} style
11998
- * The CSS property on the element that should be styled.
11999
- *
12000
- * @param {string} rule
12001
- * The style rule that should be applied to the property.
12002
- *
12003
- * @private
12004
- */
12005
- function tryUpdateStyle(el, style, rule) {
12006
- try {
12007
- el.style[style] = rule;
12008
- } catch (e) {
12009
-
12010
- // Satisfies linter.
12011
- return;
12012
- }
12013
- }
12014
-
12015
- /**
12016
- * The component for displaying text track cues.
12017
- *
12018
- * @extends Component
12019
- */
12020
-
12021
- var TextTrackDisplay = function (_Component) {
12022
- inherits(TextTrackDisplay, _Component);
12023
-
12024
- /**
12025
- * Creates an instance of this class.
12026
- *
12027
- * @param {Player} player
12028
- * The `Player` that this class should be attached to.
12029
- *
12030
- * @param {Object} [options]
12031
- * The key/value store of player options.
12032
- *
12033
- * @param {Component~ReadyCallback} [ready]
12034
- * The function to call when `TextTrackDisplay` is ready.
12035
- */
12036
- function TextTrackDisplay(player, options, ready) {
12037
- classCallCheck(this, TextTrackDisplay);
12038
-
12039
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options, ready));
12040
-
12041
- player.on('loadstart', bind(_this, _this.toggleDisplay));
12042
- player.on('texttrackchange', bind(_this, _this.updateDisplay));
12043
- player.on('loadstart', bind(_this, _this.preselectTrack));
12044
-
12045
- // This used to be called during player init, but was causing an error
12046
- // if a track should show by default and the display hadn't loaded yet.
12047
- // Should probably be moved to an external track loader when we support
12048
- // tracks that don't need a display.
12049
- player.ready(bind(_this, function () {
12050
- if (player.tech_ && player.tech_.featuresNativeTextTracks) {
12051
- this.hide();
12052
- return;
12053
- }
12054
-
12055
- player.on('fullscreenchange', bind(this, this.updateDisplay));
12056
-
12057
- var tracks = this.options_.playerOptions.tracks || [];
12058
-
12059
- for (var i = 0; i < tracks.length; i++) {
12060
- this.player_.addRemoteTextTrack(tracks[i], true);
12061
- }
12062
-
12063
- this.preselectTrack();
12064
- }));
12065
- return _this;
12066
- }
12067
-
12068
- /**
12069
- * Preselect a track following this precedence:
12070
- * - matches the previously selected {@link TextTrack}'s language and kind
12071
- * - matches the previously selected {@link TextTrack}'s language only
12072
- * - is the first default captions track
12073
- * - is the first default descriptions track
12074
- *
12075
- * @listens Player#loadstart
12076
- */
12077
-
12078
-
12079
- TextTrackDisplay.prototype.preselectTrack = function preselectTrack() {
12080
- var modes = { captions: 1, subtitles: 1 };
12081
- var trackList = this.player_.textTracks();
12082
- var userPref = this.player_.cache_.selectedLanguage;
12083
- var firstDesc = void 0;
12084
- var firstCaptions = void 0;
12085
- var preferredTrack = void 0;
12086
-
12087
- for (var i = 0; i < trackList.length; i++) {
12088
- var track = trackList[i];
12089
-
12090
- if (userPref && userPref.enabled && userPref.language === track.language) {
12091
- // Always choose the track that matches both language and kind
12092
- if (track.kind === userPref.kind) {
12093
- preferredTrack = track;
12094
- // or choose the first track that matches language
12095
- } else if (!preferredTrack) {
12096
- preferredTrack = track;
12097
- }
12098
-
12099
- // clear everything if offTextTrackMenuItem was clicked
12100
- } else if (userPref && !userPref.enabled) {
12101
- preferredTrack = null;
12102
- firstDesc = null;
12103
- firstCaptions = null;
12104
- } else if (track.default) {
12105
- if (track.kind === 'descriptions' && !firstDesc) {
12106
- firstDesc = track;
12107
- } else if (track.kind in modes && !firstCaptions) {
12108
- firstCaptions = track;
12109
- }
12110
- }
12111
- }
12112
-
12113
- // The preferredTrack matches the user preference and takes
12114
- // precedence over all the other tracks.
12115
- // So, display the preferredTrack before the first default track
12116
- // and the subtitles/captions track before the descriptions track
12117
- if (preferredTrack) {
12118
- preferredTrack.mode = 'showing';
12119
- } else if (firstCaptions) {
12120
- firstCaptions.mode = 'showing';
12121
- } else if (firstDesc) {
12122
- firstDesc.mode = 'showing';
12123
- }
12124
- };
12125
-
12126
- /**
12127
- * Turn display of {@link TextTrack}'s from the current state into the other state.
12128
- * There are only two states:
12129
- * - 'shown'
12130
- * - 'hidden'
12131
- *
12132
- * @listens Player#loadstart
12133
- */
12134
-
12135
-
12136
- TextTrackDisplay.prototype.toggleDisplay = function toggleDisplay() {
12137
- if (this.player_.tech_ && this.player_.tech_.featuresNativeTextTracks) {
12138
- this.hide();
12139
- } else {
12140
- this.show();
12141
- }
12142
- };
12143
-
12144
- /**
12145
- * Create the {@link Component}'s DOM element.
12146
- *
12147
- * @return {Element}
12148
- * The element that was created.
12149
- */
12150
-
12151
-
12152
- TextTrackDisplay.prototype.createEl = function createEl() {
12153
- return _Component.prototype.createEl.call(this, 'div', {
12154
- className: 'vjs-text-track-display'
12155
- }, {
12156
- 'aria-live': 'off',
12157
- 'aria-atomic': 'true'
12158
- });
12159
- };
12160
-
12161
- /**
12162
- * Clear all displayed {@link TextTrack}s.
12163
- */
12164
-
12165
-
12166
- TextTrackDisplay.prototype.clearDisplay = function clearDisplay() {
12167
- if (typeof window_1.WebVTT === 'function') {
12168
- window_1.WebVTT.processCues(window_1, [], this.el_);
12169
- }
12170
- };
12171
-
12172
- /**
12173
- * Update the displayed TextTrack when a either a {@link Player#texttrackchange} or
12174
- * a {@link Player#fullscreenchange} is fired.
12175
- *
12176
- * @listens Player#texttrackchange
12177
- * @listens Player#fullscreenchange
12178
- */
12179
-
12180
-
12181
- TextTrackDisplay.prototype.updateDisplay = function updateDisplay() {
12182
- var tracks = this.player_.textTracks();
12183
-
12184
- this.clearDisplay();
12185
-
12186
- // Track display prioritization model: if multiple tracks are 'showing',
12187
- // display the first 'subtitles' or 'captions' track which is 'showing',
12188
- // otherwise display the first 'descriptions' track which is 'showing'
12189
-
12190
- var descriptionsTrack = null;
12191
- var captionsSubtitlesTrack = null;
12192
- var i = tracks.length;
12193
-
12194
- while (i--) {
12195
- var track = tracks[i];
12196
-
12197
- if (track.mode === 'showing') {
12198
- if (track.kind === 'descriptions') {
12199
- descriptionsTrack = track;
12200
- } else {
12201
- captionsSubtitlesTrack = track;
12202
- }
12203
- }
12204
- }
12205
-
12206
- if (captionsSubtitlesTrack) {
12207
- if (this.getAttribute('aria-live') !== 'off') {
12208
- this.setAttribute('aria-live', 'off');
12209
- }
12210
- this.updateForTrack(captionsSubtitlesTrack);
12211
- } else if (descriptionsTrack) {
12212
- if (this.getAttribute('aria-live') !== 'assertive') {
12213
- this.setAttribute('aria-live', 'assertive');
12214
- }
12215
- this.updateForTrack(descriptionsTrack);
12216
- }
12217
- };
12218
-
12219
- /**
12220
- * Add an {@link TextTrack} to to the {@link Tech}s {@link TextTrackList}.
12221
- *
12222
- * @param {TextTrack} track
12223
- * Text track object to be added to the list.
12224
- */
12225
-
12226
-
12227
- TextTrackDisplay.prototype.updateForTrack = function updateForTrack(track) {
12228
- if (typeof window_1.WebVTT !== 'function' || !track.activeCues) {
12229
- return;
12230
- }
12231
-
12232
- var cues = [];
12233
-
12234
- for (var _i = 0; _i < track.activeCues.length; _i++) {
12235
- cues.push(track.activeCues[_i]);
12236
- }
12237
-
12238
- window_1.WebVTT.processCues(window_1, cues, this.el_);
12239
-
12240
- if (!this.player_.textTrackSettings) {
12241
- return;
12242
- }
12243
-
12244
- var overrides = this.player_.textTrackSettings.getValues();
12245
-
12246
- var i = cues.length;
12247
-
12248
- while (i--) {
12249
- var cue = cues[i];
12250
-
12251
- if (!cue) {
12252
- continue;
12253
- }
12254
-
12255
- var cueDiv = cue.displayState;
12256
-
12257
- if (overrides.color) {
12258
- cueDiv.firstChild.style.color = overrides.color;
12259
- }
12260
- if (overrides.textOpacity) {
12261
- tryUpdateStyle(cueDiv.firstChild, 'color', constructColor(overrides.color || '#fff', overrides.textOpacity));
12262
- }
12263
- if (overrides.backgroundColor) {
12264
- cueDiv.firstChild.style.backgroundColor = overrides.backgroundColor;
12265
- }
12266
- if (overrides.backgroundOpacity) {
12267
- tryUpdateStyle(cueDiv.firstChild, 'backgroundColor', constructColor(overrides.backgroundColor || '#000', overrides.backgroundOpacity));
12268
- }
12269
- if (overrides.windowColor) {
12270
- if (overrides.windowOpacity) {
12271
- tryUpdateStyle(cueDiv, 'backgroundColor', constructColor(overrides.windowColor, overrides.windowOpacity));
12272
- } else {
12273
- cueDiv.style.backgroundColor = overrides.windowColor;
12274
- }
12275
- }
12276
- if (overrides.edgeStyle) {
12277
- if (overrides.edgeStyle === 'dropshadow') {
12278
- cueDiv.firstChild.style.textShadow = '2px 2px 3px ' + darkGray + ', 2px 2px 4px ' + darkGray + ', 2px 2px 5px ' + darkGray;
12279
- } else if (overrides.edgeStyle === 'raised') {
12280
- cueDiv.firstChild.style.textShadow = '1px 1px ' + darkGray + ', 2px 2px ' + darkGray + ', 3px 3px ' + darkGray;
12281
- } else if (overrides.edgeStyle === 'depressed') {
12282
- cueDiv.firstChild.style.textShadow = '1px 1px ' + lightGray + ', 0 1px ' + lightGray + ', -1px -1px ' + darkGray + ', 0 -1px ' + darkGray;
12283
- } else if (overrides.edgeStyle === 'uniform') {
12284
- cueDiv.firstChild.style.textShadow = '0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray + ', 0 0 4px ' + darkGray;
12285
- }
12286
- }
12287
- if (overrides.fontPercent && overrides.fontPercent !== 1) {
12288
- var fontSize = window_1.parseFloat(cueDiv.style.fontSize);
12289
-
12290
- cueDiv.style.fontSize = fontSize * overrides.fontPercent + 'px';
12291
- cueDiv.style.height = 'auto';
12292
- cueDiv.style.top = 'auto';
12293
- cueDiv.style.bottom = '2px';
12294
- }
12295
- if (overrides.fontFamily && overrides.fontFamily !== 'default') {
12296
- if (overrides.fontFamily === 'small-caps') {
12297
- cueDiv.firstChild.style.fontVariant = 'small-caps';
12298
- } else {
12299
- cueDiv.firstChild.style.fontFamily = fontMap[overrides.fontFamily];
12300
- }
12301
- }
12302
- }
12303
- };
12304
-
12305
- return TextTrackDisplay;
12306
- }(Component);
12307
-
12308
- Component.registerComponent('TextTrackDisplay', TextTrackDisplay);
12309
-
12310
- /**
12311
- * @file loading-spinner.js
12312
- */
12313
-
12314
- /**
12315
- * A loading spinner for use during waiting/loading events.
12316
- *
12317
- * @extends Component
12318
- */
12319
-
12320
- var LoadingSpinner = function (_Component) {
12321
- inherits(LoadingSpinner, _Component);
12322
-
12323
- function LoadingSpinner() {
12324
- classCallCheck(this, LoadingSpinner);
12325
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
12326
- }
12327
-
12328
- /**
12329
- * Create the `LoadingSpinner`s DOM element.
12330
- *
12331
- * @return {Element}
12332
- * The dom element that gets created.
12333
- */
12334
- LoadingSpinner.prototype.createEl = function createEl$$1() {
12335
- var isAudio = this.player_.isAudio();
12336
- var playerType = this.localize(isAudio ? 'Audio Player' : 'Video Player');
12337
- var controlText = createEl('span', {
12338
- className: 'vjs-control-text',
12339
- innerHTML: this.localize('{1} is loading.', [playerType])
12340
- });
12341
-
12342
- var el = _Component.prototype.createEl.call(this, 'div', {
12343
- className: 'vjs-loading-spinner',
12344
- dir: 'ltr'
12345
- });
12346
-
12347
- el.appendChild(controlText);
12348
-
12349
- return el;
12350
- };
12351
-
12352
- return LoadingSpinner;
12353
- }(Component);
12354
-
12355
- Component.registerComponent('LoadingSpinner', LoadingSpinner);
12356
-
12357
- /**
12358
- * @file button.js
12359
- */
12360
-
12361
- /**
12362
- * Base class for all buttons.
12363
- *
12364
- * @extends ClickableComponent
12365
- */
12366
-
12367
- var Button = function (_ClickableComponent) {
12368
- inherits(Button, _ClickableComponent);
12369
-
12370
- function Button() {
12371
- classCallCheck(this, Button);
12372
- return possibleConstructorReturn(this, _ClickableComponent.apply(this, arguments));
12373
- }
12374
-
12375
- /**
12376
- * Create the `Button`s DOM element.
12377
- *
12378
- * @param {string} [tag="button"]
12379
- * The element's node type. This argument is IGNORED: no matter what
12380
- * is passed, it will always create a `button` element.
12381
- *
12382
- * @param {Object} [props={}]
12383
- * An object of properties that should be set on the element.
12384
- *
12385
- * @param {Object} [attributes={}]
12386
- * An object of attributes that should be set on the element.
12387
- *
12388
- * @return {Element}
12389
- * The element that gets created.
12390
- */
12391
- Button.prototype.createEl = function createEl(tag) {
12392
- var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
12393
- var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
12394
-
12395
- tag = 'button';
12396
-
12397
- props = assign({
12398
- innerHTML: '<span aria-hidden="true" class="vjs-icon-placeholder"></span>',
12399
- className: this.buildCSSClass()
12400
- }, props);
12401
-
12402
- // Add attributes for button element
12403
- attributes = assign({
12404
-
12405
- // Necessary since the default button type is "submit"
12406
- type: 'button'
12407
- }, attributes);
12408
-
12409
- var el = Component.prototype.createEl.call(this, tag, props, attributes);
12410
-
12411
- this.createControlTextEl(el);
12412
-
12413
- return el;
12414
- };
12415
-
12416
- /**
12417
- * Add a child `Component` inside of this `Button`.
12418
- *
12419
- * @param {string|Component} child
12420
- * The name or instance of a child to add.
12421
- *
12422
- * @param {Object} [options={}]
12423
- * The key/value store of options that will get passed to children of
12424
- * the child.
12425
- *
12426
- * @return {Component}
12427
- * The `Component` that gets added as a child. When using a string the
12428
- * `Component` will get created by this process.
12429
- *
12430
- * @deprecated since version 5
12431
- */
12432
-
12433
-
12434
- Button.prototype.addChild = function addChild(child) {
12435
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
12436
-
12437
- var className = this.constructor.name;
12438
-
12439
- log$1.warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.');
12440
-
12441
- // Avoid the error message generated by ClickableComponent's addChild method
12442
- return Component.prototype.addChild.call(this, child, options);
12443
- };
12444
-
12445
- /**
12446
- * Enable the `Button` element so that it can be activated or clicked. Use this with
12447
- * {@link Button#disable}.
12448
- */
12449
-
12450
-
12451
- Button.prototype.enable = function enable() {
12452
- _ClickableComponent.prototype.enable.call(this);
12453
- this.el_.removeAttribute('disabled');
12454
- };
12455
-
12456
- /**
12457
- * Disable the `Button` element so that it cannot be activated or clicked. Use this with
12458
- * {@link Button#enable}.
12459
- */
12460
-
12461
-
12462
- Button.prototype.disable = function disable() {
12463
- _ClickableComponent.prototype.disable.call(this);
12464
- this.el_.setAttribute('disabled', 'disabled');
12465
- };
12466
-
12467
- /**
12468
- * This gets called when a `Button` has focus and `keydown` is triggered via a key
12469
- * press.
12470
- *
12471
- * @param {EventTarget~Event} event
12472
- * The event that caused this function to get called.
12473
- *
12474
- * @listens keydown
12475
- */
12476
-
12477
-
12478
- Button.prototype.handleKeyPress = function handleKeyPress(event) {
12479
-
12480
- // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
12481
- if (event.which === 32 || event.which === 13) {
12482
- return;
12483
- }
12484
-
12485
- // Pass keypress handling up for unsupported keys
12486
- _ClickableComponent.prototype.handleKeyPress.call(this, event);
12487
- };
12488
-
12489
- return Button;
12490
- }(ClickableComponent);
12491
-
12492
- Component.registerComponent('Button', Button);
12493
-
12494
- /**
12495
- * @file big-play-button.js
12496
- */
12497
-
12498
- /**
12499
- * The initial play button that shows before the video has played. The hiding of the
12500
- * `BigPlayButton` get done via CSS and `Player` states.
12501
- *
12502
- * @extends Button
12503
- */
12504
-
12505
- var BigPlayButton = function (_Button) {
12506
- inherits(BigPlayButton, _Button);
12507
-
12508
- function BigPlayButton(player, options) {
12509
- classCallCheck(this, BigPlayButton);
12510
-
12511
- var _this = possibleConstructorReturn(this, _Button.call(this, player, options));
12512
-
12513
- _this.mouseused_ = false;
12514
-
12515
- _this.on('mousedown', _this.handleMouseDown);
12516
- return _this;
12517
- }
12518
-
12519
- /**
12520
- * Builds the default DOM `className`.
12521
- *
12522
- * @return {string}
12523
- * The DOM `className` for this object. Always returns 'vjs-big-play-button'.
12524
- */
12525
-
12526
-
12527
- BigPlayButton.prototype.buildCSSClass = function buildCSSClass() {
12528
- return 'vjs-big-play-button';
12529
- };
12530
-
12531
- /**
12532
- * This gets called when a `BigPlayButton` "clicked". See {@link ClickableComponent}
12533
- * for more detailed information on what a click can be.
12534
- *
12535
- * @param {EventTarget~Event} event
12536
- * The `keydown`, `tap`, or `click` event that caused this function to be
12537
- * called.
12538
- *
12539
- * @listens tap
12540
- * @listens click
12541
- */
12542
-
12543
-
12544
- BigPlayButton.prototype.handleClick = function handleClick(event) {
12545
- var playPromise = this.player_.play();
12546
-
12547
- // exit early if clicked via the mouse
12548
- if (this.mouseused_ && event.clientX && event.clientY) {
12549
- silencePromise(playPromise);
12550
- return;
12551
- }
12552
-
12553
- var cb = this.player_.getChild('controlBar');
12554
- var playToggle = cb && cb.getChild('playToggle');
12555
-
12556
- if (!playToggle) {
12557
- this.player_.focus();
12558
- return;
12559
- }
12560
-
12561
- var playFocus = function playFocus() {
12562
- return playToggle.focus();
12563
- };
12564
-
12565
- if (isPromise(playPromise)) {
12566
- playPromise.then(playFocus, function () {});
12567
- } else {
12568
- this.setTimeout(playFocus, 1);
12569
- }
12570
- };
12571
-
12572
- BigPlayButton.prototype.handleKeyPress = function handleKeyPress(event) {
12573
- this.mouseused_ = false;
12574
-
12575
- _Button.prototype.handleKeyPress.call(this, event);
12576
- };
12577
-
12578
- BigPlayButton.prototype.handleMouseDown = function handleMouseDown(event) {
12579
- this.mouseused_ = true;
12580
- };
12581
-
12582
- return BigPlayButton;
12583
- }(Button);
12584
-
12585
- /**
12586
- * The text that should display over the `BigPlayButton`s controls. Added to for localization.
12587
- *
12588
- * @type {string}
12589
- * @private
12590
- */
12591
-
12592
-
12593
- BigPlayButton.prototype.controlText_ = 'Play Video';
12594
-
12595
- Component.registerComponent('BigPlayButton', BigPlayButton);
12596
-
12597
- /**
12598
- * @file close-button.js
12599
- */
12600
-
12601
- /**
12602
- * The `CloseButton` is a `{@link Button}` that fires a `close` event when
12603
- * it gets clicked.
12604
- *
12605
- * @extends Button
12606
- */
12607
-
12608
- var CloseButton = function (_Button) {
12609
- inherits(CloseButton, _Button);
12610
-
12611
- /**
12612
- * Creates an instance of the this class.
12613
- *
12614
- * @param {Player} player
12615
- * The `Player` that this class should be attached to.
12616
- *
12617
- * @param {Object} [options]
12618
- * The key/value store of player options.
12619
- */
12620
- function CloseButton(player, options) {
12621
- classCallCheck(this, CloseButton);
12622
-
12623
- var _this = possibleConstructorReturn(this, _Button.call(this, player, options));
12624
-
12625
- _this.controlText(options && options.controlText || _this.localize('Close'));
12626
- return _this;
12627
- }
12628
-
12629
- /**
12630
- * Builds the default DOM `className`.
12631
- *
12632
- * @return {string}
12633
- * The DOM `className` for this object.
12634
- */
12635
-
12636
-
12637
- CloseButton.prototype.buildCSSClass = function buildCSSClass() {
12638
- return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this);
12639
- };
12640
-
12641
- /**
12642
- * This gets called when a `CloseButton` gets clicked. See
12643
- * {@link ClickableComponent#handleClick} for more information on when this will be
12644
- * triggered
12645
- *
12646
- * @param {EventTarget~Event} event
12647
- * The `keydown`, `tap`, or `click` event that caused this function to be
12648
- * called.
12649
- *
12650
- * @listens tap
12651
- * @listens click
12652
- * @fires CloseButton#close
12653
- */
12654
-
12655
-
12656
- CloseButton.prototype.handleClick = function handleClick(event) {
12657
-
12658
- /**
12659
- * Triggered when the a `CloseButton` is clicked.
12660
- *
12661
- * @event CloseButton#close
12662
- * @type {EventTarget~Event}
12663
- *
12664
- * @property {boolean} [bubbles=false]
12665
- * set to false so that the close event does not
12666
- * bubble up to parents if there is no listener
12667
- */
12668
- this.trigger({ type: 'close', bubbles: false });
12669
- };
12670
-
12671
- return CloseButton;
12672
- }(Button);
12673
-
12674
- Component.registerComponent('CloseButton', CloseButton);
12675
-
12676
- /**
12677
- * @file play-toggle.js
12678
- */
12679
-
12680
- /**
12681
- * Button to toggle between play and pause.
12682
- *
12683
- * @extends Button
12684
- */
12685
-
12686
- var PlayToggle = function (_Button) {
12687
- inherits(PlayToggle, _Button);
12688
-
12689
- /**
12690
- * Creates an instance of this class.
12691
- *
12692
- * @param {Player} player
12693
- * The `Player` that this class should be attached to.
12694
- *
12695
- * @param {Object} [options]
12696
- * The key/value store of player options.
12697
- */
12698
- function PlayToggle(player, options) {
12699
- classCallCheck(this, PlayToggle);
12700
-
12701
- var _this = possibleConstructorReturn(this, _Button.call(this, player, options));
12702
-
12703
- _this.on(player, 'play', _this.handlePlay);
12704
- _this.on(player, 'pause', _this.handlePause);
12705
- _this.on(player, 'ended', _this.handleEnded);
12706
- return _this;
12707
- }
12708
-
12709
- /**
12710
- * Builds the default DOM `className`.
12711
- *
12712
- * @return {string}
12713
- * The DOM `className` for this object.
12714
- */
12715
-
12716
-
12717
- PlayToggle.prototype.buildCSSClass = function buildCSSClass() {
12718
- return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this);
12719
- };
12720
-
12721
- /**
12722
- * This gets called when an `PlayToggle` is "clicked". See
12723
- * {@link ClickableComponent} for more detailed information on what a click can be.
12724
- *
12725
- * @param {EventTarget~Event} [event]
12726
- * The `keydown`, `tap`, or `click` event that caused this function to be
12727
- * called.
12728
- *
12729
- * @listens tap
12730
- * @listens click
12731
- */
12732
-
12733
-
12734
- PlayToggle.prototype.handleClick = function handleClick(event) {
12735
- if (this.player_.paused()) {
12736
- this.player_.play();
12737
- } else {
12738
- this.player_.pause();
12739
- }
12740
- };
12741
-
12742
- /**
12743
- * This gets called once after the video has ended and the user seeks so that
12744
- * we can change the replay button back to a play button.
12745
- *
12746
- * @param {EventTarget~Event} [event]
12747
- * The event that caused this function to run.
12748
- *
12749
- * @listens Player#seeked
12750
- */
12751
-
12752
-
12753
- PlayToggle.prototype.handleSeeked = function handleSeeked(event) {
12754
- this.removeClass('vjs-ended');
12755
-
12756
- if (this.player_.paused()) {
12757
- this.handlePause(event);
12758
- } else {
12759
- this.handlePlay(event);
12760
- }
12761
- };
12762
-
12763
- /**
12764
- * Add the vjs-playing class to the element so it can change appearance.
12765
- *
12766
- * @param {EventTarget~Event} [event]
12767
- * The event that caused this function to run.
12768
- *
12769
- * @listens Player#play
12770
- */
12771
-
12772
-
12773
- PlayToggle.prototype.handlePlay = function handlePlay(event) {
12774
- this.removeClass('vjs-ended');
12775
- this.removeClass('vjs-paused');
12776
- this.addClass('vjs-playing');
12777
- // change the button text to "Pause"
12778
- this.controlText('Pause');
12779
- };
12780
-
12781
- /**
12782
- * Add the vjs-paused class to the element so it can change appearance.
12783
- *
12784
- * @param {EventTarget~Event} [event]
12785
- * The event that caused this function to run.
12786
- *
12787
- * @listens Player#pause
12788
- */
12789
-
12790
-
12791
- PlayToggle.prototype.handlePause = function handlePause(event) {
12792
- this.removeClass('vjs-playing');
12793
- this.addClass('vjs-paused');
12794
- // change the button text to "Play"
12795
- this.controlText('Play');
12796
- };
12797
-
12798
- /**
12799
- * Add the vjs-ended class to the element so it can change appearance
12800
- *
12801
- * @param {EventTarget~Event} [event]
12802
- * The event that caused this function to run.
12803
- *
12804
- * @listens Player#ended
12805
- */
12806
-
12807
-
12808
- PlayToggle.prototype.handleEnded = function handleEnded(event) {
12809
- this.removeClass('vjs-playing');
12810
- this.addClass('vjs-ended');
12811
- // change the button text to "Replay"
12812
- this.controlText('Replay');
12813
-
12814
- // on the next seek remove the replay button
12815
- this.one(this.player_, 'seeked', this.handleSeeked);
12816
- };
12817
-
12818
- return PlayToggle;
12819
- }(Button);
12820
-
12821
- /**
12822
- * The text that should display over the `PlayToggle`s controls. Added for localization.
12823
- *
12824
- * @type {string}
12825
- * @private
12826
- */
12827
-
12828
-
12829
- PlayToggle.prototype.controlText_ = 'Play';
12830
-
12831
- Component.registerComponent('PlayToggle', PlayToggle);
12832
-
12833
- /**
12834
- * @file format-time.js
12835
- * @module format-time
12836
- */
12837
-
12838
- /**
12839
- * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in seconds)
12840
- * will force a number of leading zeros to cover the length of the guide.
12841
- *
12842
- * @param {number} seconds
12843
- * Number of seconds to be turned into a string
12844
- *
12845
- * @param {number} guide
12846
- * Number (in seconds) to model the string after
12847
- *
12848
- * @return {string}
12849
- * Time formatted as H:MM:SS or M:SS
12850
- */
12851
- var defaultImplementation = function defaultImplementation(seconds, guide) {
12852
- seconds = seconds < 0 ? 0 : seconds;
12853
- var s = Math.floor(seconds % 60);
12854
- var m = Math.floor(seconds / 60 % 60);
12855
- var h = Math.floor(seconds / 3600);
12856
- var gm = Math.floor(guide / 60 % 60);
12857
- var gh = Math.floor(guide / 3600);
12858
-
12859
- // handle invalid times
12860
- if (isNaN(seconds) || seconds === Infinity) {
12861
- // '-' is false for all relational operators (e.g. <, >=) so this setting
12862
- // will add the minimum number of fields specified by the guide
12863
- h = m = s = '-';
12864
- }
12865
-
12866
- // Check if we need to show hours
12867
- h = h > 0 || gh > 0 ? h + ':' : '';
12868
-
12869
- // If hours are showing, we may need to add a leading zero.
12870
- // Always show at least one digit of minutes.
12871
- m = ((h || gm >= 10) && m < 10 ? '0' + m : m) + ':';
12872
-
12873
- // Check if leading zero is need for seconds
12874
- s = s < 10 ? '0' + s : s;
12875
-
12876
- return h + m + s;
12877
- };
12878
-
12879
- var implementation = defaultImplementation;
12880
-
12881
- /**
12882
- * Replaces the default formatTime implementation with a custom implementation.
12883
- *
12884
- * @param {Function} customImplementation
12885
- * A function which will be used in place of the default formatTime implementation.
12886
- * Will receive the current time in seconds and the guide (in seconds) as arguments.
12887
- */
12888
- function setFormatTime(customImplementation) {
12889
- implementation = customImplementation;
12890
- }
12891
-
12892
- /**
12893
- * Resets formatTime to the default implementation.
12894
- */
12895
- function resetFormatTime() {
12896
- implementation = defaultImplementation;
12897
- }
12898
-
12899
- function formatTime (seconds) {
12900
- var guide = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : seconds;
12901
-
12902
- return implementation(seconds, guide);
12903
- }
12904
-
12905
- /**
12906
- * @file time-display.js
12907
- */
12908
-
12909
- /**
12910
- * Displays the time left in the video
12911
- *
12912
- * @extends Component
12913
- */
12914
-
12915
- var TimeDisplay = function (_Component) {
12916
- inherits(TimeDisplay, _Component);
12917
-
12918
- /**
12919
- * Creates an instance of this class.
12920
- *
12921
- * @param {Player} player
12922
- * The `Player` that this class should be attached to.
12923
- *
12924
- * @param {Object} [options]
12925
- * The key/value store of player options.
12926
- */
12927
- function TimeDisplay(player, options) {
12928
- classCallCheck(this, TimeDisplay);
12929
-
12930
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
12931
-
12932
- _this.throttledUpdateContent = throttle(bind(_this, _this.updateContent), 25);
12933
- _this.on(player, 'timeupdate', _this.throttledUpdateContent);
12934
- return _this;
12935
- }
12936
-
12937
- /**
12938
- * Create the `Component`'s DOM element
12939
- *
12940
- * @return {Element}
12941
- * The element that was created.
12942
- */
12943
-
12944
-
12945
- TimeDisplay.prototype.createEl = function createEl$$1(plainName) {
12946
- var className = this.buildCSSClass();
12947
- var el = _Component.prototype.createEl.call(this, 'div', {
12948
- className: className + ' vjs-time-control vjs-control',
12949
- innerHTML: '<span class="vjs-control-text">' + this.localize(this.labelText_) + '\xA0</span>'
12950
- });
12951
-
12952
- this.contentEl_ = createEl('span', {
12953
- className: className + '-display'
12954
- }, {
12955
- // tell screen readers not to automatically read the time as it changes
12956
- 'aria-live': 'off'
12957
- });
12958
-
12959
- this.updateTextNode_();
12960
- el.appendChild(this.contentEl_);
12961
- return el;
12962
- };
12963
-
12964
- TimeDisplay.prototype.dispose = function dispose() {
12965
- this.contentEl_ = null;
12966
- this.textNode_ = null;
12967
-
12968
- _Component.prototype.dispose.call(this);
12969
- };
12970
-
12971
- /**
12972
- * Updates the "remaining time" text node with new content using the
12973
- * contents of the `formattedTime_` property.
12974
- *
12975
- * @private
12976
- */
12977
-
12978
-
12979
- TimeDisplay.prototype.updateTextNode_ = function updateTextNode_() {
12980
- if (!this.contentEl_) {
12981
- return;
12982
- }
12983
-
12984
- while (this.contentEl_.firstChild) {
12985
- this.contentEl_.removeChild(this.contentEl_.firstChild);
12986
- }
12987
-
12988
- this.textNode_ = document_1.createTextNode(this.formattedTime_ || this.formatTime_(0));
12989
- this.contentEl_.appendChild(this.textNode_);
12990
- };
12991
-
12992
- /**
12993
- * Generates a formatted time for this component to use in display.
12994
- *
12995
- * @param {number} time
12996
- * A numeric time, in seconds.
12997
- *
12998
- * @return {string}
12999
- * A formatted time
13000
- *
13001
- * @private
13002
- */
13003
-
13004
-
13005
- TimeDisplay.prototype.formatTime_ = function formatTime_(time) {
13006
- return formatTime(time);
13007
- };
13008
-
13009
- /**
13010
- * Updates the time display text node if it has what was passed in changed
13011
- * the formatted time.
13012
- *
13013
- * @param {number} time
13014
- * The time to update to
13015
- *
13016
- * @private
13017
- */
13018
-
13019
-
13020
- TimeDisplay.prototype.updateFormattedTime_ = function updateFormattedTime_(time) {
13021
- var formattedTime = this.formatTime_(time);
13022
-
13023
- if (formattedTime === this.formattedTime_) {
13024
- return;
13025
- }
13026
-
13027
- this.formattedTime_ = formattedTime;
13028
- this.requestAnimationFrame(this.updateTextNode_);
13029
- };
13030
-
13031
- /**
13032
- * To be filled out in the child class, should update the displayed time
13033
- * in accordance with the fact that the current time has changed.
13034
- *
13035
- * @param {EventTarget~Event} [event]
13036
- * The `timeupdate` event that caused this to run.
13037
- *
13038
- * @listens Player#timeupdate
13039
- */
13040
-
13041
-
13042
- TimeDisplay.prototype.updateContent = function updateContent(event) {};
13043
-
13044
- return TimeDisplay;
13045
- }(Component);
13046
-
13047
- /**
13048
- * The text that is added to the `TimeDisplay` for screen reader users.
13049
- *
13050
- * @type {string}
13051
- * @private
13052
- */
13053
-
13054
-
13055
- TimeDisplay.prototype.labelText_ = 'Time';
13056
-
13057
- /**
13058
- * The text that should display over the `TimeDisplay`s controls. Added to for localization.
13059
- *
13060
- * @type {string}
13061
- * @private
13062
- *
13063
- * @deprecated in v7; controlText_ is not used in non-active display Components
13064
- */
13065
- TimeDisplay.prototype.controlText_ = 'Time';
13066
-
13067
- Component.registerComponent('TimeDisplay', TimeDisplay);
13068
-
13069
- /**
13070
- * @file current-time-display.js
13071
- */
13072
-
13073
- /**
13074
- * Displays the current time
13075
- *
13076
- * @extends Component
13077
- */
13078
-
13079
- var CurrentTimeDisplay = function (_TimeDisplay) {
13080
- inherits(CurrentTimeDisplay, _TimeDisplay);
13081
-
13082
- /**
13083
- * Creates an instance of this class.
13084
- *
13085
- * @param {Player} player
13086
- * The `Player` that this class should be attached to.
13087
- *
13088
- * @param {Object} [options]
13089
- * The key/value store of player options.
13090
- */
13091
- function CurrentTimeDisplay(player, options) {
13092
- classCallCheck(this, CurrentTimeDisplay);
13093
-
13094
- var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options));
13095
-
13096
- _this.on(player, 'ended', _this.handleEnded);
13097
- return _this;
13098
- }
13099
-
13100
- /**
13101
- * Builds the default DOM `className`.
13102
- *
13103
- * @return {string}
13104
- * The DOM `className` for this object.
13105
- */
13106
-
13107
-
13108
- CurrentTimeDisplay.prototype.buildCSSClass = function buildCSSClass() {
13109
- return 'vjs-current-time';
13110
- };
13111
-
13112
- /**
13113
- * Update current time display
13114
- *
13115
- * @param {EventTarget~Event} [event]
13116
- * The `timeupdate` event that caused this function to run.
13117
- *
13118
- * @listens Player#timeupdate
13119
- */
13120
-
13121
-
13122
- CurrentTimeDisplay.prototype.updateContent = function updateContent(event) {
13123
- // Allows for smooth scrubbing, when player can't keep up.
13124
- var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
13125
-
13126
- this.updateFormattedTime_(time);
13127
- };
13128
-
13129
- /**
13130
- * When the player fires ended there should be no time left. Sadly
13131
- * this is not always the case, lets make it seem like that is the case
13132
- * for users.
13133
- *
13134
- * @param {EventTarget~Event} [event]
13135
- * The `ended` event that caused this to run.
13136
- *
13137
- * @listens Player#ended
13138
- */
13139
-
13140
-
13141
- CurrentTimeDisplay.prototype.handleEnded = function handleEnded(event) {
13142
- if (!this.player_.duration()) {
13143
- return;
13144
- }
13145
- this.updateFormattedTime_(this.player_.duration());
13146
- };
13147
-
13148
- return CurrentTimeDisplay;
13149
- }(TimeDisplay);
13150
-
13151
- /**
13152
- * The text that is added to the `CurrentTimeDisplay` for screen reader users.
13153
- *
13154
- * @type {string}
13155
- * @private
13156
- */
13157
-
13158
-
13159
- CurrentTimeDisplay.prototype.labelText_ = 'Current Time';
13160
-
13161
- /**
13162
- * The text that should display over the `CurrentTimeDisplay`s controls. Added to for localization.
13163
- *
13164
- * @type {string}
13165
- * @private
13166
- *
13167
- * @deprecated in v7; controlText_ is not used in non-active display Components
13168
- */
13169
- CurrentTimeDisplay.prototype.controlText_ = 'Current Time';
13170
-
13171
- Component.registerComponent('CurrentTimeDisplay', CurrentTimeDisplay);
13172
-
13173
- /**
13174
- * @file duration-display.js
13175
- */
13176
-
13177
- /**
13178
- * Displays the duration
13179
- *
13180
- * @extends Component
13181
- */
13182
-
13183
- var DurationDisplay = function (_TimeDisplay) {
13184
- inherits(DurationDisplay, _TimeDisplay);
13185
-
13186
- /**
13187
- * Creates an instance of this class.
13188
- *
13189
- * @param {Player} player
13190
- * The `Player` that this class should be attached to.
13191
- *
13192
- * @param {Object} [options]
13193
- * The key/value store of player options.
13194
- */
13195
- function DurationDisplay(player, options) {
13196
- classCallCheck(this, DurationDisplay);
13197
-
13198
- // we do not want to/need to throttle duration changes,
13199
- // as they should always display the changed duration as
13200
- // it has changed
13201
- var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options));
13202
-
13203
- _this.on(player, 'durationchange', _this.updateContent);
13204
-
13205
- // Also listen for timeupdate (in the parent) and loadedmetadata because removing those
13206
- // listeners could have broken dependent applications/libraries. These
13207
- // can likely be removed for 7.0.
13208
- _this.on(player, 'loadedmetadata', _this.throttledUpdateContent);
13209
- return _this;
13210
- }
13211
-
13212
- /**
13213
- * Builds the default DOM `className`.
13214
- *
13215
- * @return {string}
13216
- * The DOM `className` for this object.
13217
- */
13218
-
13219
-
13220
- DurationDisplay.prototype.buildCSSClass = function buildCSSClass() {
13221
- return 'vjs-duration';
13222
- };
13223
-
13224
- /**
13225
- * Update duration time display.
13226
- *
13227
- * @param {EventTarget~Event} [event]
13228
- * The `durationchange`, `timeupdate`, or `loadedmetadata` event that caused
13229
- * this function to be called.
13230
- *
13231
- * @listens Player#durationchange
13232
- * @listens Player#timeupdate
13233
- * @listens Player#loadedmetadata
13234
- */
13235
-
13236
-
13237
- DurationDisplay.prototype.updateContent = function updateContent(event) {
13238
- var duration = this.player_.duration();
13239
-
13240
- if (duration && this.duration_ !== duration) {
13241
- this.duration_ = duration;
13242
- this.updateFormattedTime_(duration);
13243
- }
13244
- };
13245
-
13246
- return DurationDisplay;
13247
- }(TimeDisplay);
13248
-
13249
- /**
13250
- * The text that is added to the `DurationDisplay` for screen reader users.
13251
- *
13252
- * @type {string}
13253
- * @private
13254
- */
13255
-
13256
-
13257
- DurationDisplay.prototype.labelText_ = 'Duration';
13258
-
13259
- /**
13260
- * The text that should display over the `DurationDisplay`s controls. Added to for localization.
13261
- *
13262
- * @type {string}
13263
- * @private
13264
- *
13265
- * @deprecated in v7; controlText_ is not used in non-active display Components
13266
- */
13267
- DurationDisplay.prototype.controlText_ = 'Duration';
13268
-
13269
- Component.registerComponent('DurationDisplay', DurationDisplay);
13270
-
13271
- /**
13272
- * @file time-divider.js
13273
- */
13274
-
13275
- /**
13276
- * The separator between the current time and duration.
13277
- * Can be hidden if it's not needed in the design.
13278
- *
13279
- * @extends Component
13280
- */
13281
-
13282
- var TimeDivider = function (_Component) {
13283
- inherits(TimeDivider, _Component);
13284
-
13285
- function TimeDivider() {
13286
- classCallCheck(this, TimeDivider);
13287
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
13288
- }
13289
-
13290
- /**
13291
- * Create the component's DOM element
13292
- *
13293
- * @return {Element}
13294
- * The element that was created.
13295
- */
13296
- TimeDivider.prototype.createEl = function createEl() {
13297
- return _Component.prototype.createEl.call(this, 'div', {
13298
- className: 'vjs-time-control vjs-time-divider',
13299
- innerHTML: '<div><span>/</span></div>'
13300
- });
13301
- };
13302
-
13303
- return TimeDivider;
13304
- }(Component);
13305
-
13306
- Component.registerComponent('TimeDivider', TimeDivider);
13307
-
13308
- /**
13309
- * @file remaining-time-display.js
13310
- */
13311
- /**
13312
- * Displays the time left in the video
13313
- *
13314
- * @extends Component
13315
- */
13316
-
13317
- var RemainingTimeDisplay = function (_TimeDisplay) {
13318
- inherits(RemainingTimeDisplay, _TimeDisplay);
13319
-
13320
- /**
13321
- * Creates an instance of this class.
13322
- *
13323
- * @param {Player} player
13324
- * The `Player` that this class should be attached to.
13325
- *
13326
- * @param {Object} [options]
13327
- * The key/value store of player options.
13328
- */
13329
- function RemainingTimeDisplay(player, options) {
13330
- classCallCheck(this, RemainingTimeDisplay);
13331
-
13332
- var _this = possibleConstructorReturn(this, _TimeDisplay.call(this, player, options));
13333
-
13334
- _this.on(player, 'durationchange', _this.throttledUpdateContent);
13335
- _this.on(player, 'ended', _this.handleEnded);
13336
- return _this;
13337
- }
13338
-
13339
- /**
13340
- * Builds the default DOM `className`.
13341
- *
13342
- * @return {string}
13343
- * The DOM `className` for this object.
13344
- */
13345
-
13346
-
13347
- RemainingTimeDisplay.prototype.buildCSSClass = function buildCSSClass() {
13348
- return 'vjs-remaining-time';
13349
- };
13350
-
13351
- /**
13352
- * The remaining time display prefixes numbers with a "minus" character.
13353
- *
13354
- * @param {number} time
13355
- * A numeric time, in seconds.
13356
- *
13357
- * @return {string}
13358
- * A formatted time
13359
- *
13360
- * @private
13361
- */
13362
-
13363
-
13364
- RemainingTimeDisplay.prototype.formatTime_ = function formatTime_(time) {
13365
- // TODO: The "-" should be decorative, and not announced by a screen reader
13366
- return '-' + _TimeDisplay.prototype.formatTime_.call(this, time);
13367
- };
13368
-
13369
- /**
13370
- * Update remaining time display.
13371
- *
13372
- * @param {EventTarget~Event} [event]
13373
- * The `timeupdate` or `durationchange` event that caused this to run.
13374
- *
13375
- * @listens Player#timeupdate
13376
- * @listens Player#durationchange
13377
- */
13378
-
13379
-
13380
- RemainingTimeDisplay.prototype.updateContent = function updateContent(event) {
13381
- if (!this.player_.duration()) {
13382
- return;
13383
- }
13384
-
13385
- // @deprecated We should only use remainingTimeDisplay
13386
- // as of video.js 7
13387
- if (this.player_.remainingTimeDisplay) {
13388
- this.updateFormattedTime_(this.player_.remainingTimeDisplay());
13389
- } else {
13390
- this.updateFormattedTime_(this.player_.remainingTime());
13391
- }
13392
- };
13393
-
13394
- /**
13395
- * When the player fires ended there should be no time left. Sadly
13396
- * this is not always the case, lets make it seem like that is the case
13397
- * for users.
13398
- *
13399
- * @param {EventTarget~Event} [event]
13400
- * The `ended` event that caused this to run.
13401
- *
13402
- * @listens Player#ended
13403
- */
13404
-
13405
-
13406
- RemainingTimeDisplay.prototype.handleEnded = function handleEnded(event) {
13407
- if (!this.player_.duration()) {
13408
- return;
13409
- }
13410
- this.updateFormattedTime_(0);
13411
- };
13412
-
13413
- return RemainingTimeDisplay;
13414
- }(TimeDisplay);
13415
-
13416
- /**
13417
- * The text that is added to the `RemainingTimeDisplay` for screen reader users.
13418
- *
13419
- * @type {string}
13420
- * @private
13421
- */
13422
-
13423
-
13424
- RemainingTimeDisplay.prototype.labelText_ = 'Remaining Time';
13425
-
13426
- /**
13427
- * The text that should display over the `RemainingTimeDisplay`s controls. Added to for localization.
13428
- *
13429
- * @type {string}
13430
- * @private
13431
- *
13432
- * @deprecated in v7; controlText_ is not used in non-active display Components
13433
- */
13434
- RemainingTimeDisplay.prototype.controlText_ = 'Remaining Time';
13435
-
13436
- Component.registerComponent('RemainingTimeDisplay', RemainingTimeDisplay);
13437
-
13438
- /**
13439
- * @file live-display.js
13440
- */
13441
-
13442
- // TODO - Future make it click to snap to live
13443
-
13444
- /**
13445
- * Displays the live indicator when duration is Infinity.
13446
- *
13447
- * @extends Component
13448
- */
13449
-
13450
- var LiveDisplay = function (_Component) {
13451
- inherits(LiveDisplay, _Component);
13452
-
13453
- /**
13454
- * Creates an instance of this class.
13455
- *
13456
- * @param {Player} player
13457
- * The `Player` that this class should be attached to.
13458
- *
13459
- * @param {Object} [options]
13460
- * The key/value store of player options.
13461
- */
13462
- function LiveDisplay(player, options) {
13463
- classCallCheck(this, LiveDisplay);
13464
-
13465
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
13466
-
13467
- _this.updateShowing();
13468
- _this.on(_this.player(), 'durationchange', _this.updateShowing);
13469
- return _this;
13470
- }
13471
-
13472
- /**
13473
- * Create the `Component`'s DOM element
13474
- *
13475
- * @return {Element}
13476
- * The element that was created.
13477
- */
13478
-
13479
-
13480
- LiveDisplay.prototype.createEl = function createEl$$1() {
13481
- var el = _Component.prototype.createEl.call(this, 'div', {
13482
- className: 'vjs-live-control vjs-control'
13483
- });
13484
-
13485
- this.contentEl_ = createEl('div', {
13486
- className: 'vjs-live-display',
13487
- innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '\xA0</span>' + this.localize('LIVE')
13488
- }, {
13489
- 'aria-live': 'off'
13490
- });
13491
-
13492
- el.appendChild(this.contentEl_);
13493
- return el;
13494
- };
13495
-
13496
- LiveDisplay.prototype.dispose = function dispose() {
13497
- this.contentEl_ = null;
13498
-
13499
- _Component.prototype.dispose.call(this);
13500
- };
13501
-
13502
- /**
13503
- * Check the duration to see if the LiveDisplay should be showing or not. Then show/hide
13504
- * it accordingly
13505
- *
13506
- * @param {EventTarget~Event} [event]
13507
- * The {@link Player#durationchange} event that caused this function to run.
13508
- *
13509
- * @listens Player#durationchange
13510
- */
13511
-
13512
-
13513
- LiveDisplay.prototype.updateShowing = function updateShowing(event) {
13514
- if (this.player().duration() === Infinity) {
13515
- this.show();
13516
- } else {
13517
- this.hide();
13518
- }
13519
- };
13520
-
13521
- return LiveDisplay;
13522
- }(Component);
13523
-
13524
- Component.registerComponent('LiveDisplay', LiveDisplay);
13525
-
13526
- /**
13527
- * @file slider.js
13528
- */
13529
-
13530
- /**
13531
- * The base functionality for a slider. Can be vertical or horizontal.
13532
- * For instance the volume bar or the seek bar on a video is a slider.
13533
- *
13534
- * @extends Component
13535
- */
13536
-
13537
- var Slider = function (_Component) {
13538
- inherits(Slider, _Component);
13539
-
13540
- /**
13541
- * Create an instance of this class
13542
- *
13543
- * @param {Player} player
13544
- * The `Player` that this class should be attached to.
13545
- *
13546
- * @param {Object} [options]
13547
- * The key/value store of player options.
13548
- */
13549
- function Slider(player, options) {
13550
- classCallCheck(this, Slider);
13551
-
13552
- // Set property names to bar to match with the child Slider class is looking for
13553
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
13554
-
13555
- _this.bar = _this.getChild(_this.options_.barName);
13556
-
13557
- // Set a horizontal or vertical class on the slider depending on the slider type
13558
- _this.vertical(!!_this.options_.vertical);
13559
-
13560
- _this.enable();
13561
- return _this;
13562
- }
13563
-
13564
- /**
13565
- * Are controls are currently enabled for this slider or not.
13566
- *
13567
- * @return {boolean}
13568
- * true if controls are enabled, false otherwise
13569
- */
13570
-
13571
-
13572
- Slider.prototype.enabled = function enabled() {
13573
- return this.enabled_;
13574
- };
13575
-
13576
- /**
13577
- * Enable controls for this slider if they are disabled
13578
- */
13579
-
13580
-
13581
- Slider.prototype.enable = function enable() {
13582
- if (this.enabled()) {
13583
- return;
13584
- }
13585
-
13586
- this.on('mousedown', this.handleMouseDown);
13587
- this.on('touchstart', this.handleMouseDown);
13588
- this.on('focus', this.handleFocus);
13589
- this.on('blur', this.handleBlur);
13590
- this.on('click', this.handleClick);
13591
-
13592
- this.on(this.player_, 'controlsvisible', this.update);
13593
-
13594
- if (this.playerEvent) {
13595
- this.on(this.player_, this.playerEvent, this.update);
13596
- }
13597
-
13598
- this.removeClass('disabled');
13599
- this.setAttribute('tabindex', 0);
13600
-
13601
- this.enabled_ = true;
13602
- };
13603
-
13604
- /**
13605
- * Disable controls for this slider if they are enabled
13606
- */
13607
-
13608
-
13609
- Slider.prototype.disable = function disable() {
13610
- if (!this.enabled()) {
13611
- return;
13612
- }
13613
- var doc = this.bar.el_.ownerDocument;
13614
-
13615
- this.off('mousedown', this.handleMouseDown);
13616
- this.off('touchstart', this.handleMouseDown);
13617
- this.off('focus', this.handleFocus);
13618
- this.off('blur', this.handleBlur);
13619
- this.off('click', this.handleClick);
13620
- this.off(this.player_, 'controlsvisible', this.update);
13621
- this.off(doc, 'mousemove', this.handleMouseMove);
13622
- this.off(doc, 'mouseup', this.handleMouseUp);
13623
- this.off(doc, 'touchmove', this.handleMouseMove);
13624
- this.off(doc, 'touchend', this.handleMouseUp);
13625
- this.removeAttribute('tabindex');
13626
-
13627
- this.addClass('disabled');
13628
-
13629
- if (this.playerEvent) {
13630
- this.off(this.player_, this.playerEvent, this.update);
13631
- }
13632
- this.enabled_ = false;
13633
- };
13634
-
13635
- /**
13636
- * Create the `Slider`s DOM element.
13637
- *
13638
- * @param {string} type
13639
- * Type of element to create.
13640
- *
13641
- * @param {Object} [props={}]
13642
- * List of properties in Object form.
13643
- *
13644
- * @param {Object} [attributes={}]
13645
- * list of attributes in Object form.
13646
- *
13647
- * @return {Element}
13648
- * The element that gets created.
13649
- */
13650
-
13651
-
13652
- Slider.prototype.createEl = function createEl$$1(type) {
13653
- var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13654
- var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
13655
-
13656
- // Add the slider element class to all sub classes
13657
- props.className = props.className + ' vjs-slider';
13658
- props = assign({
13659
- tabIndex: 0
13660
- }, props);
13661
-
13662
- attributes = assign({
13663
- 'role': 'slider',
13664
- 'aria-valuenow': 0,
13665
- 'aria-valuemin': 0,
13666
- 'aria-valuemax': 100,
13667
- 'tabIndex': 0
13668
- }, attributes);
13669
-
13670
- return _Component.prototype.createEl.call(this, type, props, attributes);
13671
- };
13672
-
13673
- /**
13674
- * Handle `mousedown` or `touchstart` events on the `Slider`.
13675
- *
13676
- * @param {EventTarget~Event} event
13677
- * `mousedown` or `touchstart` event that triggered this function
13678
- *
13679
- * @listens mousedown
13680
- * @listens touchstart
13681
- * @fires Slider#slideractive
13682
- */
13683
-
13684
-
13685
- Slider.prototype.handleMouseDown = function handleMouseDown(event) {
13686
- var doc = this.bar.el_.ownerDocument;
13687
-
13688
- if (event.type === 'mousedown') {
13689
- event.preventDefault();
13690
- }
13691
- // Do not call preventDefault() on touchstart in Chrome
13692
- // to avoid console warnings. Use a 'touch-action: none' style
13693
- // instead to prevent unintented scrolling.
13694
- // https://developers.google.com/web/updates/2017/01/scrolling-intervention
13695
- if (event.type === 'touchstart' && !IS_CHROME) {
13696
- event.preventDefault();
13697
- }
13698
- blockTextSelection();
13699
-
13700
- this.addClass('vjs-sliding');
13701
- /**
13702
- * Triggered when the slider is in an active state
13703
- *
13704
- * @event Slider#slideractive
13705
- * @type {EventTarget~Event}
13706
- */
13707
- this.trigger('slideractive');
13708
-
13709
- this.on(doc, 'mousemove', this.handleMouseMove);
13710
- this.on(doc, 'mouseup', this.handleMouseUp);
13711
- this.on(doc, 'touchmove', this.handleMouseMove);
13712
- this.on(doc, 'touchend', this.handleMouseUp);
13713
-
13714
- this.handleMouseMove(event);
13715
- };
13716
-
13717
- /**
13718
- * Handle the `mousemove`, `touchmove`, and `mousedown` events on this `Slider`.
13719
- * The `mousemove` and `touchmove` events will only only trigger this function during
13720
- * `mousedown` and `touchstart`. This is due to {@link Slider#handleMouseDown} and
13721
- * {@link Slider#handleMouseUp}.
13722
- *
13723
- * @param {EventTarget~Event} event
13724
- * `mousedown`, `mousemove`, `touchstart`, or `touchmove` event that triggered
13725
- * this function
13726
- *
13727
- * @listens mousemove
13728
- * @listens touchmove
13729
- */
13730
-
13731
-
13732
- Slider.prototype.handleMouseMove = function handleMouseMove(event) {};
13733
-
13734
- /**
13735
- * Handle `mouseup` or `touchend` events on the `Slider`.
13736
- *
13737
- * @param {EventTarget~Event} event
13738
- * `mouseup` or `touchend` event that triggered this function.
13739
- *
13740
- * @listens touchend
13741
- * @listens mouseup
13742
- * @fires Slider#sliderinactive
13743
- */
13744
-
13745
-
13746
- Slider.prototype.handleMouseUp = function handleMouseUp() {
13747
- var doc = this.bar.el_.ownerDocument;
13748
-
13749
- unblockTextSelection();
13750
-
13751
- this.removeClass('vjs-sliding');
13752
- /**
13753
- * Triggered when the slider is no longer in an active state.
13754
- *
13755
- * @event Slider#sliderinactive
13756
- * @type {EventTarget~Event}
13757
- */
13758
- this.trigger('sliderinactive');
13759
-
13760
- this.off(doc, 'mousemove', this.handleMouseMove);
13761
- this.off(doc, 'mouseup', this.handleMouseUp);
13762
- this.off(doc, 'touchmove', this.handleMouseMove);
13763
- this.off(doc, 'touchend', this.handleMouseUp);
13764
-
13765
- this.update();
13766
- };
13767
-
13768
- /**
13769
- * Update the progress bar of the `Slider`.
13770
- *
13771
- * @returns {number}
13772
- * The percentage of progress the progress bar represents as a
13773
- * number from 0 to 1.
13774
- */
13775
-
13776
-
13777
- Slider.prototype.update = function update() {
13778
-
13779
- // In VolumeBar init we have a setTimeout for update that pops and update
13780
- // to the end of the execution stack. The player is destroyed before then
13781
- // update will cause an error
13782
- if (!this.el_) {
13783
- return;
13784
- }
13785
-
13786
- // If scrubbing, we could use a cached value to make the handle keep up
13787
- // with the user's mouse. On HTML5 browsers scrubbing is really smooth, but
13788
- // some flash players are slow, so we might want to utilize this later.
13789
- // var progress = (this.player_.scrubbing()) ? this.player_.getCache().currentTime / this.player_.duration() : this.player_.currentTime() / this.player_.duration();
13790
- var progress = this.getPercent();
13791
- var bar = this.bar;
13792
-
13793
- // If there's no bar...
13794
- if (!bar) {
13795
- return;
13796
- }
13797
-
13798
- // Protect against no duration and other division issues
13799
- if (typeof progress !== 'number' || progress !== progress || progress < 0 || progress === Infinity) {
13800
- progress = 0;
13801
- }
13802
-
13803
- // Convert to a percentage for setting
13804
- var percentage = (progress * 100).toFixed(2) + '%';
13805
- var style = bar.el().style;
13806
-
13807
- // Set the new bar width or height
13808
- if (this.vertical()) {
13809
- style.height = percentage;
13810
- } else {
13811
- style.width = percentage;
13812
- }
13813
-
13814
- return progress;
13815
- };
13816
-
13817
- /**
13818
- * Calculate distance for slider
13819
- *
13820
- * @param {EventTarget~Event} event
13821
- * The event that caused this function to run.
13822
- *
13823
- * @return {number}
13824
- * The current position of the Slider.
13825
- * - position.x for vertical `Slider`s
13826
- * - position.y for horizontal `Slider`s
13827
- */
13828
-
13829
-
13830
- Slider.prototype.calculateDistance = function calculateDistance(event) {
13831
- var position = getPointerPosition(this.el_, event);
13832
-
13833
- if (this.vertical()) {
13834
- return position.y;
13835
- }
13836
- return position.x;
13837
- };
13838
-
13839
- /**
13840
- * Handle a `focus` event on this `Slider`.
13841
- *
13842
- * @param {EventTarget~Event} event
13843
- * The `focus` event that caused this function to run.
13844
- *
13845
- * @listens focus
13846
- */
13847
-
13848
-
13849
- Slider.prototype.handleFocus = function handleFocus() {
13850
- this.on(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress);
13851
- };
13852
-
13853
- /**
13854
- * Handle a `keydown` event on the `Slider`. Watches for left, rigth, up, and down
13855
- * arrow keys. This function will only be called when the slider has focus. See
13856
- * {@link Slider#handleFocus} and {@link Slider#handleBlur}.
13857
- *
13858
- * @param {EventTarget~Event} event
13859
- * the `keydown` event that caused this function to run.
13860
- *
13861
- * @listens keydown
13862
- */
13863
-
13864
-
13865
- Slider.prototype.handleKeyPress = function handleKeyPress(event) {
13866
- // Left and Down Arrows
13867
- if (event.which === 37 || event.which === 40) {
13868
- event.preventDefault();
13869
- this.stepBack();
13870
-
13871
- // Up and Right Arrows
13872
- } else if (event.which === 38 || event.which === 39) {
13873
- event.preventDefault();
13874
- this.stepForward();
13875
- }
13876
- };
13877
-
13878
- /**
13879
- * Handle a `blur` event on this `Slider`.
13880
- *
13881
- * @param {EventTarget~Event} event
13882
- * The `blur` event that caused this function to run.
13883
- *
13884
- * @listens blur
13885
- */
13886
-
13887
- Slider.prototype.handleBlur = function handleBlur() {
13888
- this.off(this.bar.el_.ownerDocument, 'keydown', this.handleKeyPress);
13889
- };
13890
-
13891
- /**
13892
- * Listener for click events on slider, used to prevent clicks
13893
- * from bubbling up to parent elements like button menus.
13894
- *
13895
- * @param {Object} event
13896
- * Event that caused this object to run
13897
- */
13898
-
13899
-
13900
- Slider.prototype.handleClick = function handleClick(event) {
13901
- event.stopImmediatePropagation();
13902
- event.preventDefault();
13903
- };
13904
-
13905
- /**
13906
- * Get/set if slider is horizontal for vertical
13907
- *
13908
- * @param {boolean} [bool]
13909
- * - true if slider is vertical,
13910
- * - false is horizontal
13911
- *
13912
- * @return {boolean}
13913
- * - true if slider is vertical, and getting
13914
- * - false if the slider is horizontal, and getting
13915
- */
13916
-
13917
-
13918
- Slider.prototype.vertical = function vertical(bool) {
13919
- if (bool === undefined) {
13920
- return this.vertical_ || false;
13921
- }
13922
-
13923
- this.vertical_ = !!bool;
13924
-
13925
- if (this.vertical_) {
13926
- this.addClass('vjs-slider-vertical');
13927
- } else {
13928
- this.addClass('vjs-slider-horizontal');
13929
- }
13930
- };
13931
-
13932
- return Slider;
13933
- }(Component);
13934
-
13935
- Component.registerComponent('Slider', Slider);
13936
-
13937
- /**
13938
- * @file load-progress-bar.js
13939
- */
13940
-
13941
- /**
13942
- * Shows loading progress
13943
- *
13944
- * @extends Component
13945
- */
13946
-
13947
- var LoadProgressBar = function (_Component) {
13948
- inherits(LoadProgressBar, _Component);
13949
-
13950
- /**
13951
- * Creates an instance of this class.
13952
- *
13953
- * @param {Player} player
13954
- * The `Player` that this class should be attached to.
13955
- *
13956
- * @param {Object} [options]
13957
- * The key/value store of player options.
13958
- */
13959
- function LoadProgressBar(player, options) {
13960
- classCallCheck(this, LoadProgressBar);
13961
-
13962
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
13963
-
13964
- _this.partEls_ = [];
13965
- _this.on(player, 'progress', _this.update);
13966
- return _this;
13967
- }
13968
-
13969
- /**
13970
- * Create the `Component`'s DOM element
13971
- *
13972
- * @return {Element}
13973
- * The element that was created.
13974
- */
13975
-
13976
-
13977
- LoadProgressBar.prototype.createEl = function createEl$$1() {
13978
- return _Component.prototype.createEl.call(this, 'div', {
13979
- className: 'vjs-load-progress',
13980
- innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>'
13981
- });
13982
- };
13983
-
13984
- LoadProgressBar.prototype.dispose = function dispose() {
13985
- this.partEls_ = null;
13986
-
13987
- _Component.prototype.dispose.call(this);
13988
- };
13989
-
13990
- /**
13991
- * Update progress bar
13992
- *
13993
- * @param {EventTarget~Event} [event]
13994
- * The `progress` event that caused this function to run.
13995
- *
13996
- * @listens Player#progress
13997
- */
13998
-
13999
-
14000
- LoadProgressBar.prototype.update = function update(event) {
14001
- var buffered = this.player_.buffered();
14002
- var duration = this.player_.duration();
14003
- var bufferedEnd = this.player_.bufferedEnd();
14004
- var children = this.partEls_;
14005
-
14006
- // get the percent width of a time compared to the total end
14007
- var percentify = function percentify(time, end) {
14008
- // no NaN
14009
- var percent = time / end || 0;
14010
-
14011
- return (percent >= 1 ? 1 : percent) * 100 + '%';
14012
- };
14013
-
14014
- // update the width of the progress bar
14015
- this.el_.style.width = percentify(bufferedEnd, duration);
14016
-
14017
- // add child elements to represent the individual buffered time ranges
14018
- for (var i = 0; i < buffered.length; i++) {
14019
- var start = buffered.start(i);
14020
- var end = buffered.end(i);
14021
- var part = children[i];
14022
-
14023
- if (!part) {
14024
- part = this.el_.appendChild(createEl());
14025
- children[i] = part;
14026
- }
14027
-
14028
- // set the percent based on the width of the progress bar (bufferedEnd)
14029
- part.style.left = percentify(start, bufferedEnd);
14030
- part.style.width = percentify(end - start, bufferedEnd);
14031
- }
14032
-
14033
- // remove unused buffered range elements
14034
- for (var _i = children.length; _i > buffered.length; _i--) {
14035
- this.el_.removeChild(children[_i - 1]);
14036
- }
14037
- children.length = buffered.length;
14038
- };
14039
-
14040
- return LoadProgressBar;
14041
- }(Component);
14042
-
14043
- Component.registerComponent('LoadProgressBar', LoadProgressBar);
14044
-
14045
- /**
14046
- * @file time-tooltip.js
14047
- */
14048
-
14049
- /**
14050
- * Time tooltips display a time above the progress bar.
14051
- *
14052
- * @extends Component
14053
- */
14054
-
14055
- var TimeTooltip = function (_Component) {
14056
- inherits(TimeTooltip, _Component);
14057
-
14058
- function TimeTooltip() {
14059
- classCallCheck(this, TimeTooltip);
14060
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
14061
- }
14062
-
14063
- /**
14064
- * Create the time tooltip DOM element
14065
- *
14066
- * @return {Element}
14067
- * The element that was created.
14068
- */
14069
- TimeTooltip.prototype.createEl = function createEl$$1() {
14070
- return _Component.prototype.createEl.call(this, 'div', {
14071
- className: 'vjs-time-tooltip'
14072
- });
14073
- };
14074
-
14075
- /**
14076
- * Updates the position of the time tooltip relative to the `SeekBar`.
14077
- *
14078
- * @param {Object} seekBarRect
14079
- * The `ClientRect` for the {@link SeekBar} element.
14080
- *
14081
- * @param {number} seekBarPoint
14082
- * A number from 0 to 1, representing a horizontal reference point
14083
- * from the left edge of the {@link SeekBar}
14084
- */
14085
-
14086
-
14087
- TimeTooltip.prototype.update = function update(seekBarRect, seekBarPoint, content) {
14088
- var tooltipRect = getBoundingClientRect(this.el_);
14089
- var playerRect = getBoundingClientRect(this.player_.el());
14090
- var seekBarPointPx = seekBarRect.width * seekBarPoint;
14091
-
14092
- // do nothing if either rect isn't available
14093
- // for example, if the player isn't in the DOM for testing
14094
- if (!playerRect || !tooltipRect) {
14095
- return;
14096
- }
14097
-
14098
- // This is the space left of the `seekBarPoint` available within the bounds
14099
- // of the player. We calculate any gap between the left edge of the player
14100
- // and the left edge of the `SeekBar` and add the number of pixels in the
14101
- // `SeekBar` before hitting the `seekBarPoint`
14102
- var spaceLeftOfPoint = seekBarRect.left - playerRect.left + seekBarPointPx;
14103
-
14104
- // This is the space right of the `seekBarPoint` available within the bounds
14105
- // of the player. We calculate the number of pixels from the `seekBarPoint`
14106
- // to the right edge of the `SeekBar` and add to that any gap between the
14107
- // right edge of the `SeekBar` and the player.
14108
- var spaceRightOfPoint = seekBarRect.width - seekBarPointPx + (playerRect.right - seekBarRect.right);
14109
-
14110
- // This is the number of pixels by which the tooltip will need to be pulled
14111
- // further to the right to center it over the `seekBarPoint`.
14112
- var pullTooltipBy = tooltipRect.width / 2;
14113
-
14114
- // Adjust the `pullTooltipBy` distance to the left or right depending on
14115
- // the results of the space calculations above.
14116
- if (spaceLeftOfPoint < pullTooltipBy) {
14117
- pullTooltipBy += pullTooltipBy - spaceLeftOfPoint;
14118
- } else if (spaceRightOfPoint < pullTooltipBy) {
14119
- pullTooltipBy = spaceRightOfPoint;
14120
- }
14121
-
14122
- // Due to the imprecision of decimal/ratio based calculations and varying
14123
- // rounding behaviors, there are cases where the spacing adjustment is off
14124
- // by a pixel or two. This adds insurance to these calculations.
14125
- if (pullTooltipBy < 0) {
14126
- pullTooltipBy = 0;
14127
- } else if (pullTooltipBy > tooltipRect.width) {
14128
- pullTooltipBy = tooltipRect.width;
14129
- }
14130
-
14131
- this.el_.style.right = '-' + pullTooltipBy + 'px';
14132
- textContent(this.el_, content);
14133
- };
14134
-
14135
- return TimeTooltip;
14136
- }(Component);
14137
-
14138
- Component.registerComponent('TimeTooltip', TimeTooltip);
14139
-
14140
- /**
14141
- * @file play-progress-bar.js
14142
- */
14143
-
14144
- /**
14145
- * Used by {@link SeekBar} to display media playback progress as part of the
14146
- * {@link ProgressControl}.
14147
- *
14148
- * @extends Component
14149
- */
14150
-
14151
- var PlayProgressBar = function (_Component) {
14152
- inherits(PlayProgressBar, _Component);
14153
-
14154
- function PlayProgressBar() {
14155
- classCallCheck(this, PlayProgressBar);
14156
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
14157
- }
14158
-
14159
- /**
14160
- * Create the the DOM element for this class.
14161
- *
14162
- * @return {Element}
14163
- * The element that was created.
14164
- */
14165
- PlayProgressBar.prototype.createEl = function createEl() {
14166
- return _Component.prototype.createEl.call(this, 'div', {
14167
- className: 'vjs-play-progress vjs-slider-bar',
14168
- innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
14169
- });
14170
- };
14171
-
14172
- /**
14173
- * Enqueues updates to its own DOM as well as the DOM of its
14174
- * {@link TimeTooltip} child.
14175
- *
14176
- * @param {Object} seekBarRect
14177
- * The `ClientRect` for the {@link SeekBar} element.
14178
- *
14179
- * @param {number} seekBarPoint
14180
- * A number from 0 to 1, representing a horizontal reference point
14181
- * from the left edge of the {@link SeekBar}
14182
- */
14183
-
14184
-
14185
- PlayProgressBar.prototype.update = function update(seekBarRect, seekBarPoint) {
14186
- var _this2 = this;
14187
-
14188
- // If there is an existing rAF ID, cancel it so we don't over-queue.
14189
- if (this.rafId_) {
14190
- this.cancelAnimationFrame(this.rafId_);
14191
- }
14192
-
14193
- this.rafId_ = this.requestAnimationFrame(function () {
14194
- var time = _this2.player_.scrubbing() ? _this2.player_.getCache().currentTime : _this2.player_.currentTime();
14195
-
14196
- var content = formatTime(time, _this2.player_.duration());
14197
- var timeTooltip = _this2.getChild('timeTooltip');
14198
-
14199
- if (timeTooltip) {
14200
- timeTooltip.update(seekBarRect, seekBarPoint, content);
14201
- }
14202
- });
14203
- };
14204
-
14205
- return PlayProgressBar;
14206
- }(Component);
14207
-
14208
- /**
14209
- * Default options for {@link PlayProgressBar}.
14210
- *
14211
- * @type {Object}
14212
- * @private
14213
- */
14214
-
14215
-
14216
- PlayProgressBar.prototype.options_ = {
14217
- children: []
14218
- };
14219
-
14220
- // Time tooltips should not be added to a player on mobile devices
14221
- if (!IS_IOS && !IS_ANDROID) {
14222
- PlayProgressBar.prototype.options_.children.push('timeTooltip');
14223
- }
14224
-
14225
- Component.registerComponent('PlayProgressBar', PlayProgressBar);
14226
-
14227
- /**
14228
- * @file mouse-time-display.js
14229
- */
14230
-
14231
- /**
14232
- * The {@link MouseTimeDisplay} component tracks mouse movement over the
14233
- * {@link ProgressControl}. It displays an indicator and a {@link TimeTooltip}
14234
- * indicating the time which is represented by a given point in the
14235
- * {@link ProgressControl}.
14236
- *
14237
- * @extends Component
14238
- */
14239
-
14240
- var MouseTimeDisplay = function (_Component) {
14241
- inherits(MouseTimeDisplay, _Component);
14242
-
14243
- /**
14244
- * Creates an instance of this class.
14245
- *
14246
- * @param {Player} player
14247
- * The {@link Player} that this class should be attached to.
14248
- *
14249
- * @param {Object} [options]
14250
- * The key/value store of player options.
14251
- */
14252
- function MouseTimeDisplay(player, options) {
14253
- classCallCheck(this, MouseTimeDisplay);
14254
-
14255
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
14256
-
14257
- _this.update = throttle(bind(_this, _this.update), 25);
14258
- return _this;
14259
- }
14260
-
14261
- /**
14262
- * Create the DOM element for this class.
14263
- *
14264
- * @return {Element}
14265
- * The element that was created.
14266
- */
14267
-
14268
-
14269
- MouseTimeDisplay.prototype.createEl = function createEl() {
14270
- return _Component.prototype.createEl.call(this, 'div', {
14271
- className: 'vjs-mouse-display'
14272
- });
14273
- };
14274
-
14275
- /**
14276
- * Enqueues updates to its own DOM as well as the DOM of its
14277
- * {@link TimeTooltip} child.
14278
- *
14279
- * @param {Object} seekBarRect
14280
- * The `ClientRect` for the {@link SeekBar} element.
14281
- *
14282
- * @param {number} seekBarPoint
14283
- * A number from 0 to 1, representing a horizontal reference point
14284
- * from the left edge of the {@link SeekBar}
14285
- */
14286
-
14287
-
14288
- MouseTimeDisplay.prototype.update = function update(seekBarRect, seekBarPoint) {
14289
- var _this2 = this;
14290
-
14291
- // If there is an existing rAF ID, cancel it so we don't over-queue.
14292
- if (this.rafId_) {
14293
- this.cancelAnimationFrame(this.rafId_);
14294
- }
14295
-
14296
- this.rafId_ = this.requestAnimationFrame(function () {
14297
- var duration = _this2.player_.duration();
14298
- var content = formatTime(seekBarPoint * duration, duration);
14299
-
14300
- _this2.el_.style.left = seekBarRect.width * seekBarPoint + 'px';
14301
- _this2.getChild('timeTooltip').update(seekBarRect, seekBarPoint, content);
14302
- });
14303
- };
14304
-
14305
- return MouseTimeDisplay;
14306
- }(Component);
14307
-
14308
- /**
14309
- * Default options for `MouseTimeDisplay`
14310
- *
14311
- * @type {Object}
14312
- * @private
14313
- */
14314
-
14315
-
14316
- MouseTimeDisplay.prototype.options_ = {
14317
- children: ['timeTooltip']
14318
- };
14319
-
14320
- Component.registerComponent('MouseTimeDisplay', MouseTimeDisplay);
14321
-
14322
- /**
14323
- * @file seek-bar.js
14324
- */
14325
-
14326
- // The number of seconds the `step*` functions move the timeline.
14327
- var STEP_SECONDS = 5;
14328
-
14329
- // The interval at which the bar should update as it progresses.
14330
- var UPDATE_REFRESH_INTERVAL = 30;
14331
-
14332
- /**
14333
- * Seek bar and container for the progress bars. Uses {@link PlayProgressBar}
14334
- * as its `bar`.
14335
- *
14336
- * @extends Slider
14337
- */
14338
-
14339
- var SeekBar = function (_Slider) {
14340
- inherits(SeekBar, _Slider);
14341
-
14342
- /**
14343
- * Creates an instance of this class.
14344
- *
14345
- * @param {Player} player
14346
- * The `Player` that this class should be attached to.
14347
- *
14348
- * @param {Object} [options]
14349
- * The key/value store of player options.
14350
- */
14351
- function SeekBar(player, options) {
14352
- classCallCheck(this, SeekBar);
14353
-
14354
- var _this = possibleConstructorReturn(this, _Slider.call(this, player, options));
14355
-
14356
- _this.setEventHandlers_();
14357
- return _this;
14358
- }
14359
-
14360
- /**
14361
- * Sets the event handlers
14362
- *
14363
- * @private
14364
- */
14365
-
14366
-
14367
- SeekBar.prototype.setEventHandlers_ = function setEventHandlers_() {
14368
- var _this2 = this;
14369
-
14370
- this.update = throttle(bind(this, this.update), UPDATE_REFRESH_INTERVAL);
14371
-
14372
- this.on(this.player_, 'timeupdate', this.update);
14373
- this.on(this.player_, 'ended', this.handleEnded);
14374
-
14375
- // when playing, let's ensure we smoothly update the play progress bar
14376
- // via an interval
14377
- this.updateInterval = null;
14378
-
14379
- this.on(this.player_, ['playing'], function () {
14380
- _this2.clearInterval(_this2.updateInterval);
14381
-
14382
- _this2.updateInterval = _this2.setInterval(function () {
14383
- _this2.requestAnimationFrame(function () {
14384
- _this2.update();
14385
- });
14386
- }, UPDATE_REFRESH_INTERVAL);
14387
- });
14388
-
14389
- this.on(this.player_, ['ended', 'pause', 'waiting'], function () {
14390
- _this2.clearInterval(_this2.updateInterval);
14391
- });
14392
-
14393
- this.on(this.player_, ['timeupdate', 'ended'], this.update);
14394
- };
14395
-
14396
- /**
14397
- * Create the `Component`'s DOM element
14398
- *
14399
- * @return {Element}
14400
- * The element that was created.
14401
- */
14402
-
14403
-
14404
- SeekBar.prototype.createEl = function createEl$$1() {
14405
- return _Slider.prototype.createEl.call(this, 'div', {
14406
- className: 'vjs-progress-holder'
14407
- }, {
14408
- 'aria-label': this.localize('Progress Bar')
14409
- });
14410
- };
14411
-
14412
- /**
14413
- * This function updates the play progress bar and accessibility
14414
- * attributes to whatever is passed in.
14415
- *
14416
- * @param {number} currentTime
14417
- * The currentTime value that should be used for accessibility
14418
- *
14419
- * @param {number} percent
14420
- * The percentage as a decimal that the bar should be filled from 0-1.
14421
- *
14422
- * @private
14423
- */
14424
-
14425
-
14426
- SeekBar.prototype.update_ = function update_(currentTime, percent) {
14427
- var duration = this.player_.duration();
14428
-
14429
- // machine readable value of progress bar (percentage complete)
14430
- this.el_.setAttribute('aria-valuenow', (percent * 100).toFixed(2));
14431
-
14432
- // human readable value of progress bar (time complete)
14433
- this.el_.setAttribute('aria-valuetext', this.localize('progress bar timing: currentTime={1} duration={2}', [formatTime(currentTime, duration), formatTime(duration, duration)], '{1} of {2}'));
14434
-
14435
- // Update the `PlayProgressBar`.
14436
- this.bar.update(getBoundingClientRect(this.el_), percent);
14437
- };
14438
-
14439
- /**
14440
- * Update the seek bar's UI.
14441
- *
14442
- * @param {EventTarget~Event} [event]
14443
- * The `timeupdate` or `ended` event that caused this to run.
14444
- *
14445
- * @listens Player#timeupdate
14446
- *
14447
- * @returns {number}
14448
- * The current percent at a number from 0-1
14449
- */
14450
-
14451
-
14452
- SeekBar.prototype.update = function update(event) {
14453
- var percent = _Slider.prototype.update.call(this);
14454
-
14455
- this.update_(this.getCurrentTime_(), percent);
14456
- return percent;
14457
- };
14458
-
14459
- /**
14460
- * Get the value of current time but allows for smooth scrubbing,
14461
- * when player can't keep up.
14462
- *
14463
- * @return {number}
14464
- * The current time value to display
14465
- *
14466
- * @private
14467
- */
14468
-
14469
-
14470
- SeekBar.prototype.getCurrentTime_ = function getCurrentTime_() {
14471
- return this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
14472
- };
14473
-
14474
- /**
14475
- * We want the seek bar to be full on ended
14476
- * no matter what the actual internal values are. so we force it.
14477
- *
14478
- * @param {EventTarget~Event} [event]
14479
- * The `timeupdate` or `ended` event that caused this to run.
14480
- *
14481
- * @listens Player#ended
14482
- */
14483
-
14484
-
14485
- SeekBar.prototype.handleEnded = function handleEnded(event) {
14486
- this.update_(this.player_.duration(), 1);
14487
- };
14488
-
14489
- /**
14490
- * Get the percentage of media played so far.
14491
- *
14492
- * @return {number}
14493
- * The percentage of media played so far (0 to 1).
14494
- */
14495
-
14496
-
14497
- SeekBar.prototype.getPercent = function getPercent() {
14498
- var percent = this.getCurrentTime_() / this.player_.duration();
14499
-
14500
- return percent >= 1 ? 1 : percent || 0;
14501
- };
14502
-
14503
- /**
14504
- * Handle mouse down on seek bar
14505
- *
14506
- * @param {EventTarget~Event} event
14507
- * The `mousedown` event that caused this to run.
14508
- *
14509
- * @listens mousedown
14510
- */
14511
-
14512
-
14513
- SeekBar.prototype.handleMouseDown = function handleMouseDown(event) {
14514
- if (!isSingleLeftClick(event)) {
14515
- return;
14516
- }
14517
-
14518
- // Stop event propagation to prevent double fire in progress-control.js
14519
- event.stopPropagation();
14520
- this.player_.scrubbing(true);
14521
-
14522
- this.videoWasPlaying = !this.player_.paused();
14523
- this.player_.pause();
14524
-
14525
- _Slider.prototype.handleMouseDown.call(this, event);
14526
- };
14527
-
14528
- /**
14529
- * Handle mouse move on seek bar
14530
- *
14531
- * @param {EventTarget~Event} event
14532
- * The `mousemove` event that caused this to run.
14533
- *
14534
- * @listens mousemove
14535
- */
14536
-
14537
-
14538
- SeekBar.prototype.handleMouseMove = function handleMouseMove(event) {
14539
- if (!isSingleLeftClick(event)) {
14540
- return;
14541
- }
14542
-
14543
- var newTime = this.calculateDistance(event) * this.player_.duration();
14544
-
14545
- // Don't let video end while scrubbing.
14546
- if (newTime === this.player_.duration()) {
14547
- newTime = newTime - 0.1;
14548
- }
14549
-
14550
- // Set new time (tell player to seek to new time)
14551
- this.player_.currentTime(newTime);
14552
- };
14553
-
14554
- SeekBar.prototype.enable = function enable() {
14555
- _Slider.prototype.enable.call(this);
14556
- var mouseTimeDisplay = this.getChild('mouseTimeDisplay');
14557
-
14558
- if (!mouseTimeDisplay) {
14559
- return;
14560
- }
14561
-
14562
- mouseTimeDisplay.show();
14563
- };
14564
-
14565
- SeekBar.prototype.disable = function disable() {
14566
- _Slider.prototype.disable.call(this);
14567
- var mouseTimeDisplay = this.getChild('mouseTimeDisplay');
14568
-
14569
- if (!mouseTimeDisplay) {
14570
- return;
14571
- }
14572
-
14573
- mouseTimeDisplay.hide();
14574
- };
14575
-
14576
- /**
14577
- * Handle mouse up on seek bar
14578
- *
14579
- * @param {EventTarget~Event} event
14580
- * The `mouseup` event that caused this to run.
14581
- *
14582
- * @listens mouseup
14583
- */
14584
-
14585
-
14586
- SeekBar.prototype.handleMouseUp = function handleMouseUp(event) {
14587
- _Slider.prototype.handleMouseUp.call(this, event);
14588
-
14589
- // Stop event propagation to prevent double fire in progress-control.js
14590
- if (event) {
14591
- event.stopPropagation();
14592
- }
14593
- this.player_.scrubbing(false);
14594
-
14595
- /**
14596
- * Trigger timeupdate because we're done seeking and the time has changed.
14597
- * This is particularly useful for if the player is paused to time the time displays.
14598
- *
14599
- * @event Tech#timeupdate
14600
- * @type {EventTarget~Event}
14601
- */
14602
- this.player_.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
14603
- if (this.videoWasPlaying) {
14604
- silencePromise(this.player_.play());
14605
- }
14606
- };
14607
-
14608
- /**
14609
- * Move more quickly fast forward for keyboard-only users
14610
- */
14611
-
14612
-
14613
- SeekBar.prototype.stepForward = function stepForward() {
14614
- this.player_.currentTime(this.player_.currentTime() + STEP_SECONDS);
14615
- };
14616
-
14617
- /**
14618
- * Move more quickly rewind for keyboard-only users
14619
- */
14620
-
14621
-
14622
- SeekBar.prototype.stepBack = function stepBack() {
14623
- this.player_.currentTime(this.player_.currentTime() - STEP_SECONDS);
14624
- };
14625
-
14626
- /**
14627
- * Toggles the playback state of the player
14628
- * This gets called when enter or space is used on the seekbar
14629
- *
14630
- * @param {EventTarget~Event} event
14631
- * The `keydown` event that caused this function to be called
14632
- *
14633
- */
14634
-
14635
-
14636
- SeekBar.prototype.handleAction = function handleAction(event) {
14637
- if (this.player_.paused()) {
14638
- this.player_.play();
14639
- } else {
14640
- this.player_.pause();
14641
- }
14642
- };
14643
-
14644
- /**
14645
- * Called when this SeekBar has focus and a key gets pressed down. By
14646
- * default it will call `this.handleAction` when the key is space or enter.
14647
- *
14648
- * @param {EventTarget~Event} event
14649
- * The `keydown` event that caused this function to be called.
14650
- *
14651
- * @listens keydown
14652
- */
14653
-
14654
-
14655
- SeekBar.prototype.handleKeyPress = function handleKeyPress(event) {
14656
-
14657
- // Support Space (32) or Enter (13) key operation to fire a click event
14658
- if (event.which === 32 || event.which === 13) {
14659
- event.preventDefault();
14660
- this.handleAction(event);
14661
- } else if (_Slider.prototype.handleKeyPress) {
14662
-
14663
- // Pass keypress handling up for unsupported keys
14664
- _Slider.prototype.handleKeyPress.call(this, event);
14665
- }
14666
- };
14667
-
14668
- return SeekBar;
14669
- }(Slider);
14670
-
14671
- /**
14672
- * Default options for the `SeekBar`
14673
- *
14674
- * @type {Object}
14675
- * @private
14676
- */
14677
-
14678
-
14679
- SeekBar.prototype.options_ = {
14680
- children: ['loadProgressBar', 'playProgressBar'],
14681
- barName: 'playProgressBar'
14682
- };
14683
-
14684
- // MouseTimeDisplay tooltips should not be added to a player on mobile devices
14685
- if (!IS_IOS && !IS_ANDROID) {
14686
- SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay');
14687
- }
14688
-
14689
- /**
14690
- * Call the update event for this Slider when this event happens on the player.
14691
- *
14692
- * @type {string}
14693
- */
14694
- SeekBar.prototype.playerEvent = 'timeupdate';
14695
-
14696
- Component.registerComponent('SeekBar', SeekBar);
14697
-
14698
- /**
14699
- * @file progress-control.js
14700
- */
14701
-
14702
- /**
14703
- * The Progress Control component contains the seek bar, load progress,
14704
- * and play progress.
14705
- *
14706
- * @extends Component
14707
- */
14708
-
14709
- var ProgressControl = function (_Component) {
14710
- inherits(ProgressControl, _Component);
14711
-
14712
- /**
14713
- * Creates an instance of this class.
14714
- *
14715
- * @param {Player} player
14716
- * The `Player` that this class should be attached to.
14717
- *
14718
- * @param {Object} [options]
14719
- * The key/value store of player options.
14720
- */
14721
- function ProgressControl(player, options) {
14722
- classCallCheck(this, ProgressControl);
14723
-
14724
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
14725
-
14726
- _this.handleMouseMove = throttle(bind(_this, _this.handleMouseMove), 25);
14727
- _this.throttledHandleMouseSeek = throttle(bind(_this, _this.handleMouseSeek), 25);
14728
-
14729
- _this.enable();
14730
- return _this;
14731
- }
14732
-
14733
- /**
14734
- * Create the `Component`'s DOM element
14735
- *
14736
- * @return {Element}
14737
- * The element that was created.
14738
- */
14739
-
14740
-
14741
- ProgressControl.prototype.createEl = function createEl$$1() {
14742
- return _Component.prototype.createEl.call(this, 'div', {
14743
- className: 'vjs-progress-control vjs-control'
14744
- });
14745
- };
14746
-
14747
- /**
14748
- * When the mouse moves over the `ProgressControl`, the pointer position
14749
- * gets passed down to the `MouseTimeDisplay` component.
14750
- *
14751
- * @param {EventTarget~Event} event
14752
- * The `mousemove` event that caused this function to run.
14753
- *
14754
- * @listen mousemove
14755
- */
14756
-
14757
-
14758
- ProgressControl.prototype.handleMouseMove = function handleMouseMove(event) {
14759
- var seekBar = this.getChild('seekBar');
14760
-
14761
- if (seekBar) {
14762
- var mouseTimeDisplay = seekBar.getChild('mouseTimeDisplay');
14763
- var seekBarEl = seekBar.el();
14764
- var seekBarRect = getBoundingClientRect(seekBarEl);
14765
- var seekBarPoint = getPointerPosition(seekBarEl, event).x;
14766
-
14767
- // The default skin has a gap on either side of the `SeekBar`. This means
14768
- // that it's possible to trigger this behavior outside the boundaries of
14769
- // the `SeekBar`. This ensures we stay within it at all times.
14770
- if (seekBarPoint > 1) {
14771
- seekBarPoint = 1;
14772
- } else if (seekBarPoint < 0) {
14773
- seekBarPoint = 0;
14774
- }
14775
-
14776
- if (mouseTimeDisplay) {
14777
- mouseTimeDisplay.update(seekBarRect, seekBarPoint);
14778
- }
14779
- }
14780
- };
14781
-
14782
- /**
14783
- * A throttled version of the {@link ProgressControl#handleMouseSeek} listener.
14784
- *
14785
- * @method ProgressControl#throttledHandleMouseSeek
14786
- * @param {EventTarget~Event} event
14787
- * The `mousemove` event that caused this function to run.
14788
- *
14789
- * @listen mousemove
14790
- * @listen touchmove
14791
- */
14792
-
14793
- /**
14794
- * Handle `mousemove` or `touchmove` events on the `ProgressControl`.
14795
- *
14796
- * @param {EventTarget~Event} event
14797
- * `mousedown` or `touchstart` event that triggered this function
14798
- *
14799
- * @listens mousemove
14800
- * @listens touchmove
14801
- */
14802
-
14803
-
14804
- ProgressControl.prototype.handleMouseSeek = function handleMouseSeek(event) {
14805
- var seekBar = this.getChild('seekBar');
14806
-
14807
- if (seekBar) {
14808
- seekBar.handleMouseMove(event);
14809
- }
14810
- };
14811
-
14812
- /**
14813
- * Are controls are currently enabled for this progress control.
14814
- *
14815
- * @return {boolean}
14816
- * true if controls are enabled, false otherwise
14817
- */
14818
-
14819
-
14820
- ProgressControl.prototype.enabled = function enabled() {
14821
- return this.enabled_;
14822
- };
14823
-
14824
- /**
14825
- * Disable all controls on the progress control and its children
14826
- */
14827
-
14828
-
14829
- ProgressControl.prototype.disable = function disable() {
14830
- this.children().forEach(function (child) {
14831
- return child.disable && child.disable();
14832
- });
14833
-
14834
- if (!this.enabled()) {
14835
- return;
14836
- }
14837
-
14838
- this.off(['mousedown', 'touchstart'], this.handleMouseDown);
14839
- this.off(this.el_, 'mousemove', this.handleMouseMove);
14840
- this.handleMouseUp();
14841
-
14842
- this.addClass('disabled');
14843
-
14844
- this.enabled_ = false;
14845
- };
14846
-
14847
- /**
14848
- * Enable all controls on the progress control and its children
14849
- */
14850
-
14851
-
14852
- ProgressControl.prototype.enable = function enable() {
14853
- this.children().forEach(function (child) {
14854
- return child.enable && child.enable();
14855
- });
14856
-
14857
- if (this.enabled()) {
14858
- return;
14859
- }
14860
-
14861
- this.on(['mousedown', 'touchstart'], this.handleMouseDown);
14862
- this.on(this.el_, 'mousemove', this.handleMouseMove);
14863
- this.removeClass('disabled');
14864
-
14865
- this.enabled_ = true;
14866
- };
14867
-
14868
- /**
14869
- * Handle `mousedown` or `touchstart` events on the `ProgressControl`.
14870
- *
14871
- * @param {EventTarget~Event} event
14872
- * `mousedown` or `touchstart` event that triggered this function
14873
- *
14874
- * @listens mousedown
14875
- * @listens touchstart
14876
- */
14877
-
14878
-
14879
- ProgressControl.prototype.handleMouseDown = function handleMouseDown(event) {
14880
- var doc = this.el_.ownerDocument;
14881
- var seekBar = this.getChild('seekBar');
14882
-
14883
- if (seekBar) {
14884
- seekBar.handleMouseDown(event);
14885
- }
14886
-
14887
- this.on(doc, 'mousemove', this.throttledHandleMouseSeek);
14888
- this.on(doc, 'touchmove', this.throttledHandleMouseSeek);
14889
- this.on(doc, 'mouseup', this.handleMouseUp);
14890
- this.on(doc, 'touchend', this.handleMouseUp);
14891
- };
14892
-
14893
- /**
14894
- * Handle `mouseup` or `touchend` events on the `ProgressControl`.
14895
- *
14896
- * @param {EventTarget~Event} event
14897
- * `mouseup` or `touchend` event that triggered this function.
14898
- *
14899
- * @listens touchend
14900
- * @listens mouseup
14901
- */
14902
-
14903
-
14904
- ProgressControl.prototype.handleMouseUp = function handleMouseUp(event) {
14905
- var doc = this.el_.ownerDocument;
14906
- var seekBar = this.getChild('seekBar');
14907
-
14908
- if (seekBar) {
14909
- seekBar.handleMouseUp(event);
14910
- }
14911
-
14912
- this.off(doc, 'mousemove', this.throttledHandleMouseSeek);
14913
- this.off(doc, 'touchmove', this.throttledHandleMouseSeek);
14914
- this.off(doc, 'mouseup', this.handleMouseUp);
14915
- this.off(doc, 'touchend', this.handleMouseUp);
14916
- };
14917
-
14918
- return ProgressControl;
14919
- }(Component);
14920
-
14921
- /**
14922
- * Default options for `ProgressControl`
14923
- *
14924
- * @type {Object}
14925
- * @private
14926
- */
14927
-
14928
-
14929
- ProgressControl.prototype.options_ = {
14930
- children: ['seekBar']
14931
- };
14932
-
14933
- Component.registerComponent('ProgressControl', ProgressControl);
14934
-
14935
- /**
14936
- * @file fullscreen-toggle.js
14937
- */
14938
-
14939
- /**
14940
- * Toggle fullscreen video
14941
- *
14942
- * @extends Button
14943
- */
14944
-
14945
- var FullscreenToggle = function (_Button) {
14946
- inherits(FullscreenToggle, _Button);
14947
-
14948
- /**
14949
- * Creates an instance of this class.
14950
- *
14951
- * @param {Player} player
14952
- * The `Player` that this class should be attached to.
14953
- *
14954
- * @param {Object} [options]
14955
- * The key/value store of player options.
14956
- */
14957
- function FullscreenToggle(player, options) {
14958
- classCallCheck(this, FullscreenToggle);
14959
-
14960
- var _this = possibleConstructorReturn(this, _Button.call(this, player, options));
14961
-
14962
- _this.on(player, 'fullscreenchange', _this.handleFullscreenChange);
14963
-
14964
- if (document_1[FullscreenApi.fullscreenEnabled] === false) {
14965
- _this.disable();
14966
- }
14967
- return _this;
14968
- }
14969
-
14970
- /**
14971
- * Builds the default DOM `className`.
14972
- *
14973
- * @return {string}
14974
- * The DOM `className` for this object.
14975
- */
14976
-
14977
-
14978
- FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() {
14979
- return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this);
14980
- };
14981
-
14982
- /**
14983
- * Handles fullscreenchange on the player and change control text accordingly.
14984
- *
14985
- * @param {EventTarget~Event} [event]
14986
- * The {@link Player#fullscreenchange} event that caused this function to be
14987
- * called.
14988
- *
14989
- * @listens Player#fullscreenchange
14990
- */
14991
-
14992
-
14993
- FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange(event) {
14994
- if (this.player_.isFullscreen()) {
14995
- this.controlText('Non-Fullscreen');
14996
- } else {
14997
- this.controlText('Fullscreen');
14998
- }
14999
- };
15000
-
15001
- /**
15002
- * This gets called when an `FullscreenToggle` is "clicked". See
15003
- * {@link ClickableComponent} for more detailed information on what a click can be.
15004
- *
15005
- * @param {EventTarget~Event} [event]
15006
- * The `keydown`, `tap`, or `click` event that caused this function to be
15007
- * called.
15008
- *
15009
- * @listens tap
15010
- * @listens click
15011
- */
15012
-
15013
-
15014
- FullscreenToggle.prototype.handleClick = function handleClick(event) {
15015
- if (!this.player_.isFullscreen()) {
15016
- this.player_.requestFullscreen();
15017
- } else {
15018
- this.player_.exitFullscreen();
15019
- }
15020
- };
15021
-
15022
- return FullscreenToggle;
15023
- }(Button);
15024
-
15025
- /**
15026
- * The text that should display over the `FullscreenToggle`s controls. Added for localization.
15027
- *
15028
- * @type {string}
15029
- * @private
15030
- */
15031
-
15032
-
15033
- FullscreenToggle.prototype.controlText_ = 'Fullscreen';
15034
-
15035
- Component.registerComponent('FullscreenToggle', FullscreenToggle);
15036
-
15037
- /**
15038
- * Check if volume control is supported and if it isn't hide the
15039
- * `Component` that was passed using the `vjs-hidden` class.
15040
- *
15041
- * @param {Component} self
15042
- * The component that should be hidden if volume is unsupported
15043
- *
15044
- * @param {Player} player
15045
- * A reference to the player
15046
- *
15047
- * @private
15048
- */
15049
- var checkVolumeSupport = function checkVolumeSupport(self, player) {
15050
- // hide volume controls when they're not supported by the current tech
15051
- if (player.tech_ && !player.tech_.featuresVolumeControl) {
15052
- self.addClass('vjs-hidden');
15053
- }
15054
-
15055
- self.on(player, 'loadstart', function () {
15056
- if (!player.tech_.featuresVolumeControl) {
15057
- self.addClass('vjs-hidden');
15058
- } else {
15059
- self.removeClass('vjs-hidden');
15060
- }
15061
- });
15062
- };
15063
-
15064
- /**
15065
- * @file volume-level.js
15066
- */
15067
-
15068
- /**
15069
- * Shows volume level
15070
- *
15071
- * @extends Component
15072
- */
15073
-
15074
- var VolumeLevel = function (_Component) {
15075
- inherits(VolumeLevel, _Component);
15076
-
15077
- function VolumeLevel() {
15078
- classCallCheck(this, VolumeLevel);
15079
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
15080
- }
15081
-
15082
- /**
15083
- * Create the `Component`'s DOM element
15084
- *
15085
- * @return {Element}
15086
- * The element that was created.
15087
- */
15088
- VolumeLevel.prototype.createEl = function createEl() {
15089
- return _Component.prototype.createEl.call(this, 'div', {
15090
- className: 'vjs-volume-level',
15091
- innerHTML: '<span class="vjs-control-text"></span>'
15092
- });
15093
- };
15094
-
15095
- return VolumeLevel;
15096
- }(Component);
15097
-
15098
- Component.registerComponent('VolumeLevel', VolumeLevel);
15099
-
15100
- /**
15101
- * @file volume-bar.js
15102
- */
15103
-
15104
- /**
15105
- * The bar that contains the volume level and can be clicked on to adjust the level
15106
- *
15107
- * @extends Slider
15108
- */
15109
-
15110
- var VolumeBar = function (_Slider) {
15111
- inherits(VolumeBar, _Slider);
15112
-
15113
- /**
15114
- * Creates an instance of this class.
15115
- *
15116
- * @param {Player} player
15117
- * The `Player` that this class should be attached to.
15118
- *
15119
- * @param {Object} [options]
15120
- * The key/value store of player options.
15121
- */
15122
- function VolumeBar(player, options) {
15123
- classCallCheck(this, VolumeBar);
15124
-
15125
- var _this = possibleConstructorReturn(this, _Slider.call(this, player, options));
15126
-
15127
- _this.on('slideractive', _this.updateLastVolume_);
15128
- _this.on(player, 'volumechange', _this.updateARIAAttributes);
15129
- player.ready(function () {
15130
- return _this.updateARIAAttributes();
15131
- });
15132
- return _this;
15133
- }
15134
-
15135
- /**
15136
- * Create the `Component`'s DOM element
15137
- *
15138
- * @return {Element}
15139
- * The element that was created.
15140
- */
15141
-
15142
-
15143
- VolumeBar.prototype.createEl = function createEl$$1() {
15144
- return _Slider.prototype.createEl.call(this, 'div', {
15145
- className: 'vjs-volume-bar vjs-slider-bar'
15146
- }, {
15147
- 'aria-label': this.localize('Volume Level'),
15148
- 'aria-live': 'polite'
15149
- });
15150
- };
15151
-
15152
- /**
15153
- * Handle mouse down on volume bar
15154
- *
15155
- * @param {EventTarget~Event} event
15156
- * The `mousedown` event that caused this to run.
15157
- *
15158
- * @listens mousedown
15159
- */
15160
-
15161
-
15162
- VolumeBar.prototype.handleMouseDown = function handleMouseDown(event) {
15163
- if (!isSingleLeftClick(event)) {
15164
- return;
15165
- }
15166
-
15167
- _Slider.prototype.handleMouseDown.call(this, event);
15168
- };
15169
-
15170
- /**
15171
- * Handle movement events on the {@link VolumeMenuButton}.
15172
- *
15173
- * @param {EventTarget~Event} event
15174
- * The event that caused this function to run.
15175
- *
15176
- * @listens mousemove
15177
- */
15178
-
15179
-
15180
- VolumeBar.prototype.handleMouseMove = function handleMouseMove(event) {
15181
- if (!isSingleLeftClick(event)) {
15182
- return;
15183
- }
15184
-
15185
- this.checkMuted();
15186
- this.player_.volume(this.calculateDistance(event));
15187
- };
15188
-
15189
- /**
15190
- * If the player is muted unmute it.
15191
- */
15192
-
15193
-
15194
- VolumeBar.prototype.checkMuted = function checkMuted() {
15195
- if (this.player_.muted()) {
15196
- this.player_.muted(false);
15197
- }
15198
- };
15199
-
15200
- /**
15201
- * Get percent of volume level
15202
- *
15203
- * @return {number}
15204
- * Volume level percent as a decimal number.
15205
- */
15206
-
15207
-
15208
- VolumeBar.prototype.getPercent = function getPercent() {
15209
- if (this.player_.muted()) {
15210
- return 0;
15211
- }
15212
- return this.player_.volume();
15213
- };
15214
-
15215
- /**
15216
- * Increase volume level for keyboard users
15217
- */
15218
-
15219
-
15220
- VolumeBar.prototype.stepForward = function stepForward() {
15221
- this.checkMuted();
15222
- this.player_.volume(this.player_.volume() + 0.1);
15223
- };
15224
-
15225
- /**
15226
- * Decrease volume level for keyboard users
15227
- */
15228
-
15229
-
15230
- VolumeBar.prototype.stepBack = function stepBack() {
15231
- this.checkMuted();
15232
- this.player_.volume(this.player_.volume() - 0.1);
15233
- };
15234
-
15235
- /**
15236
- * Update ARIA accessibility attributes
15237
- *
15238
- * @param {EventTarget~Event} [event]
15239
- * The `volumechange` event that caused this function to run.
15240
- *
15241
- * @listens Player#volumechange
15242
- */
15243
-
15244
-
15245
- VolumeBar.prototype.updateARIAAttributes = function updateARIAAttributes(event) {
15246
- var ariaValue = this.player_.muted() ? 0 : this.volumeAsPercentage_();
15247
-
15248
- this.el_.setAttribute('aria-valuenow', ariaValue);
15249
- this.el_.setAttribute('aria-valuetext', ariaValue + '%');
15250
- };
15251
-
15252
- /**
15253
- * Returns the current value of the player volume as a percentage
15254
- *
15255
- * @private
15256
- */
15257
-
15258
-
15259
- VolumeBar.prototype.volumeAsPercentage_ = function volumeAsPercentage_() {
15260
- return Math.round(this.player_.volume() * 100);
15261
- };
15262
-
15263
- /**
15264
- * When user starts dragging the VolumeBar, store the volume and listen for
15265
- * the end of the drag. When the drag ends, if the volume was set to zero,
15266
- * set lastVolume to the stored volume.
15267
- *
15268
- * @listens slideractive
15269
- * @private
15270
- */
15271
-
15272
-
15273
- VolumeBar.prototype.updateLastVolume_ = function updateLastVolume_() {
15274
- var _this2 = this;
15275
-
15276
- var volumeBeforeDrag = this.player_.volume();
15277
-
15278
- this.one('sliderinactive', function () {
15279
- if (_this2.player_.volume() === 0) {
15280
- _this2.player_.lastVolume_(volumeBeforeDrag);
15281
- }
15282
- });
15283
- };
15284
-
15285
- return VolumeBar;
15286
- }(Slider);
15287
-
15288
- /**
15289
- * Default options for the `VolumeBar`
15290
- *
15291
- * @type {Object}
15292
- * @private
15293
- */
15294
-
15295
-
15296
- VolumeBar.prototype.options_ = {
15297
- children: ['volumeLevel'],
15298
- barName: 'volumeLevel'
15299
- };
15300
-
15301
- /**
15302
- * Call the update event for this Slider when this event happens on the player.
15303
- *
15304
- * @type {string}
15305
- */
15306
- VolumeBar.prototype.playerEvent = 'volumechange';
15307
-
15308
- Component.registerComponent('VolumeBar', VolumeBar);
15309
-
15310
- /**
15311
- * @file volume-control.js
15312
- */
15313
-
15314
- /**
15315
- * The component for controlling the volume level
15316
- *
15317
- * @extends Component
15318
- */
15319
-
15320
- var VolumeControl = function (_Component) {
15321
- inherits(VolumeControl, _Component);
15322
-
15323
- /**
15324
- * Creates an instance of this class.
15325
- *
15326
- * @param {Player} player
15327
- * The `Player` that this class should be attached to.
15328
- *
15329
- * @param {Object} [options={}]
15330
- * The key/value store of player options.
15331
- */
15332
- function VolumeControl(player) {
15333
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
15334
- classCallCheck(this, VolumeControl);
15335
-
15336
- options.vertical = options.vertical || false;
15337
-
15338
- // Pass the vertical option down to the VolumeBar if
15339
- // the VolumeBar is turned on.
15340
- if (typeof options.volumeBar === 'undefined' || isPlain(options.volumeBar)) {
15341
- options.volumeBar = options.volumeBar || {};
15342
- options.volumeBar.vertical = options.vertical;
15343
- }
15344
-
15345
- // hide this control if volume support is missing
15346
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
15347
-
15348
- checkVolumeSupport(_this, player);
15349
-
15350
- _this.throttledHandleMouseMove = throttle(bind(_this, _this.handleMouseMove), 25);
15351
-
15352
- _this.on('mousedown', _this.handleMouseDown);
15353
- _this.on('touchstart', _this.handleMouseDown);
15354
-
15355
- // while the slider is active (the mouse has been pressed down and
15356
- // is dragging) or in focus we do not want to hide the VolumeBar
15357
- _this.on(_this.volumeBar, ['focus', 'slideractive'], function () {
15358
- _this.volumeBar.addClass('vjs-slider-active');
15359
- _this.addClass('vjs-slider-active');
15360
- _this.trigger('slideractive');
15361
- });
15362
-
15363
- _this.on(_this.volumeBar, ['blur', 'sliderinactive'], function () {
15364
- _this.volumeBar.removeClass('vjs-slider-active');
15365
- _this.removeClass('vjs-slider-active');
15366
- _this.trigger('sliderinactive');
15367
- });
15368
- return _this;
15369
- }
15370
-
15371
- /**
15372
- * Create the `Component`'s DOM element
15373
- *
15374
- * @return {Element}
15375
- * The element that was created.
15376
- */
15377
-
15378
-
15379
- VolumeControl.prototype.createEl = function createEl() {
15380
- var orientationClass = 'vjs-volume-horizontal';
15381
-
15382
- if (this.options_.vertical) {
15383
- orientationClass = 'vjs-volume-vertical';
15384
- }
15385
-
15386
- return _Component.prototype.createEl.call(this, 'div', {
15387
- className: 'vjs-volume-control vjs-control ' + orientationClass
15388
- });
15389
- };
15390
-
15391
- /**
15392
- * Handle `mousedown` or `touchstart` events on the `VolumeControl`.
15393
- *
15394
- * @param {EventTarget~Event} event
15395
- * `mousedown` or `touchstart` event that triggered this function
15396
- *
15397
- * @listens mousedown
15398
- * @listens touchstart
15399
- */
15400
-
15401
-
15402
- VolumeControl.prototype.handleMouseDown = function handleMouseDown(event) {
15403
- var doc = this.el_.ownerDocument;
15404
-
15405
- this.on(doc, 'mousemove', this.throttledHandleMouseMove);
15406
- this.on(doc, 'touchmove', this.throttledHandleMouseMove);
15407
- this.on(doc, 'mouseup', this.handleMouseUp);
15408
- this.on(doc, 'touchend', this.handleMouseUp);
15409
- };
15410
-
15411
- /**
15412
- * Handle `mouseup` or `touchend` events on the `VolumeControl`.
15413
- *
15414
- * @param {EventTarget~Event} event
15415
- * `mouseup` or `touchend` event that triggered this function.
15416
- *
15417
- * @listens touchend
15418
- * @listens mouseup
15419
- */
15420
-
15421
-
15422
- VolumeControl.prototype.handleMouseUp = function handleMouseUp(event) {
15423
- var doc = this.el_.ownerDocument;
15424
-
15425
- this.off(doc, 'mousemove', this.throttledHandleMouseMove);
15426
- this.off(doc, 'touchmove', this.throttledHandleMouseMove);
15427
- this.off(doc, 'mouseup', this.handleMouseUp);
15428
- this.off(doc, 'touchend', this.handleMouseUp);
15429
- };
15430
-
15431
- /**
15432
- * Handle `mousedown` or `touchstart` events on the `VolumeControl`.
15433
- *
15434
- * @param {EventTarget~Event} event
15435
- * `mousedown` or `touchstart` event that triggered this function
15436
- *
15437
- * @listens mousedown
15438
- * @listens touchstart
15439
- */
15440
-
15441
-
15442
- VolumeControl.prototype.handleMouseMove = function handleMouseMove(event) {
15443
- this.volumeBar.handleMouseMove(event);
15444
- };
15445
-
15446
- return VolumeControl;
15447
- }(Component);
15448
-
15449
- /**
15450
- * Default options for the `VolumeControl`
15451
- *
15452
- * @type {Object}
15453
- * @private
15454
- */
15455
-
15456
-
15457
- VolumeControl.prototype.options_ = {
15458
- children: ['volumeBar']
15459
- };
15460
-
15461
- Component.registerComponent('VolumeControl', VolumeControl);
15462
-
15463
- /**
15464
- * Check if muting volume is supported and if it isn't hide the mute toggle
15465
- * button.
15466
- *
15467
- * @param {Component} self
15468
- * A reference to the mute toggle button
15469
- *
15470
- * @param {Player} player
15471
- * A reference to the player
15472
- *
15473
- * @private
15474
- */
15475
- var checkMuteSupport = function checkMuteSupport(self, player) {
15476
- // hide mute toggle button if it's not supported by the current tech
15477
- if (player.tech_ && !player.tech_.featuresMuteControl) {
15478
- self.addClass('vjs-hidden');
15479
- }
15480
-
15481
- self.on(player, 'loadstart', function () {
15482
- if (!player.tech_.featuresMuteControl) {
15483
- self.addClass('vjs-hidden');
15484
- } else {
15485
- self.removeClass('vjs-hidden');
15486
- }
15487
- });
15488
- };
15489
-
15490
- /**
15491
- * @file mute-toggle.js
15492
- */
15493
-
15494
- /**
15495
- * A button component for muting the audio.
15496
- *
15497
- * @extends Button
15498
- */
15499
-
15500
- var MuteToggle = function (_Button) {
15501
- inherits(MuteToggle, _Button);
15502
-
15503
- /**
15504
- * Creates an instance of this class.
15505
- *
15506
- * @param {Player} player
15507
- * The `Player` that this class should be attached to.
15508
- *
15509
- * @param {Object} [options]
15510
- * The key/value store of player options.
15511
- */
15512
- function MuteToggle(player, options) {
15513
- classCallCheck(this, MuteToggle);
15514
-
15515
- // hide this control if volume support is missing
15516
- var _this = possibleConstructorReturn(this, _Button.call(this, player, options));
15517
-
15518
- checkMuteSupport(_this, player);
15519
-
15520
- _this.on(player, ['loadstart', 'volumechange'], _this.update);
15521
- return _this;
15522
- }
15523
-
15524
- /**
15525
- * Builds the default DOM `className`.
15526
- *
15527
- * @return {string}
15528
- * The DOM `className` for this object.
15529
- */
15530
-
15531
-
15532
- MuteToggle.prototype.buildCSSClass = function buildCSSClass() {
15533
- return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this);
15534
- };
15535
-
15536
- /**
15537
- * This gets called when an `MuteToggle` is "clicked". See
15538
- * {@link ClickableComponent} for more detailed information on what a click can be.
15539
- *
15540
- * @param {EventTarget~Event} [event]
15541
- * The `keydown`, `tap`, or `click` event that caused this function to be
15542
- * called.
15543
- *
15544
- * @listens tap
15545
- * @listens click
15546
- */
15547
-
15548
-
15549
- MuteToggle.prototype.handleClick = function handleClick(event) {
15550
- var vol = this.player_.volume();
15551
- var lastVolume = this.player_.lastVolume_();
15552
-
15553
- if (vol === 0) {
15554
- var volumeToSet = lastVolume < 0.1 ? 0.1 : lastVolume;
15555
-
15556
- this.player_.volume(volumeToSet);
15557
- this.player_.muted(false);
15558
- } else {
15559
- this.player_.muted(this.player_.muted() ? false : true);
15560
- }
15561
- };
15562
-
15563
- /**
15564
- * Update the `MuteToggle` button based on the state of `volume` and `muted`
15565
- * on the player.
15566
- *
15567
- * @param {EventTarget~Event} [event]
15568
- * The {@link Player#loadstart} event if this function was called
15569
- * through an event.
15570
- *
15571
- * @listens Player#loadstart
15572
- * @listens Player#volumechange
15573
- */
15574
-
15575
-
15576
- MuteToggle.prototype.update = function update(event) {
15577
- this.updateIcon_();
15578
- this.updateControlText_();
15579
- };
15580
-
15581
- /**
15582
- * Update the appearance of the `MuteToggle` icon.
15583
- *
15584
- * Possible states (given `level` variable below):
15585
- * - 0: crossed out
15586
- * - 1: zero bars of volume
15587
- * - 2: one bar of volume
15588
- * - 3: two bars of volume
15589
- *
15590
- * @private
15591
- */
15592
-
15593
-
15594
- MuteToggle.prototype.updateIcon_ = function updateIcon_() {
15595
- var vol = this.player_.volume();
15596
- var level = 3;
15597
-
15598
- // in iOS when a player is loaded with muted attribute
15599
- // and volume is changed with a native mute button
15600
- // we want to make sure muted state is updated
15601
- if (IS_IOS) {
15602
- this.player_.muted(this.player_.tech_.el_.muted);
15603
- }
15604
-
15605
- if (vol === 0 || this.player_.muted()) {
15606
- level = 0;
15607
- } else if (vol < 0.33) {
15608
- level = 1;
15609
- } else if (vol < 0.67) {
15610
- level = 2;
15611
- }
15612
-
15613
- // TODO improve muted icon classes
15614
- for (var i = 0; i < 4; i++) {
15615
- removeClass(this.el_, 'vjs-vol-' + i);
15616
- }
15617
- addClass(this.el_, 'vjs-vol-' + level);
15618
- };
15619
-
15620
- /**
15621
- * If `muted` has changed on the player, update the control text
15622
- * (`title` attribute on `vjs-mute-control` element and content of
15623
- * `vjs-control-text` element).
15624
- *
15625
- * @private
15626
- */
15627
-
15628
-
15629
- MuteToggle.prototype.updateControlText_ = function updateControlText_() {
15630
- var soundOff = this.player_.muted() || this.player_.volume() === 0;
15631
- var text = soundOff ? 'Unmute' : 'Mute';
15632
-
15633
- if (this.controlText() !== text) {
15634
- this.controlText(text);
15635
- }
15636
- };
15637
-
15638
- return MuteToggle;
15639
- }(Button);
15640
-
15641
- /**
15642
- * The text that should display over the `MuteToggle`s controls. Added for localization.
15643
- *
15644
- * @type {string}
15645
- * @private
15646
- */
15647
-
15648
-
15649
- MuteToggle.prototype.controlText_ = 'Mute';
15650
-
15651
- Component.registerComponent('MuteToggle', MuteToggle);
15652
-
15653
- /**
15654
- * @file volume-control.js
15655
- */
15656
-
15657
- /**
15658
- * A Component to contain the MuteToggle and VolumeControl so that
15659
- * they can work together.
15660
- *
15661
- * @extends Component
15662
- */
15663
-
15664
- var VolumePanel = function (_Component) {
15665
- inherits(VolumePanel, _Component);
15666
-
15667
- /**
15668
- * Creates an instance of this class.
15669
- *
15670
- * @param {Player} player
15671
- * The `Player` that this class should be attached to.
15672
- *
15673
- * @param {Object} [options={}]
15674
- * The key/value store of player options.
15675
- */
15676
- function VolumePanel(player) {
15677
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
15678
- classCallCheck(this, VolumePanel);
15679
-
15680
- if (typeof options.inline !== 'undefined') {
15681
- options.inline = options.inline;
15682
- } else {
15683
- options.inline = true;
15684
- }
15685
-
15686
- // pass the inline option down to the VolumeControl as vertical if
15687
- // the VolumeControl is on.
15688
- if (typeof options.volumeControl === 'undefined' || isPlain(options.volumeControl)) {
15689
- options.volumeControl = options.volumeControl || {};
15690
- options.volumeControl.vertical = !options.inline;
15691
- }
15692
-
15693
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
15694
-
15695
- _this.on(player, ['loadstart'], _this.volumePanelState_);
15696
-
15697
- // while the slider is active (the mouse has been pressed down and
15698
- // is dragging) we do not want to hide the VolumeBar
15699
- _this.on(_this.volumeControl, ['slideractive'], _this.sliderActive_);
15700
-
15701
- _this.on(_this.volumeControl, ['sliderinactive'], _this.sliderInactive_);
15702
- return _this;
15703
- }
15704
-
15705
- /**
15706
- * Add vjs-slider-active class to the VolumePanel
15707
- *
15708
- * @listens VolumeControl#slideractive
15709
- * @private
15710
- */
15711
-
15712
-
15713
- VolumePanel.prototype.sliderActive_ = function sliderActive_() {
15714
- this.addClass('vjs-slider-active');
15715
- };
15716
-
15717
- /**
15718
- * Removes vjs-slider-active class to the VolumePanel
15719
- *
15720
- * @listens VolumeControl#sliderinactive
15721
- * @private
15722
- */
15723
-
15724
-
15725
- VolumePanel.prototype.sliderInactive_ = function sliderInactive_() {
15726
- this.removeClass('vjs-slider-active');
15727
- };
15728
-
15729
- /**
15730
- * Adds vjs-hidden or vjs-mute-toggle-only to the VolumePanel
15731
- * depending on MuteToggle and VolumeControl state
15732
- *
15733
- * @listens Player#loadstart
15734
- * @private
15735
- */
15736
-
15737
-
15738
- VolumePanel.prototype.volumePanelState_ = function volumePanelState_() {
15739
- // hide volume panel if neither volume control or mute toggle
15740
- // are displayed
15741
- if (this.volumeControl.hasClass('vjs-hidden') && this.muteToggle.hasClass('vjs-hidden')) {
15742
- this.addClass('vjs-hidden');
15743
- }
15744
-
15745
- // if only mute toggle is visible we don't want
15746
- // volume panel expanding when hovered or active
15747
- if (this.volumeControl.hasClass('vjs-hidden') && !this.muteToggle.hasClass('vjs-hidden')) {
15748
- this.addClass('vjs-mute-toggle-only');
15749
- }
15750
- };
15751
-
15752
- /**
15753
- * Create the `Component`'s DOM element
15754
- *
15755
- * @return {Element}
15756
- * The element that was created.
15757
- */
15758
-
15759
-
15760
- VolumePanel.prototype.createEl = function createEl() {
15761
- var orientationClass = 'vjs-volume-panel-horizontal';
15762
-
15763
- if (!this.options_.inline) {
15764
- orientationClass = 'vjs-volume-panel-vertical';
15765
- }
15766
-
15767
- return _Component.prototype.createEl.call(this, 'div', {
15768
- className: 'vjs-volume-panel vjs-control ' + orientationClass
15769
- });
15770
- };
15771
-
15772
- return VolumePanel;
15773
- }(Component);
15774
-
15775
- /**
15776
- * Default options for the `VolumeControl`
15777
- *
15778
- * @type {Object}
15779
- * @private
15780
- */
15781
-
15782
-
15783
- VolumePanel.prototype.options_ = {
15784
- children: ['muteToggle', 'volumeControl']
15785
- };
15786
-
15787
- Component.registerComponent('VolumePanel', VolumePanel);
15788
-
15789
- /**
15790
- * @file menu.js
15791
- */
15792
-
15793
- /**
15794
- * The Menu component is used to build popup menus, including subtitle and
15795
- * captions selection menus.
15796
- *
15797
- * @extends Component
15798
- */
15799
-
15800
- var Menu = function (_Component) {
15801
- inherits(Menu, _Component);
15802
-
15803
- /**
15804
- * Create an instance of this class.
15805
- *
15806
- * @param {Player} player
15807
- * the player that this component should attach to
15808
- *
15809
- * @param {Object} [options]
15810
- * Object of option names and values
15811
- *
15812
- */
15813
- function Menu(player, options) {
15814
- classCallCheck(this, Menu);
15815
-
15816
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
15817
-
15818
- if (options) {
15819
- _this.menuButton_ = options.menuButton;
15820
- }
15821
-
15822
- _this.focusedChild_ = -1;
15823
-
15824
- _this.on('keydown', _this.handleKeyPress);
15825
- return _this;
15826
- }
15827
-
15828
- /**
15829
- * Add a {@link MenuItem} to the menu.
15830
- *
15831
- * @param {Object|string} component
15832
- * The name or instance of the `MenuItem` to add.
15833
- *
15834
- */
15835
-
15836
-
15837
- Menu.prototype.addItem = function addItem(component) {
15838
- this.addChild(component);
15839
- component.on('click', bind(this, function (event) {
15840
- // Unpress the associated MenuButton, and move focus back to it
15841
- if (this.menuButton_) {
15842
- this.menuButton_.unpressButton();
15843
-
15844
- // don't focus menu button if item is a caption settings item
15845
- // because focus will move elsewhere
15846
- if (component.name() !== 'CaptionSettingsMenuItem') {
15847
- this.menuButton_.focus();
15848
- }
15849
- }
15850
- }));
15851
- };
15852
-
15853
- /**
15854
- * Create the `Menu`s DOM element.
15855
- *
15856
- * @return {Element}
15857
- * the element that was created
15858
- */
15859
-
15860
-
15861
- Menu.prototype.createEl = function createEl$$1() {
15862
- var contentElType = this.options_.contentElType || 'ul';
15863
-
15864
- this.contentEl_ = createEl(contentElType, {
15865
- className: 'vjs-menu-content'
15866
- });
15867
-
15868
- this.contentEl_.setAttribute('role', 'menu');
15869
-
15870
- var el = _Component.prototype.createEl.call(this, 'div', {
15871
- append: this.contentEl_,
15872
- className: 'vjs-menu'
15873
- });
15874
-
15875
- el.appendChild(this.contentEl_);
15876
-
15877
- // Prevent clicks from bubbling up. Needed for Menu Buttons,
15878
- // where a click on the parent is significant
15879
- on(el, 'click', function (event) {
15880
- event.preventDefault();
15881
- event.stopImmediatePropagation();
15882
- });
15883
-
15884
- return el;
15885
- };
15886
-
15887
- Menu.prototype.dispose = function dispose() {
15888
- this.contentEl_ = null;
15889
-
15890
- _Component.prototype.dispose.call(this);
15891
- };
15892
-
15893
- /**
15894
- * Handle a `keydown` event on this menu. This listener is added in the constructor.
15895
- *
15896
- * @param {EventTarget~Event} event
15897
- * A `keydown` event that happened on the menu.
15898
- *
15899
- * @listens keydown
15900
- */
15901
-
15902
-
15903
- Menu.prototype.handleKeyPress = function handleKeyPress(event) {
15904
- // Left and Down Arrows
15905
- if (event.which === 37 || event.which === 40) {
15906
- event.preventDefault();
15907
- this.stepForward();
15908
-
15909
- // Up and Right Arrows
15910
- } else if (event.which === 38 || event.which === 39) {
15911
- event.preventDefault();
15912
- this.stepBack();
15913
- }
15914
- };
15915
-
15916
- /**
15917
- * Move to next (lower) menu item for keyboard users.
15918
- */
15919
-
15920
-
15921
- Menu.prototype.stepForward = function stepForward() {
15922
- var stepChild = 0;
15923
-
15924
- if (this.focusedChild_ !== undefined) {
15925
- stepChild = this.focusedChild_ + 1;
15926
- }
15927
- this.focus(stepChild);
15928
- };
15929
-
15930
- /**
15931
- * Move to previous (higher) menu item for keyboard users.
15932
- */
15933
-
15934
-
15935
- Menu.prototype.stepBack = function stepBack() {
15936
- var stepChild = 0;
15937
-
15938
- if (this.focusedChild_ !== undefined) {
15939
- stepChild = this.focusedChild_ - 1;
15940
- }
15941
- this.focus(stepChild);
15942
- };
15943
-
15944
- /**
15945
- * Set focus on a {@link MenuItem} in the `Menu`.
15946
- *
15947
- * @param {Object|string} [item=0]
15948
- * Index of child item set focus on.
15949
- */
15950
-
15951
-
15952
- Menu.prototype.focus = function focus() {
15953
- var item = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
15954
-
15955
- var children = this.children().slice();
15956
- var haveTitle = children.length && children[0].className && /vjs-menu-title/.test(children[0].className);
15957
-
15958
- if (haveTitle) {
15959
- children.shift();
15960
- }
15961
-
15962
- if (children.length > 0) {
15963
- if (item < 0) {
15964
- item = 0;
15965
- } else if (item >= children.length) {
15966
- item = children.length - 1;
15967
- }
15968
-
15969
- this.focusedChild_ = item;
15970
-
15971
- children[item].el_.focus();
15972
- }
15973
- };
15974
-
15975
- return Menu;
15976
- }(Component);
15977
-
15978
- Component.registerComponent('Menu', Menu);
15979
-
15980
- /**
15981
- * @file menu-button.js
15982
- */
15983
-
15984
- /**
15985
- * A `MenuButton` class for any popup {@link Menu}.
15986
- *
15987
- * @extends Component
15988
- */
15989
-
15990
- var MenuButton = function (_Component) {
15991
- inherits(MenuButton, _Component);
15992
-
15993
- /**
15994
- * Creates an instance of this class.
15995
- *
15996
- * @param {Player} player
15997
- * The `Player` that this class should be attached to.
15998
- *
15999
- * @param {Object} [options={}]
16000
- * The key/value store of player options.
16001
- */
16002
- function MenuButton(player) {
16003
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
16004
- classCallCheck(this, MenuButton);
16005
-
16006
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options));
16007
-
16008
- _this.menuButton_ = new Button(player, options);
16009
-
16010
- _this.menuButton_.controlText(_this.controlText_);
16011
- _this.menuButton_.el_.setAttribute('aria-haspopup', 'true');
16012
-
16013
- // Add buildCSSClass values to the button, not the wrapper
16014
- var buttonClass = Button.prototype.buildCSSClass();
16015
-
16016
- _this.menuButton_.el_.className = _this.buildCSSClass() + ' ' + buttonClass;
16017
- _this.menuButton_.removeClass('vjs-control');
16018
-
16019
- _this.addChild(_this.menuButton_);
16020
-
16021
- _this.update();
16022
-
16023
- _this.enabled_ = true;
16024
-
16025
- _this.on(_this.menuButton_, 'tap', _this.handleClick);
16026
- _this.on(_this.menuButton_, 'click', _this.handleClick);
16027
- _this.on(_this.menuButton_, 'focus', _this.handleFocus);
16028
- _this.on(_this.menuButton_, 'blur', _this.handleBlur);
16029
-
16030
- _this.on('keydown', _this.handleSubmenuKeyPress);
16031
- return _this;
16032
- }
16033
-
16034
- /**
16035
- * Update the menu based on the current state of its items.
16036
- */
16037
-
16038
-
16039
- MenuButton.prototype.update = function update() {
16040
- var menu = this.createMenu();
16041
-
16042
- if (this.menu) {
16043
- this.menu.dispose();
16044
- this.removeChild(this.menu);
16045
- }
16046
-
16047
- this.menu = menu;
16048
- this.addChild(menu);
16049
-
16050
- /**
16051
- * Track the state of the menu button
16052
- *
16053
- * @type {Boolean}
16054
- * @private
16055
- */
16056
- this.buttonPressed_ = false;
16057
- this.menuButton_.el_.setAttribute('aria-expanded', 'false');
16058
-
16059
- if (this.items && this.items.length <= this.hideThreshold_) {
16060
- this.hide();
16061
- } else {
16062
- this.show();
16063
- }
16064
- };
16065
-
16066
- /**
16067
- * Create the menu and add all items to it.
16068
- *
16069
- * @return {Menu}
16070
- * The constructed menu
16071
- */
16072
-
16073
-
16074
- MenuButton.prototype.createMenu = function createMenu() {
16075
- var menu = new Menu(this.player_, { menuButton: this });
16076
-
16077
- /**
16078
- * Hide the menu if the number of items is less than or equal to this threshold. This defaults
16079
- * to 0 and whenever we add items which can be hidden to the menu we'll increment it. We list
16080
- * it here because every time we run `createMenu` we need to reset the value.
16081
- *
16082
- * @protected
16083
- * @type {Number}
16084
- */
16085
- this.hideThreshold_ = 0;
16086
-
16087
- // Add a title list item to the top
16088
- if (this.options_.title) {
16089
- var title = createEl('li', {
16090
- className: 'vjs-menu-title',
16091
- innerHTML: toTitleCase(this.options_.title),
16092
- tabIndex: -1
16093
- });
16094
-
16095
- this.hideThreshold_ += 1;
16096
-
16097
- menu.children_.unshift(title);
16098
- prependTo(title, menu.contentEl());
16099
- }
16100
-
16101
- this.items = this.createItems();
16102
-
16103
- if (this.items) {
16104
- // Add menu items to the menu
16105
- for (var i = 0; i < this.items.length; i++) {
16106
- menu.addItem(this.items[i]);
16107
- }
16108
- }
16109
-
16110
- return menu;
16111
- };
16112
-
16113
- /**
16114
- * Create the list of menu items. Specific to each subclass.
16115
- *
16116
- * @abstract
16117
- */
16118
-
16119
-
16120
- MenuButton.prototype.createItems = function createItems() {};
16121
-
16122
- /**
16123
- * Create the `MenuButtons`s DOM element.
16124
- *
16125
- * @return {Element}
16126
- * The element that gets created.
16127
- */
16128
-
16129
-
16130
- MenuButton.prototype.createEl = function createEl$$1() {
16131
- return _Component.prototype.createEl.call(this, 'div', {
16132
- className: this.buildWrapperCSSClass()
16133
- }, {});
16134
- };
16135
-
16136
- /**
16137
- * Allow sub components to stack CSS class names for the wrapper element
16138
- *
16139
- * @return {string}
16140
- * The constructed wrapper DOM `className`
16141
- */
16142
-
16143
-
16144
- MenuButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
16145
- var menuButtonClass = 'vjs-menu-button';
16146
-
16147
- // If the inline option is passed, we want to use different styles altogether.
16148
- if (this.options_.inline === true) {
16149
- menuButtonClass += '-inline';
16150
- } else {
16151
- menuButtonClass += '-popup';
16152
- }
16153
-
16154
- // TODO: Fix the CSS so that this isn't necessary
16155
- var buttonClass = Button.prototype.buildCSSClass();
16156
-
16157
- return 'vjs-menu-button ' + menuButtonClass + ' ' + buttonClass + ' ' + _Component.prototype.buildCSSClass.call(this);
16158
- };
16159
-
16160
- /**
16161
- * Builds the default DOM `className`.
16162
- *
16163
- * @return {string}
16164
- * The DOM `className` for this object.
16165
- */
16166
-
16167
-
16168
- MenuButton.prototype.buildCSSClass = function buildCSSClass() {
16169
- var menuButtonClass = 'vjs-menu-button';
16170
-
16171
- // If the inline option is passed, we want to use different styles altogether.
16172
- if (this.options_.inline === true) {
16173
- menuButtonClass += '-inline';
16174
- } else {
16175
- menuButtonClass += '-popup';
16176
- }
16177
-
16178
- return 'vjs-menu-button ' + menuButtonClass + ' ' + _Component.prototype.buildCSSClass.call(this);
16179
- };
16180
-
16181
- /**
16182
- * Get or set the localized control text that will be used for accessibility.
16183
- *
16184
- * > NOTE: This will come from the internal `menuButton_` element.
16185
- *
16186
- * @param {string} [text]
16187
- * Control text for element.
16188
- *
16189
- * @param {Element} [el=this.menuButton_.el()]
16190
- * Element to set the title on.
16191
- *
16192
- * @return {string}
16193
- * - The control text when getting
16194
- */
16195
-
16196
-
16197
- MenuButton.prototype.controlText = function controlText(text) {
16198
- var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.menuButton_.el();
16199
-
16200
- return this.menuButton_.controlText(text, el);
16201
- };
16202
-
16203
- /**
16204
- * Handle a click on a `MenuButton`.
16205
- * See {@link ClickableComponent#handleClick} for instances where this is called.
16206
- *
16207
- * @param {EventTarget~Event} event
16208
- * The `keydown`, `tap`, or `click` event that caused this function to be
16209
- * called.
16210
- *
16211
- * @listens tap
16212
- * @listens click
16213
- */
16214
-
16215
-
16216
- MenuButton.prototype.handleClick = function handleClick(event) {
16217
- // When you click the button it adds focus, which will show the menu.
16218
- // So we'll remove focus when the mouse leaves the button. Focus is needed
16219
- // for tab navigation.
16220
-
16221
- this.one(this.menu.contentEl(), 'mouseleave', bind(this, function (e) {
16222
- this.unpressButton();
16223
- this.el_.blur();
16224
- }));
16225
- if (this.buttonPressed_) {
16226
- this.unpressButton();
16227
- } else {
16228
- this.pressButton();
16229
- }
16230
- };
16231
-
16232
- /**
16233
- * Set the focus to the actual button, not to this element
16234
- */
16235
-
16236
-
16237
- MenuButton.prototype.focus = function focus() {
16238
- this.menuButton_.focus();
16239
- };
16240
-
16241
- /**
16242
- * Remove the focus from the actual button, not this element
16243
- */
16244
-
16245
-
16246
- MenuButton.prototype.blur = function blur() {
16247
- this.menuButton_.blur();
16248
- };
16249
-
16250
- /**
16251
- * This gets called when a `MenuButton` gains focus via a `focus` event.
16252
- * Turns on listening for `keydown` events. When they happen it
16253
- * calls `this.handleKeyPress`.
16254
- *
16255
- * @param {EventTarget~Event} event
16256
- * The `focus` event that caused this function to be called.
16257
- *
16258
- * @listens focus
16259
- */
16260
-
16261
-
16262
- MenuButton.prototype.handleFocus = function handleFocus() {
16263
- on(document_1, 'keydown', bind(this, this.handleKeyPress));
16264
- };
16265
-
16266
- /**
16267
- * Called when a `MenuButton` loses focus. Turns off the listener for
16268
- * `keydown` events. Which Stops `this.handleKeyPress` from getting called.
16269
- *
16270
- * @param {EventTarget~Event} event
16271
- * The `blur` event that caused this function to be called.
16272
- *
16273
- * @listens blur
16274
- */
16275
-
16276
-
16277
- MenuButton.prototype.handleBlur = function handleBlur() {
16278
- off(document_1, 'keydown', bind(this, this.handleKeyPress));
16279
- };
16280
-
16281
- /**
16282
- * Handle tab, escape, down arrow, and up arrow keys for `MenuButton`. See
16283
- * {@link ClickableComponent#handleKeyPress} for instances where this is called.
16284
- *
16285
- * @param {EventTarget~Event} event
16286
- * The `keydown` event that caused this function to be called.
16287
- *
16288
- * @listens keydown
16289
- */
16290
-
16291
-
16292
- MenuButton.prototype.handleKeyPress = function handleKeyPress(event) {
16293
-
16294
- // Escape (27) key or Tab (9) key unpress the 'button'
16295
- if (event.which === 27 || event.which === 9) {
16296
- if (this.buttonPressed_) {
16297
- this.unpressButton();
16298
- }
16299
- // Don't preventDefault for Tab key - we still want to lose focus
16300
- if (event.which !== 9) {
16301
- event.preventDefault();
16302
- // Set focus back to the menu button's button
16303
- this.menuButton_.el_.focus();
16304
- }
16305
- // Up (38) key or Down (40) key press the 'button'
16306
- } else if (event.which === 38 || event.which === 40) {
16307
- if (!this.buttonPressed_) {
16308
- this.pressButton();
16309
- event.preventDefault();
16310
- }
16311
- }
16312
- };
16313
-
16314
- /**
16315
- * Handle a `keydown` event on a sub-menu. The listener for this is added in
16316
- * the constructor.
16317
- *
16318
- * @param {EventTarget~Event} event
16319
- * Key press event
16320
- *
16321
- * @listens keydown
16322
- */
16323
-
16324
-
16325
- MenuButton.prototype.handleSubmenuKeyPress = function handleSubmenuKeyPress(event) {
16326
-
16327
- // Escape (27) key or Tab (9) key unpress the 'button'
16328
- if (event.which === 27 || event.which === 9) {
16329
- if (this.buttonPressed_) {
16330
- this.unpressButton();
16331
- }
16332
- // Don't preventDefault for Tab key - we still want to lose focus
16333
- if (event.which !== 9) {
16334
- event.preventDefault();
16335
- // Set focus back to the menu button's button
16336
- this.menuButton_.el_.focus();
16337
- }
16338
- }
16339
- };
16340
-
16341
- /**
16342
- * Put the current `MenuButton` into a pressed state.
16343
- */
16344
-
16345
-
16346
- MenuButton.prototype.pressButton = function pressButton() {
16347
- if (this.enabled_) {
16348
- this.buttonPressed_ = true;
16349
- this.menu.lockShowing();
16350
- this.menuButton_.el_.setAttribute('aria-expanded', 'true');
16351
-
16352
- // set the focus into the submenu, except on iOS where it is resulting in
16353
- // undesired scrolling behavior when the player is in an iframe
16354
- if (IS_IOS && isInFrame()) {
16355
- // Return early so that the menu isn't focused
16356
- return;
16357
- }
16358
-
16359
- this.menu.focus();
16360
- }
16361
- };
16362
-
16363
- /**
16364
- * Take the current `MenuButton` out of a pressed state.
16365
- */
16366
-
16367
-
16368
- MenuButton.prototype.unpressButton = function unpressButton() {
16369
- if (this.enabled_) {
16370
- this.buttonPressed_ = false;
16371
- this.menu.unlockShowing();
16372
- this.menuButton_.el_.setAttribute('aria-expanded', 'false');
16373
- }
16374
- };
16375
-
16376
- /**
16377
- * Disable the `MenuButton`. Don't allow it to be clicked.
16378
- */
16379
-
16380
-
16381
- MenuButton.prototype.disable = function disable() {
16382
- this.unpressButton();
16383
-
16384
- this.enabled_ = false;
16385
- this.addClass('vjs-disabled');
16386
-
16387
- this.menuButton_.disable();
16388
- };
16389
-
16390
- /**
16391
- * Enable the `MenuButton`. Allow it to be clicked.
16392
- */
16393
-
16394
-
16395
- MenuButton.prototype.enable = function enable() {
16396
- this.enabled_ = true;
16397
- this.removeClass('vjs-disabled');
16398
-
16399
- this.menuButton_.enable();
16400
- };
16401
-
16402
- return MenuButton;
16403
- }(Component);
16404
-
16405
- Component.registerComponent('MenuButton', MenuButton);
16406
-
16407
- /**
16408
- * @file track-button.js
16409
- */
16410
-
16411
- /**
16412
- * The base class for buttons that toggle specific track types (e.g. subtitles).
16413
- *
16414
- * @extends MenuButton
16415
- */
16416
-
16417
- var TrackButton = function (_MenuButton) {
16418
- inherits(TrackButton, _MenuButton);
16419
-
16420
- /**
16421
- * Creates an instance of this class.
16422
- *
16423
- * @param {Player} player
16424
- * The `Player` that this class should be attached to.
16425
- *
16426
- * @param {Object} [options]
16427
- * The key/value store of player options.
16428
- */
16429
- function TrackButton(player, options) {
16430
- classCallCheck(this, TrackButton);
16431
-
16432
- var tracks = options.tracks;
16433
-
16434
- var _this = possibleConstructorReturn(this, _MenuButton.call(this, player, options));
16435
-
16436
- if (_this.items.length <= 1) {
16437
- _this.hide();
16438
- }
16439
-
16440
- if (!tracks) {
16441
- return possibleConstructorReturn(_this);
16442
- }
16443
-
16444
- var updateHandler = bind(_this, _this.update);
16445
-
16446
- tracks.addEventListener('removetrack', updateHandler);
16447
- tracks.addEventListener('addtrack', updateHandler);
16448
- _this.player_.on('ready', updateHandler);
16449
-
16450
- _this.player_.on('dispose', function () {
16451
- tracks.removeEventListener('removetrack', updateHandler);
16452
- tracks.removeEventListener('addtrack', updateHandler);
16453
- });
16454
- return _this;
16455
- }
16456
-
16457
- return TrackButton;
16458
- }(MenuButton);
16459
-
16460
- Component.registerComponent('TrackButton', TrackButton);
16461
-
16462
- /**
16463
- * @file menu-item.js
16464
- */
16465
-
16466
- /**
16467
- * The component for a menu item. `<li>`
16468
- *
16469
- * @extends ClickableComponent
16470
- */
16471
-
16472
- var MenuItem = function (_ClickableComponent) {
16473
- inherits(MenuItem, _ClickableComponent);
16474
-
16475
- /**
16476
- * Creates an instance of the this class.
16477
- *
16478
- * @param {Player} player
16479
- * The `Player` that this class should be attached to.
16480
- *
16481
- * @param {Object} [options={}]
16482
- * The key/value store of player options.
16483
- *
16484
- */
16485
- function MenuItem(player, options) {
16486
- classCallCheck(this, MenuItem);
16487
-
16488
- var _this = possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
16489
-
16490
- _this.selectable = options.selectable;
16491
- _this.isSelected_ = options.selected || false;
16492
- _this.multiSelectable = options.multiSelectable;
16493
-
16494
- _this.selected(_this.isSelected_);
16495
-
16496
- if (_this.selectable) {
16497
- if (_this.multiSelectable) {
16498
- _this.el_.setAttribute('role', 'menuitemcheckbox');
16499
- } else {
16500
- _this.el_.setAttribute('role', 'menuitemradio');
16501
- }
16502
- } else {
16503
- _this.el_.setAttribute('role', 'menuitem');
16504
- }
16505
- return _this;
16506
- }
16507
-
16508
- /**
16509
- * Create the `MenuItem's DOM element
16510
- *
16511
- * @param {string} [type=li]
16512
- * Element's node type, not actually used, always set to `li`.
16513
- *
16514
- * @param {Object} [props={}]
16515
- * An object of properties that should be set on the element
16516
- *
16517
- * @param {Object} [attrs={}]
16518
- * An object of attributes that should be set on the element
16519
- *
16520
- * @return {Element}
16521
- * The element that gets created.
16522
- */
16523
-
16524
-
16525
- MenuItem.prototype.createEl = function createEl(type, props, attrs) {
16526
- // The control is textual, not just an icon
16527
- this.nonIconControl = true;
16528
-
16529
- return _ClickableComponent.prototype.createEl.call(this, 'li', assign({
16530
- className: 'vjs-menu-item',
16531
- innerHTML: '<span class="vjs-menu-item-text">' + this.localize(this.options_.label) + '</span>',
16532
- tabIndex: -1
16533
- }, props), attrs);
16534
- };
16535
-
16536
- /**
16537
- * Any click on a `MenuItem` puts it into the selected state.
16538
- * See {@link ClickableComponent#handleClick} for instances where this is called.
16539
- *
16540
- * @param {EventTarget~Event} event
16541
- * The `keydown`, `tap`, or `click` event that caused this function to be
16542
- * called.
16543
- *
16544
- * @listens tap
16545
- * @listens click
16546
- */
16547
-
16548
-
16549
- MenuItem.prototype.handleClick = function handleClick(event) {
16550
- this.selected(true);
16551
- };
16552
-
16553
- /**
16554
- * Set the state for this menu item as selected or not.
16555
- *
16556
- * @param {boolean} selected
16557
- * if the menu item is selected or not
16558
- */
16559
-
16560
-
16561
- MenuItem.prototype.selected = function selected(_selected) {
16562
- if (this.selectable) {
16563
- if (_selected) {
16564
- this.addClass('vjs-selected');
16565
- this.el_.setAttribute('aria-checked', 'true');
16566
- // aria-checked isn't fully supported by browsers/screen readers,
16567
- // so indicate selected state to screen reader in the control text.
16568
- this.controlText(', selected');
16569
- this.isSelected_ = true;
16570
- } else {
16571
- this.removeClass('vjs-selected');
16572
- this.el_.setAttribute('aria-checked', 'false');
16573
- // Indicate un-selected state to screen reader
16574
- this.controlText('');
16575
- this.isSelected_ = false;
16576
- }
16577
- }
16578
- };
16579
-
16580
- return MenuItem;
16581
- }(ClickableComponent);
16582
-
16583
- Component.registerComponent('MenuItem', MenuItem);
16584
-
16585
- /**
16586
- * @file text-track-menu-item.js
16587
- */
16588
-
16589
- /**
16590
- * The specific menu item type for selecting a language within a text track kind
16591
- *
16592
- * @extends MenuItem
16593
- */
16594
-
16595
- var TextTrackMenuItem = function (_MenuItem) {
16596
- inherits(TextTrackMenuItem, _MenuItem);
16597
-
16598
- /**
16599
- * Creates an instance of this class.
16600
- *
16601
- * @param {Player} player
16602
- * The `Player` that this class should be attached to.
16603
- *
16604
- * @param {Object} [options]
16605
- * The key/value store of player options.
16606
- */
16607
- function TextTrackMenuItem(player, options) {
16608
- classCallCheck(this, TextTrackMenuItem);
16609
-
16610
- var track = options.track;
16611
- var tracks = player.textTracks();
16612
-
16613
- // Modify options for parent MenuItem class's init.
16614
- options.label = track.label || track.language || 'Unknown';
16615
- options.selected = track.mode === 'showing';
16616
-
16617
- var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options));
16618
-
16619
- _this.track = track;
16620
- var changeHandler = function changeHandler() {
16621
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
16622
- args[_key] = arguments[_key];
16623
- }
16624
-
16625
- _this.handleTracksChange.apply(_this, args);
16626
- };
16627
- var selectedLanguageChangeHandler = function selectedLanguageChangeHandler() {
16628
- for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
16629
- args[_key2] = arguments[_key2];
16630
- }
16631
-
16632
- _this.handleSelectedLanguageChange.apply(_this, args);
16633
- };
16634
-
16635
- player.on(['loadstart', 'texttrackchange'], changeHandler);
16636
- tracks.addEventListener('change', changeHandler);
16637
- tracks.addEventListener('selectedlanguagechange', selectedLanguageChangeHandler);
16638
- _this.on('dispose', function () {
16639
- player.off(['loadstart', 'texttrackchange'], changeHandler);
16640
- tracks.removeEventListener('change', changeHandler);
16641
- tracks.removeEventListener('selectedlanguagechange', selectedLanguageChangeHandler);
16642
- });
16643
-
16644
- // iOS7 doesn't dispatch change events to TextTrackLists when an
16645
- // associated track's mode changes. Without something like
16646
- // Object.observe() (also not present on iOS7), it's not
16647
- // possible to detect changes to the mode attribute and polyfill
16648
- // the change event. As a poor substitute, we manually dispatch
16649
- // change events whenever the controls modify the mode.
16650
- if (tracks.onchange === undefined) {
16651
- var event = void 0;
16652
-
16653
- _this.on(['tap', 'click'], function () {
16654
- if (_typeof(window_1.Event) !== 'object') {
16655
- // Android 2.3 throws an Illegal Constructor error for window.Event
16656
- try {
16657
- event = new window_1.Event('change');
16658
- } catch (err) {
16659
- // continue regardless of error
16660
- }
16661
- }
16662
-
16663
- if (!event) {
16664
- event = document_1.createEvent('Event');
16665
- event.initEvent('change', true, true);
16666
- }
16667
-
16668
- tracks.dispatchEvent(event);
16669
- });
16670
- }
16671
-
16672
- // set the default state based on current tracks
16673
- _this.handleTracksChange();
16674
- return _this;
16675
- }
16676
-
16677
- /**
16678
- * This gets called when an `TextTrackMenuItem` is "clicked". See
16679
- * {@link ClickableComponent} for more detailed information on what a click can be.
16680
- *
16681
- * @param {EventTarget~Event} event
16682
- * The `keydown`, `tap`, or `click` event that caused this function to be
16683
- * called.
16684
- *
16685
- * @listens tap
16686
- * @listens click
16687
- */
16688
-
16689
-
16690
- TextTrackMenuItem.prototype.handleClick = function handleClick(event) {
16691
- var kind = this.track.kind;
16692
- var kinds = this.track.kinds;
16693
- var tracks = this.player_.textTracks();
16694
-
16695
- if (!kinds) {
16696
- kinds = [kind];
16697
- }
16698
-
16699
- _MenuItem.prototype.handleClick.call(this, event);
16700
-
16701
- if (!tracks) {
16702
- return;
16703
- }
16704
-
16705
- for (var i = 0; i < tracks.length; i++) {
16706
- var track = tracks[i];
16707
-
16708
- if (track === this.track && kinds.indexOf(track.kind) > -1) {
16709
- if (track.mode !== 'showing') {
16710
- track.mode = 'showing';
16711
- }
16712
- } else if (track.mode !== 'disabled') {
16713
- track.mode = 'disabled';
16714
- }
16715
- }
16716
- };
16717
-
16718
- /**
16719
- * Handle text track list change
16720
- *
16721
- * @param {EventTarget~Event} event
16722
- * The `change` event that caused this function to be called.
16723
- *
16724
- * @listens TextTrackList#change
16725
- */
16726
-
16727
-
16728
- TextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
16729
- var shouldBeSelected = this.track.mode === 'showing';
16730
-
16731
- // Prevent redundant selected() calls because they may cause
16732
- // screen readers to read the appended control text unnecessarily
16733
- if (shouldBeSelected !== this.isSelected_) {
16734
- this.selected(shouldBeSelected);
16735
- }
16736
- };
16737
-
16738
- TextTrackMenuItem.prototype.handleSelectedLanguageChange = function handleSelectedLanguageChange(event) {
16739
- if (this.track.mode === 'showing') {
16740
- var selectedLanguage = this.player_.cache_.selectedLanguage;
16741
-
16742
- // Don't replace the kind of track across the same language
16743
- if (selectedLanguage && selectedLanguage.enabled && selectedLanguage.language === this.track.language && selectedLanguage.kind !== this.track.kind) {
16744
- return;
16745
- }
16746
-
16747
- this.player_.cache_.selectedLanguage = {
16748
- enabled: true,
16749
- language: this.track.language,
16750
- kind: this.track.kind
16751
- };
16752
- }
16753
- };
16754
-
16755
- TextTrackMenuItem.prototype.dispose = function dispose() {
16756
- // remove reference to track object on dispose
16757
- this.track = null;
16758
-
16759
- _MenuItem.prototype.dispose.call(this);
16760
- };
16761
-
16762
- return TextTrackMenuItem;
16763
- }(MenuItem);
16764
-
16765
- Component.registerComponent('TextTrackMenuItem', TextTrackMenuItem);
16766
-
16767
- /**
16768
- * @file off-text-track-menu-item.js
16769
- */
16770
-
16771
- /**
16772
- * A special menu item for turning of a specific type of text track
16773
- *
16774
- * @extends TextTrackMenuItem
16775
- */
16776
-
16777
- var OffTextTrackMenuItem = function (_TextTrackMenuItem) {
16778
- inherits(OffTextTrackMenuItem, _TextTrackMenuItem);
16779
-
16780
- /**
16781
- * Creates an instance of this class.
16782
- *
16783
- * @param {Player} player
16784
- * The `Player` that this class should be attached to.
16785
- *
16786
- * @param {Object} [options]
16787
- * The key/value store of player options.
16788
- */
16789
- function OffTextTrackMenuItem(player, options) {
16790
- classCallCheck(this, OffTextTrackMenuItem);
16791
-
16792
- // Create pseudo track info
16793
- // Requires options['kind']
16794
- options.track = {
16795
- player: player,
16796
- kind: options.kind,
16797
- kinds: options.kinds,
16798
- default: false,
16799
- mode: 'disabled'
16800
- };
16801
-
16802
- if (!options.kinds) {
16803
- options.kinds = [options.kind];
16804
- }
16805
-
16806
- if (options.label) {
16807
- options.track.label = options.label;
16808
- } else {
16809
- options.track.label = options.kinds.join(' and ') + ' off';
16810
- }
16811
-
16812
- // MenuItem is selectable
16813
- options.selectable = true;
16814
- // MenuItem is NOT multiSelectable (i.e. only one can be marked "selected" at a time)
16815
- options.multiSelectable = false;
16816
-
16817
- return possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options));
16818
- }
16819
-
16820
- /**
16821
- * Handle text track change
16822
- *
16823
- * @param {EventTarget~Event} event
16824
- * The event that caused this function to run
16825
- */
16826
-
16827
-
16828
- OffTextTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
16829
- var tracks = this.player().textTracks();
16830
- var shouldBeSelected = true;
16831
-
16832
- for (var i = 0, l = tracks.length; i < l; i++) {
16833
- var track = tracks[i];
16834
-
16835
- if (this.options_.kinds.indexOf(track.kind) > -1 && track.mode === 'showing') {
16836
- shouldBeSelected = false;
16837
- break;
16838
- }
16839
- }
16840
-
16841
- // Prevent redundant selected() calls because they may cause
16842
- // screen readers to read the appended control text unnecessarily
16843
- if (shouldBeSelected !== this.isSelected_) {
16844
- this.selected(shouldBeSelected);
16845
- }
16846
- };
16847
-
16848
- OffTextTrackMenuItem.prototype.handleSelectedLanguageChange = function handleSelectedLanguageChange(event) {
16849
- var tracks = this.player().textTracks();
16850
- var allHidden = true;
16851
-
16852
- for (var i = 0, l = tracks.length; i < l; i++) {
16853
- var track = tracks[i];
16854
-
16855
- if (['captions', 'descriptions', 'subtitles'].indexOf(track.kind) > -1 && track.mode === 'showing') {
16856
- allHidden = false;
16857
- break;
16858
- }
16859
- }
16860
-
16861
- if (allHidden) {
16862
- this.player_.cache_.selectedLanguage = {
16863
- enabled: false
16864
- };
16865
- }
16866
- };
16867
-
16868
- return OffTextTrackMenuItem;
16869
- }(TextTrackMenuItem);
16870
-
16871
- Component.registerComponent('OffTextTrackMenuItem', OffTextTrackMenuItem);
16872
-
16873
- /**
16874
- * @file text-track-button.js
16875
- */
16876
-
16877
- /**
16878
- * The base class for buttons that toggle specific text track types (e.g. subtitles)
16879
- *
16880
- * @extends MenuButton
16881
- */
16882
-
16883
- var TextTrackButton = function (_TrackButton) {
16884
- inherits(TextTrackButton, _TrackButton);
16885
-
16886
- /**
16887
- * Creates an instance of this class.
16888
- *
16889
- * @param {Player} player
16890
- * The `Player` that this class should be attached to.
16891
- *
16892
- * @param {Object} [options={}]
16893
- * The key/value store of player options.
16894
- */
16895
- function TextTrackButton(player) {
16896
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
16897
- classCallCheck(this, TextTrackButton);
16898
-
16899
- options.tracks = player.textTracks();
16900
-
16901
- return possibleConstructorReturn(this, _TrackButton.call(this, player, options));
16902
- }
16903
-
16904
- /**
16905
- * Create a menu item for each text track
16906
- *
16907
- * @param {TextTrackMenuItem[]} [items=[]]
16908
- * Existing array of items to use during creation
16909
- *
16910
- * @return {TextTrackMenuItem[]}
16911
- * Array of menu items that were created
16912
- */
16913
-
16914
-
16915
- TextTrackButton.prototype.createItems = function createItems() {
16916
- var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
16917
- var TrackMenuItem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : TextTrackMenuItem;
16918
-
16919
-
16920
- // Label is an override for the [track] off label
16921
- // USed to localise captions/subtitles
16922
- var label = void 0;
16923
-
16924
- if (this.label_) {
16925
- label = this.label_ + ' off';
16926
- }
16927
- // Add an OFF menu item to turn all tracks off
16928
- items.push(new OffTextTrackMenuItem(this.player_, {
16929
- kinds: this.kinds_,
16930
- kind: this.kind_,
16931
- label: label
16932
- }));
16933
-
16934
- this.hideThreshold_ += 1;
16935
-
16936
- var tracks = this.player_.textTracks();
16937
-
16938
- if (!Array.isArray(this.kinds_)) {
16939
- this.kinds_ = [this.kind_];
16940
- }
16941
-
16942
- for (var i = 0; i < tracks.length; i++) {
16943
- var track = tracks[i];
16944
-
16945
- // only add tracks that are of an appropriate kind and have a label
16946
- if (this.kinds_.indexOf(track.kind) > -1) {
16947
-
16948
- var item = new TrackMenuItem(this.player_, {
16949
- track: track,
16950
- // MenuItem is selectable
16951
- selectable: true,
16952
- // MenuItem is NOT multiSelectable (i.e. only one can be marked "selected" at a time)
16953
- multiSelectable: false
16954
- });
16955
-
16956
- item.addClass('vjs-' + track.kind + '-menu-item');
16957
- items.push(item);
16958
- }
16959
- }
16960
-
16961
- return items;
16962
- };
16963
-
16964
- return TextTrackButton;
16965
- }(TrackButton);
16966
-
16967
- Component.registerComponent('TextTrackButton', TextTrackButton);
16968
-
16969
- /**
16970
- * @file chapters-track-menu-item.js
16971
- */
16972
-
16973
- /**
16974
- * The chapter track menu item
16975
- *
16976
- * @extends MenuItem
16977
- */
16978
-
16979
- var ChaptersTrackMenuItem = function (_MenuItem) {
16980
- inherits(ChaptersTrackMenuItem, _MenuItem);
16981
-
16982
- /**
16983
- * Creates an instance of this class.
16984
- *
16985
- * @param {Player} player
16986
- * The `Player` that this class should be attached to.
16987
- *
16988
- * @param {Object} [options]
16989
- * The key/value store of player options.
16990
- */
16991
- function ChaptersTrackMenuItem(player, options) {
16992
- classCallCheck(this, ChaptersTrackMenuItem);
16993
-
16994
- var track = options.track;
16995
- var cue = options.cue;
16996
- var currentTime = player.currentTime();
16997
-
16998
- // Modify options for parent MenuItem class's init.
16999
- options.selectable = true;
17000
- options.multiSelectable = false;
17001
- options.label = cue.text;
17002
- options.selected = cue.startTime <= currentTime && currentTime < cue.endTime;
17003
-
17004
- var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options));
17005
-
17006
- _this.track = track;
17007
- _this.cue = cue;
17008
- track.addEventListener('cuechange', bind(_this, _this.update));
17009
- return _this;
17010
- }
17011
-
17012
- /**
17013
- * This gets called when an `ChaptersTrackMenuItem` is "clicked". See
17014
- * {@link ClickableComponent} for more detailed information on what a click can be.
17015
- *
17016
- * @param {EventTarget~Event} [event]
17017
- * The `keydown`, `tap`, or `click` event that caused this function to be
17018
- * called.
17019
- *
17020
- * @listens tap
17021
- * @listens click
17022
- */
17023
-
17024
-
17025
- ChaptersTrackMenuItem.prototype.handleClick = function handleClick(event) {
17026
- _MenuItem.prototype.handleClick.call(this);
17027
- this.player_.currentTime(this.cue.startTime);
17028
- this.update(this.cue.startTime);
17029
- };
17030
-
17031
- /**
17032
- * Update chapter menu item
17033
- *
17034
- * @param {EventTarget~Event} [event]
17035
- * The `cuechange` event that caused this function to run.
17036
- *
17037
- * @listens TextTrack#cuechange
17038
- */
17039
-
17040
-
17041
- ChaptersTrackMenuItem.prototype.update = function update(event) {
17042
- var cue = this.cue;
17043
- var currentTime = this.player_.currentTime();
17044
-
17045
- // vjs.log(currentTime, cue.startTime);
17046
- this.selected(cue.startTime <= currentTime && currentTime < cue.endTime);
17047
- };
17048
-
17049
- return ChaptersTrackMenuItem;
17050
- }(MenuItem);
17051
-
17052
- Component.registerComponent('ChaptersTrackMenuItem', ChaptersTrackMenuItem);
17053
-
17054
- /**
17055
- * @file chapters-button.js
17056
- */
17057
-
17058
- /**
17059
- * The button component for toggling and selecting chapters
17060
- * Chapters act much differently than other text tracks
17061
- * Cues are navigation vs. other tracks of alternative languages
17062
- *
17063
- * @extends TextTrackButton
17064
- */
17065
-
17066
- var ChaptersButton = function (_TextTrackButton) {
17067
- inherits(ChaptersButton, _TextTrackButton);
17068
-
17069
- /**
17070
- * Creates an instance of this class.
17071
- *
17072
- * @param {Player} player
17073
- * The `Player` that this class should be attached to.
17074
- *
17075
- * @param {Object} [options]
17076
- * The key/value store of player options.
17077
- *
17078
- * @param {Component~ReadyCallback} [ready]
17079
- * The function to call when this function is ready.
17080
- */
17081
- function ChaptersButton(player, options, ready) {
17082
- classCallCheck(this, ChaptersButton);
17083
- return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
17084
- }
17085
-
17086
- /**
17087
- * Builds the default DOM `className`.
17088
- *
17089
- * @return {string}
17090
- * The DOM `className` for this object.
17091
- */
17092
-
17093
-
17094
- ChaptersButton.prototype.buildCSSClass = function buildCSSClass() {
17095
- return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
17096
- };
17097
-
17098
- ChaptersButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17099
- return 'vjs-chapters-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this);
17100
- };
17101
-
17102
- /**
17103
- * Update the menu based on the current state of its items.
17104
- *
17105
- * @param {EventTarget~Event} [event]
17106
- * An event that triggered this function to run.
17107
- *
17108
- * @listens TextTrackList#addtrack
17109
- * @listens TextTrackList#removetrack
17110
- * @listens TextTrackList#change
17111
- */
17112
-
17113
-
17114
- ChaptersButton.prototype.update = function update(event) {
17115
- if (!this.track_ || event && (event.type === 'addtrack' || event.type === 'removetrack')) {
17116
- this.setTrack(this.findChaptersTrack());
17117
- }
17118
- _TextTrackButton.prototype.update.call(this);
17119
- };
17120
-
17121
- /**
17122
- * Set the currently selected track for the chapters button.
17123
- *
17124
- * @param {TextTrack} track
17125
- * The new track to select. Nothing will change if this is the currently selected
17126
- * track.
17127
- */
17128
-
17129
-
17130
- ChaptersButton.prototype.setTrack = function setTrack(track) {
17131
- if (this.track_ === track) {
17132
- return;
17133
- }
17134
-
17135
- if (!this.updateHandler_) {
17136
- this.updateHandler_ = this.update.bind(this);
17137
- }
17138
-
17139
- // here this.track_ refers to the old track instance
17140
- if (this.track_) {
17141
- var remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);
17142
-
17143
- if (remoteTextTrackEl) {
17144
- remoteTextTrackEl.removeEventListener('load', this.updateHandler_);
17145
- }
17146
-
17147
- this.track_ = null;
17148
- }
17149
-
17150
- this.track_ = track;
17151
-
17152
- // here this.track_ refers to the new track instance
17153
- if (this.track_) {
17154
- this.track_.mode = 'hidden';
17155
-
17156
- var _remoteTextTrackEl = this.player_.remoteTextTrackEls().getTrackElementByTrack_(this.track_);
17157
-
17158
- if (_remoteTextTrackEl) {
17159
- _remoteTextTrackEl.addEventListener('load', this.updateHandler_);
17160
- }
17161
- }
17162
- };
17163
-
17164
- /**
17165
- * Find the track object that is currently in use by this ChaptersButton
17166
- *
17167
- * @return {TextTrack|undefined}
17168
- * The current track or undefined if none was found.
17169
- */
17170
-
17171
-
17172
- ChaptersButton.prototype.findChaptersTrack = function findChaptersTrack() {
17173
- var tracks = this.player_.textTracks() || [];
17174
-
17175
- for (var i = tracks.length - 1; i >= 0; i--) {
17176
- // We will always choose the last track as our chaptersTrack
17177
- var track = tracks[i];
17178
-
17179
- if (track.kind === this.kind_) {
17180
- return track;
17181
- }
17182
- }
17183
- };
17184
-
17185
- /**
17186
- * Get the caption for the ChaptersButton based on the track label. This will also
17187
- * use the current tracks localized kind as a fallback if a label does not exist.
17188
- *
17189
- * @return {string}
17190
- * The tracks current label or the localized track kind.
17191
- */
17192
-
17193
-
17194
- ChaptersButton.prototype.getMenuCaption = function getMenuCaption() {
17195
- if (this.track_ && this.track_.label) {
17196
- return this.track_.label;
17197
- }
17198
- return this.localize(toTitleCase(this.kind_));
17199
- };
17200
-
17201
- /**
17202
- * Create menu from chapter track
17203
- *
17204
- * @return {Menu}
17205
- * New menu for the chapter buttons
17206
- */
17207
-
17208
-
17209
- ChaptersButton.prototype.createMenu = function createMenu() {
17210
- this.options_.title = this.getMenuCaption();
17211
- return _TextTrackButton.prototype.createMenu.call(this);
17212
- };
17213
-
17214
- /**
17215
- * Create a menu item for each text track
17216
- *
17217
- * @return {TextTrackMenuItem[]}
17218
- * Array of menu items
17219
- */
17220
-
17221
-
17222
- ChaptersButton.prototype.createItems = function createItems() {
17223
- var items = [];
17224
-
17225
- if (!this.track_) {
17226
- return items;
17227
- }
17228
-
17229
- var cues = this.track_.cues;
17230
-
17231
- if (!cues) {
17232
- return items;
17233
- }
17234
-
17235
- for (var i = 0, l = cues.length; i < l; i++) {
17236
- var cue = cues[i];
17237
- var mi = new ChaptersTrackMenuItem(this.player_, { track: this.track_, cue: cue });
17238
-
17239
- items.push(mi);
17240
- }
17241
-
17242
- return items;
17243
- };
17244
-
17245
- return ChaptersButton;
17246
- }(TextTrackButton);
17247
-
17248
- /**
17249
- * `kind` of TextTrack to look for to associate it with this menu.
17250
- *
17251
- * @type {string}
17252
- * @private
17253
- */
17254
-
17255
-
17256
- ChaptersButton.prototype.kind_ = 'chapters';
17257
-
17258
- /**
17259
- * The text that should display over the `ChaptersButton`s controls. Added for localization.
17260
- *
17261
- * @type {string}
17262
- * @private
17263
- */
17264
- ChaptersButton.prototype.controlText_ = 'Chapters';
17265
-
17266
- Component.registerComponent('ChaptersButton', ChaptersButton);
17267
-
17268
- /**
17269
- * @file descriptions-button.js
17270
- */
17271
-
17272
- /**
17273
- * The button component for toggling and selecting descriptions
17274
- *
17275
- * @extends TextTrackButton
17276
- */
17277
-
17278
- var DescriptionsButton = function (_TextTrackButton) {
17279
- inherits(DescriptionsButton, _TextTrackButton);
17280
-
17281
- /**
17282
- * Creates an instance of this class.
17283
- *
17284
- * @param {Player} player
17285
- * The `Player` that this class should be attached to.
17286
- *
17287
- * @param {Object} [options]
17288
- * The key/value store of player options.
17289
- *
17290
- * @param {Component~ReadyCallback} [ready]
17291
- * The function to call when this component is ready.
17292
- */
17293
- function DescriptionsButton(player, options, ready) {
17294
- classCallCheck(this, DescriptionsButton);
17295
-
17296
- var _this = possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
17297
-
17298
- var tracks = player.textTracks();
17299
- var changeHandler = bind(_this, _this.handleTracksChange);
17300
-
17301
- tracks.addEventListener('change', changeHandler);
17302
- _this.on('dispose', function () {
17303
- tracks.removeEventListener('change', changeHandler);
17304
- });
17305
- return _this;
17306
- }
17307
-
17308
- /**
17309
- * Handle text track change
17310
- *
17311
- * @param {EventTarget~Event} event
17312
- * The event that caused this function to run
17313
- *
17314
- * @listens TextTrackList#change
17315
- */
17316
-
17317
-
17318
- DescriptionsButton.prototype.handleTracksChange = function handleTracksChange(event) {
17319
- var tracks = this.player().textTracks();
17320
- var disabled = false;
17321
-
17322
- // Check whether a track of a different kind is showing
17323
- for (var i = 0, l = tracks.length; i < l; i++) {
17324
- var track = tracks[i];
17325
-
17326
- if (track.kind !== this.kind_ && track.mode === 'showing') {
17327
- disabled = true;
17328
- break;
17329
- }
17330
- }
17331
-
17332
- // If another track is showing, disable this menu button
17333
- if (disabled) {
17334
- this.disable();
17335
- } else {
17336
- this.enable();
17337
- }
17338
- };
17339
-
17340
- /**
17341
- * Builds the default DOM `className`.
17342
- *
17343
- * @return {string}
17344
- * The DOM `className` for this object.
17345
- */
17346
-
17347
-
17348
- DescriptionsButton.prototype.buildCSSClass = function buildCSSClass() {
17349
- return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
17350
- };
17351
-
17352
- DescriptionsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17353
- return 'vjs-descriptions-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this);
17354
- };
17355
-
17356
- return DescriptionsButton;
17357
- }(TextTrackButton);
17358
-
17359
- /**
17360
- * `kind` of TextTrack to look for to associate it with this menu.
17361
- *
17362
- * @type {string}
17363
- * @private
17364
- */
17365
-
17366
-
17367
- DescriptionsButton.prototype.kind_ = 'descriptions';
17368
-
17369
- /**
17370
- * The text that should display over the `DescriptionsButton`s controls. Added for localization.
17371
- *
17372
- * @type {string}
17373
- * @private
17374
- */
17375
- DescriptionsButton.prototype.controlText_ = 'Descriptions';
17376
-
17377
- Component.registerComponent('DescriptionsButton', DescriptionsButton);
17378
-
17379
- /**
17380
- * @file subtitles-button.js
17381
- */
17382
-
17383
- /**
17384
- * The button component for toggling and selecting subtitles
17385
- *
17386
- * @extends TextTrackButton
17387
- */
17388
-
17389
- var SubtitlesButton = function (_TextTrackButton) {
17390
- inherits(SubtitlesButton, _TextTrackButton);
17391
-
17392
- /**
17393
- * Creates an instance of this class.
17394
- *
17395
- * @param {Player} player
17396
- * The `Player` that this class should be attached to.
17397
- *
17398
- * @param {Object} [options]
17399
- * The key/value store of player options.
17400
- *
17401
- * @param {Component~ReadyCallback} [ready]
17402
- * The function to call when this component is ready.
17403
- */
17404
- function SubtitlesButton(player, options, ready) {
17405
- classCallCheck(this, SubtitlesButton);
17406
- return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
17407
- }
17408
-
17409
- /**
17410
- * Builds the default DOM `className`.
17411
- *
17412
- * @return {string}
17413
- * The DOM `className` for this object.
17414
- */
17415
-
17416
-
17417
- SubtitlesButton.prototype.buildCSSClass = function buildCSSClass() {
17418
- return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
17419
- };
17420
-
17421
- SubtitlesButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17422
- return 'vjs-subtitles-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this);
17423
- };
17424
-
17425
- return SubtitlesButton;
17426
- }(TextTrackButton);
17427
-
17428
- /**
17429
- * `kind` of TextTrack to look for to associate it with this menu.
17430
- *
17431
- * @type {string}
17432
- * @private
17433
- */
17434
-
17435
-
17436
- SubtitlesButton.prototype.kind_ = 'subtitles';
17437
-
17438
- /**
17439
- * The text that should display over the `SubtitlesButton`s controls. Added for localization.
17440
- *
17441
- * @type {string}
17442
- * @private
17443
- */
17444
- SubtitlesButton.prototype.controlText_ = 'Subtitles';
17445
-
17446
- Component.registerComponent('SubtitlesButton', SubtitlesButton);
17447
-
17448
- /**
17449
- * @file caption-settings-menu-item.js
17450
- */
17451
-
17452
- /**
17453
- * The menu item for caption track settings menu
17454
- *
17455
- * @extends TextTrackMenuItem
17456
- */
17457
-
17458
- var CaptionSettingsMenuItem = function (_TextTrackMenuItem) {
17459
- inherits(CaptionSettingsMenuItem, _TextTrackMenuItem);
17460
-
17461
- /**
17462
- * Creates an instance of this class.
17463
- *
17464
- * @param {Player} player
17465
- * The `Player` that this class should be attached to.
17466
- *
17467
- * @param {Object} [options]
17468
- * The key/value store of player options.
17469
- */
17470
- function CaptionSettingsMenuItem(player, options) {
17471
- classCallCheck(this, CaptionSettingsMenuItem);
17472
-
17473
- options.track = {
17474
- player: player,
17475
- kind: options.kind,
17476
- label: options.kind + ' settings',
17477
- selectable: false,
17478
- default: false,
17479
- mode: 'disabled'
17480
- };
17481
-
17482
- // CaptionSettingsMenuItem has no concept of 'selected'
17483
- options.selectable = false;
17484
-
17485
- options.name = 'CaptionSettingsMenuItem';
17486
-
17487
- var _this = possibleConstructorReturn(this, _TextTrackMenuItem.call(this, player, options));
17488
-
17489
- _this.addClass('vjs-texttrack-settings');
17490
- _this.controlText(', opens ' + options.kind + ' settings dialog');
17491
- return _this;
17492
- }
17493
-
17494
- /**
17495
- * This gets called when an `CaptionSettingsMenuItem` is "clicked". See
17496
- * {@link ClickableComponent} for more detailed information on what a click can be.
17497
- *
17498
- * @param {EventTarget~Event} [event]
17499
- * The `keydown`, `tap`, or `click` event that caused this function to be
17500
- * called.
17501
- *
17502
- * @listens tap
17503
- * @listens click
17504
- */
17505
-
17506
-
17507
- CaptionSettingsMenuItem.prototype.handleClick = function handleClick(event) {
17508
- this.player().getChild('textTrackSettings').open();
17509
- };
17510
-
17511
- return CaptionSettingsMenuItem;
17512
- }(TextTrackMenuItem);
17513
-
17514
- Component.registerComponent('CaptionSettingsMenuItem', CaptionSettingsMenuItem);
17515
-
17516
- /**
17517
- * @file captions-button.js
17518
- */
17519
-
17520
- /**
17521
- * The button component for toggling and selecting captions
17522
- *
17523
- * @extends TextTrackButton
17524
- */
17525
-
17526
- var CaptionsButton = function (_TextTrackButton) {
17527
- inherits(CaptionsButton, _TextTrackButton);
17528
-
17529
- /**
17530
- * Creates an instance of this class.
17531
- *
17532
- * @param {Player} player
17533
- * The `Player` that this class should be attached to.
17534
- *
17535
- * @param {Object} [options]
17536
- * The key/value store of player options.
17537
- *
17538
- * @param {Component~ReadyCallback} [ready]
17539
- * The function to call when this component is ready.
17540
- */
17541
- function CaptionsButton(player, options, ready) {
17542
- classCallCheck(this, CaptionsButton);
17543
- return possibleConstructorReturn(this, _TextTrackButton.call(this, player, options, ready));
17544
- }
17545
-
17546
- /**
17547
- * Builds the default DOM `className`.
17548
- *
17549
- * @return {string}
17550
- * The DOM `className` for this object.
17551
- */
17552
-
17553
-
17554
- CaptionsButton.prototype.buildCSSClass = function buildCSSClass() {
17555
- return 'vjs-captions-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
17556
- };
17557
-
17558
- CaptionsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17559
- return 'vjs-captions-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this);
17560
- };
17561
-
17562
- /**
17563
- * Create caption menu items
17564
- *
17565
- * @return {CaptionSettingsMenuItem[]}
17566
- * The array of current menu items.
17567
- */
17568
-
17569
-
17570
- CaptionsButton.prototype.createItems = function createItems() {
17571
- var items = [];
17572
-
17573
- if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) {
17574
- items.push(new CaptionSettingsMenuItem(this.player_, { kind: this.kind_ }));
17575
-
17576
- this.hideThreshold_ += 1;
17577
- }
17578
-
17579
- return _TextTrackButton.prototype.createItems.call(this, items);
17580
- };
17581
-
17582
- return CaptionsButton;
17583
- }(TextTrackButton);
17584
-
17585
- /**
17586
- * `kind` of TextTrack to look for to associate it with this menu.
17587
- *
17588
- * @type {string}
17589
- * @private
17590
- */
17591
-
17592
-
17593
- CaptionsButton.prototype.kind_ = 'captions';
17594
-
17595
- /**
17596
- * The text that should display over the `CaptionsButton`s controls. Added for localization.
17597
- *
17598
- * @type {string}
17599
- * @private
17600
- */
17601
- CaptionsButton.prototype.controlText_ = 'Captions';
17602
-
17603
- Component.registerComponent('CaptionsButton', CaptionsButton);
17604
-
17605
- /**
17606
- * @file subs-caps-menu-item.js
17607
- */
17608
-
17609
- /**
17610
- * SubsCapsMenuItem has an [cc] icon to distinguish captions from subtitles
17611
- * in the SubsCapsMenu.
17612
- *
17613
- * @extends TextTrackMenuItem
17614
- */
17615
-
17616
- var SubsCapsMenuItem = function (_TextTrackMenuItem) {
17617
- inherits(SubsCapsMenuItem, _TextTrackMenuItem);
17618
-
17619
- function SubsCapsMenuItem() {
17620
- classCallCheck(this, SubsCapsMenuItem);
17621
- return possibleConstructorReturn(this, _TextTrackMenuItem.apply(this, arguments));
17622
- }
17623
-
17624
- SubsCapsMenuItem.prototype.createEl = function createEl(type, props, attrs) {
17625
- var innerHTML = '<span class="vjs-menu-item-text">' + this.localize(this.options_.label);
17626
-
17627
- if (this.options_.track.kind === 'captions') {
17628
- innerHTML += '\n <span aria-hidden="true" class="vjs-icon-placeholder"></span>\n <span class="vjs-control-text"> ' + this.localize('Captions') + '</span>\n ';
17629
- }
17630
-
17631
- innerHTML += '</span>';
17632
-
17633
- var el = _TextTrackMenuItem.prototype.createEl.call(this, type, assign({
17634
- innerHTML: innerHTML
17635
- }, props), attrs);
17636
-
17637
- return el;
17638
- };
17639
-
17640
- return SubsCapsMenuItem;
17641
- }(TextTrackMenuItem);
17642
-
17643
- Component.registerComponent('SubsCapsMenuItem', SubsCapsMenuItem);
17644
-
17645
- /**
17646
- * @file sub-caps-button.js
17647
- */
17648
- /**
17649
- * The button component for toggling and selecting captions and/or subtitles
17650
- *
17651
- * @extends TextTrackButton
17652
- */
17653
-
17654
- var SubsCapsButton = function (_TextTrackButton) {
17655
- inherits(SubsCapsButton, _TextTrackButton);
17656
-
17657
- function SubsCapsButton(player) {
17658
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
17659
- classCallCheck(this, SubsCapsButton);
17660
-
17661
- // Although North America uses "captions" in most cases for
17662
- // "captions and subtitles" other locales use "subtitles"
17663
- var _this = possibleConstructorReturn(this, _TextTrackButton.call(this, player, options));
17664
-
17665
- _this.label_ = 'subtitles';
17666
- if (['en', 'en-us', 'en-ca', 'fr-ca'].indexOf(_this.player_.language_) > -1) {
17667
- _this.label_ = 'captions';
17668
- }
17669
- _this.menuButton_.controlText(toTitleCase(_this.label_));
17670
- return _this;
17671
- }
17672
-
17673
- /**
17674
- * Builds the default DOM `className`.
17675
- *
17676
- * @return {string}
17677
- * The DOM `className` for this object.
17678
- */
17679
-
17680
-
17681
- SubsCapsButton.prototype.buildCSSClass = function buildCSSClass() {
17682
- return 'vjs-subs-caps-button ' + _TextTrackButton.prototype.buildCSSClass.call(this);
17683
- };
17684
-
17685
- SubsCapsButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17686
- return 'vjs-subs-caps-button ' + _TextTrackButton.prototype.buildWrapperCSSClass.call(this);
17687
- };
17688
-
17689
- /**
17690
- * Create caption/subtitles menu items
17691
- *
17692
- * @return {CaptionSettingsMenuItem[]}
17693
- * The array of current menu items.
17694
- */
17695
-
17696
-
17697
- SubsCapsButton.prototype.createItems = function createItems() {
17698
- var items = [];
17699
-
17700
- if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && this.player().getChild('textTrackSettings')) {
17701
- items.push(new CaptionSettingsMenuItem(this.player_, { kind: this.label_ }));
17702
-
17703
- this.hideThreshold_ += 1;
17704
- }
17705
-
17706
- items = _TextTrackButton.prototype.createItems.call(this, items, SubsCapsMenuItem);
17707
- return items;
17708
- };
17709
-
17710
- return SubsCapsButton;
17711
- }(TextTrackButton);
17712
-
17713
- /**
17714
- * `kind`s of TextTrack to look for to associate it with this menu.
17715
- *
17716
- * @type {array}
17717
- * @private
17718
- */
17719
-
17720
-
17721
- SubsCapsButton.prototype.kinds_ = ['captions', 'subtitles'];
17722
-
17723
- /**
17724
- * The text that should display over the `SubsCapsButton`s controls.
17725
- *
17726
- *
17727
- * @type {string}
17728
- * @private
17729
- */
17730
- SubsCapsButton.prototype.controlText_ = 'Subtitles';
17731
-
17732
- Component.registerComponent('SubsCapsButton', SubsCapsButton);
17733
-
17734
- /**
17735
- * @file audio-track-menu-item.js
17736
- */
17737
-
17738
- /**
17739
- * An {@link AudioTrack} {@link MenuItem}
17740
- *
17741
- * @extends MenuItem
17742
- */
17743
-
17744
- var AudioTrackMenuItem = function (_MenuItem) {
17745
- inherits(AudioTrackMenuItem, _MenuItem);
17746
-
17747
- /**
17748
- * Creates an instance of this class.
17749
- *
17750
- * @param {Player} player
17751
- * The `Player` that this class should be attached to.
17752
- *
17753
- * @param {Object} [options]
17754
- * The key/value store of player options.
17755
- */
17756
- function AudioTrackMenuItem(player, options) {
17757
- classCallCheck(this, AudioTrackMenuItem);
17758
-
17759
- var track = options.track;
17760
- var tracks = player.audioTracks();
17761
-
17762
- // Modify options for parent MenuItem class's init.
17763
- options.label = track.label || track.language || 'Unknown';
17764
- options.selected = track.enabled;
17765
-
17766
- var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options));
17767
-
17768
- _this.track = track;
17769
-
17770
- _this.addClass('vjs-' + track.kind + '-menu-item');
17771
-
17772
- var changeHandler = function changeHandler() {
17773
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
17774
- args[_key] = arguments[_key];
17775
- }
17776
-
17777
- _this.handleTracksChange.apply(_this, args);
17778
- };
17779
-
17780
- tracks.addEventListener('change', changeHandler);
17781
- _this.on('dispose', function () {
17782
- tracks.removeEventListener('change', changeHandler);
17783
- });
17784
- return _this;
17785
- }
17786
-
17787
- AudioTrackMenuItem.prototype.createEl = function createEl(type, props, attrs) {
17788
- var innerHTML = '<span class="vjs-menu-item-text">' + this.localize(this.options_.label);
17789
-
17790
- if (this.options_.track.kind === 'main-desc') {
17791
- innerHTML += '\n <span aria-hidden="true" class="vjs-icon-placeholder"></span>\n <span class="vjs-control-text"> ' + this.localize('Descriptions') + '</span>\n ';
17792
- }
17793
-
17794
- innerHTML += '</span>';
17795
-
17796
- var el = _MenuItem.prototype.createEl.call(this, type, assign({
17797
- innerHTML: innerHTML
17798
- }, props), attrs);
17799
-
17800
- return el;
17801
- };
17802
-
17803
- /**
17804
- * This gets called when an `AudioTrackMenuItem is "clicked". See {@link ClickableComponent}
17805
- * for more detailed information on what a click can be.
17806
- *
17807
- * @param {EventTarget~Event} [event]
17808
- * The `keydown`, `tap`, or `click` event that caused this function to be
17809
- * called.
17810
- *
17811
- * @listens tap
17812
- * @listens click
17813
- */
17814
-
17815
-
17816
- AudioTrackMenuItem.prototype.handleClick = function handleClick(event) {
17817
- var tracks = this.player_.audioTracks();
17818
-
17819
- _MenuItem.prototype.handleClick.call(this, event);
17820
-
17821
- for (var i = 0; i < tracks.length; i++) {
17822
- var track = tracks[i];
17823
-
17824
- track.enabled = track === this.track;
17825
- }
17826
- };
17827
-
17828
- /**
17829
- * Handle any {@link AudioTrack} change.
17830
- *
17831
- * @param {EventTarget~Event} [event]
17832
- * The {@link AudioTrackList#change} event that caused this to run.
17833
- *
17834
- * @listens AudioTrackList#change
17835
- */
17836
-
17837
-
17838
- AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
17839
- this.selected(this.track.enabled);
17840
- };
17841
-
17842
- return AudioTrackMenuItem;
17843
- }(MenuItem);
17844
-
17845
- Component.registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
17846
-
17847
- /**
17848
- * @file audio-track-button.js
17849
- */
17850
-
17851
- /**
17852
- * The base class for buttons that toggle specific {@link AudioTrack} types.
17853
- *
17854
- * @extends TrackButton
17855
- */
17856
-
17857
- var AudioTrackButton = function (_TrackButton) {
17858
- inherits(AudioTrackButton, _TrackButton);
17859
-
17860
- /**
17861
- * Creates an instance of this class.
17862
- *
17863
- * @param {Player} player
17864
- * The `Player` that this class should be attached to.
17865
- *
17866
- * @param {Object} [options={}]
17867
- * The key/value store of player options.
17868
- */
17869
- function AudioTrackButton(player) {
17870
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
17871
- classCallCheck(this, AudioTrackButton);
17872
-
17873
- options.tracks = player.audioTracks();
17874
-
17875
- return possibleConstructorReturn(this, _TrackButton.call(this, player, options));
17876
- }
17877
-
17878
- /**
17879
- * Builds the default DOM `className`.
17880
- *
17881
- * @return {string}
17882
- * The DOM `className` for this object.
17883
- */
17884
-
17885
-
17886
- AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() {
17887
- return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this);
17888
- };
17889
-
17890
- AudioTrackButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
17891
- return 'vjs-audio-button ' + _TrackButton.prototype.buildWrapperCSSClass.call(this);
17892
- };
17893
-
17894
- /**
17895
- * Create a menu item for each audio track
17896
- *
17897
- * @param {AudioTrackMenuItem[]} [items=[]]
17898
- * An array of existing menu items to use.
17899
- *
17900
- * @return {AudioTrackMenuItem[]}
17901
- * An array of menu items
17902
- */
17903
-
17904
-
17905
- AudioTrackButton.prototype.createItems = function createItems() {
17906
- var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
17907
-
17908
- // if there's only one audio track, there no point in showing it
17909
- this.hideThreshold_ = 1;
17910
-
17911
- var tracks = this.player_.audioTracks();
17912
-
17913
- for (var i = 0; i < tracks.length; i++) {
17914
- var track = tracks[i];
17915
-
17916
- items.push(new AudioTrackMenuItem(this.player_, {
17917
- track: track,
17918
- // MenuItem is selectable
17919
- selectable: true,
17920
- // MenuItem is NOT multiSelectable (i.e. only one can be marked "selected" at a time)
17921
- multiSelectable: false
17922
- }));
17923
- }
17924
-
17925
- return items;
17926
- };
17927
-
17928
- return AudioTrackButton;
17929
- }(TrackButton);
17930
-
17931
- /**
17932
- * The text that should display over the `AudioTrackButton`s controls. Added for localization.
17933
- *
17934
- * @type {string}
17935
- * @private
17936
- */
17937
-
17938
-
17939
- AudioTrackButton.prototype.controlText_ = 'Audio Track';
17940
- Component.registerComponent('AudioTrackButton', AudioTrackButton);
17941
-
17942
- /**
17943
- * @file playback-rate-menu-item.js
17944
- */
17945
-
17946
- /**
17947
- * The specific menu item type for selecting a playback rate.
17948
- *
17949
- * @extends MenuItem
17950
- */
17951
-
17952
- var PlaybackRateMenuItem = function (_MenuItem) {
17953
- inherits(PlaybackRateMenuItem, _MenuItem);
17954
-
17955
- /**
17956
- * Creates an instance of this class.
17957
- *
17958
- * @param {Player} player
17959
- * The `Player` that this class should be attached to.
17960
- *
17961
- * @param {Object} [options]
17962
- * The key/value store of player options.
17963
- */
17964
- function PlaybackRateMenuItem(player, options) {
17965
- classCallCheck(this, PlaybackRateMenuItem);
17966
-
17967
- var label = options.rate;
17968
- var rate = parseFloat(label, 10);
17969
-
17970
- // Modify options for parent MenuItem class's init.
17971
- options.label = label;
17972
- options.selected = rate === 1;
17973
- options.selectable = true;
17974
- options.multiSelectable = false;
17975
-
17976
- var _this = possibleConstructorReturn(this, _MenuItem.call(this, player, options));
17977
-
17978
- _this.label = label;
17979
- _this.rate = rate;
17980
-
17981
- _this.on(player, 'ratechange', _this.update);
17982
- return _this;
17983
- }
17984
-
17985
- /**
17986
- * This gets called when an `PlaybackRateMenuItem` is "clicked". See
17987
- * {@link ClickableComponent} for more detailed information on what a click can be.
17988
- *
17989
- * @param {EventTarget~Event} [event]
17990
- * The `keydown`, `tap`, or `click` event that caused this function to be
17991
- * called.
17992
- *
17993
- * @listens tap
17994
- * @listens click
17995
- */
17996
-
17997
-
17998
- PlaybackRateMenuItem.prototype.handleClick = function handleClick(event) {
17999
- _MenuItem.prototype.handleClick.call(this);
18000
- this.player().playbackRate(this.rate);
18001
- };
18002
-
18003
- /**
18004
- * Update the PlaybackRateMenuItem when the playbackrate changes.
18005
- *
18006
- * @param {EventTarget~Event} [event]
18007
- * The `ratechange` event that caused this function to run.
18008
- *
18009
- * @listens Player#ratechange
18010
- */
18011
-
18012
-
18013
- PlaybackRateMenuItem.prototype.update = function update(event) {
18014
- this.selected(this.player().playbackRate() === this.rate);
18015
- };
18016
-
18017
- return PlaybackRateMenuItem;
18018
- }(MenuItem);
18019
-
18020
- /**
18021
- * The text that should display over the `PlaybackRateMenuItem`s controls. Added for localization.
18022
- *
18023
- * @type {string}
18024
- * @private
18025
- */
18026
-
18027
-
18028
- PlaybackRateMenuItem.prototype.contentElType = 'button';
18029
-
18030
- Component.registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
18031
-
18032
- /**
18033
- * @file playback-rate-menu-button.js
18034
- */
18035
-
18036
- /**
18037
- * The component for controlling the playback rate.
18038
- *
18039
- * @extends MenuButton
18040
- */
18041
-
18042
- var PlaybackRateMenuButton = function (_MenuButton) {
18043
- inherits(PlaybackRateMenuButton, _MenuButton);
18044
-
18045
- /**
18046
- * Creates an instance of this class.
18047
- *
18048
- * @param {Player} player
18049
- * The `Player` that this class should be attached to.
18050
- *
18051
- * @param {Object} [options]
18052
- * The key/value store of player options.
18053
- */
18054
- function PlaybackRateMenuButton(player, options) {
18055
- classCallCheck(this, PlaybackRateMenuButton);
18056
-
18057
- var _this = possibleConstructorReturn(this, _MenuButton.call(this, player, options));
18058
-
18059
- _this.updateVisibility();
18060
- _this.updateLabel();
18061
-
18062
- _this.on(player, 'loadstart', _this.updateVisibility);
18063
- _this.on(player, 'ratechange', _this.updateLabel);
18064
- return _this;
18065
- }
18066
-
18067
- /**
18068
- * Create the `Component`'s DOM element
18069
- *
18070
- * @return {Element}
18071
- * The element that was created.
18072
- */
18073
-
18074
-
18075
- PlaybackRateMenuButton.prototype.createEl = function createEl$$1() {
18076
- var el = _MenuButton.prototype.createEl.call(this);
18077
-
18078
- this.labelEl_ = createEl('div', {
18079
- className: 'vjs-playback-rate-value',
18080
- innerHTML: '1x'
18081
- });
18082
-
18083
- el.appendChild(this.labelEl_);
18084
-
18085
- return el;
18086
- };
18087
-
18088
- PlaybackRateMenuButton.prototype.dispose = function dispose() {
18089
- this.labelEl_ = null;
18090
-
18091
- _MenuButton.prototype.dispose.call(this);
18092
- };
18093
-
18094
- /**
18095
- * Builds the default DOM `className`.
18096
- *
18097
- * @return {string}
18098
- * The DOM `className` for this object.
18099
- */
18100
-
18101
-
18102
- PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() {
18103
- return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this);
18104
- };
18105
-
18106
- PlaybackRateMenuButton.prototype.buildWrapperCSSClass = function buildWrapperCSSClass() {
18107
- return 'vjs-playback-rate ' + _MenuButton.prototype.buildWrapperCSSClass.call(this);
18108
- };
18109
-
18110
- /**
18111
- * Create the playback rate menu
18112
- *
18113
- * @return {Menu}
18114
- * Menu object populated with {@link PlaybackRateMenuItem}s
18115
- */
18116
-
18117
-
18118
- PlaybackRateMenuButton.prototype.createMenu = function createMenu() {
18119
- var menu = new Menu(this.player());
18120
- var rates = this.playbackRates();
18121
-
18122
- if (rates) {
18123
- for (var i = rates.length - 1; i >= 0; i--) {
18124
- menu.addChild(new PlaybackRateMenuItem(this.player(), { rate: rates[i] + 'x' }));
18125
- }
18126
- }
18127
-
18128
- return menu;
18129
- };
18130
-
18131
- /**
18132
- * Updates ARIA accessibility attributes
18133
- */
18134
-
18135
-
18136
- PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() {
18137
- // Current playback rate
18138
- this.el().setAttribute('aria-valuenow', this.player().playbackRate());
18139
- };
18140
-
18141
- /**
18142
- * This gets called when an `PlaybackRateMenuButton` is "clicked". See
18143
- * {@link ClickableComponent} for more detailed information on what a click can be.
18144
- *
18145
- * @param {EventTarget~Event} [event]
18146
- * The `keydown`, `tap`, or `click` event that caused this function to be
18147
- * called.
18148
- *
18149
- * @listens tap
18150
- * @listens click
18151
- */
18152
-
18153
-
18154
- PlaybackRateMenuButton.prototype.handleClick = function handleClick(event) {
18155
- // select next rate option
18156
- var currentRate = this.player().playbackRate();
18157
- var rates = this.playbackRates();
18158
-
18159
- // this will select first one if the last one currently selected
18160
- var newRate = rates[0];
18161
-
18162
- for (var i = 0; i < rates.length; i++) {
18163
- if (rates[i] > currentRate) {
18164
- newRate = rates[i];
18165
- break;
18166
- }
18167
- }
18168
- this.player().playbackRate(newRate);
18169
- };
18170
-
18171
- /**
18172
- * Get possible playback rates
18173
- *
18174
- * @return {Array}
18175
- * All possible playback rates
18176
- */
18177
-
18178
-
18179
- PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() {
18180
- return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates;
18181
- };
18182
-
18183
- /**
18184
- * Get whether playback rates is supported by the tech
18185
- * and an array of playback rates exists
18186
- *
18187
- * @return {boolean}
18188
- * Whether changing playback rate is supported
18189
- */
18190
-
18191
-
18192
- PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() {
18193
- return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0;
18194
- };
18195
-
18196
- /**
18197
- * Hide playback rate controls when they're no playback rate options to select
18198
- *
18199
- * @param {EventTarget~Event} [event]
18200
- * The event that caused this function to run.
18201
- *
18202
- * @listens Player#loadstart
18203
- */
18204
-
18205
-
18206
- PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility(event) {
18207
- if (this.playbackRateSupported()) {
18208
- this.removeClass('vjs-hidden');
18209
- } else {
18210
- this.addClass('vjs-hidden');
18211
- }
18212
- };
18213
-
18214
- /**
18215
- * Update button label when rate changed
18216
- *
18217
- * @param {EventTarget~Event} [event]
18218
- * The event that caused this function to run.
18219
- *
18220
- * @listens Player#ratechange
18221
- */
18222
-
18223
-
18224
- PlaybackRateMenuButton.prototype.updateLabel = function updateLabel(event) {
18225
- if (this.playbackRateSupported()) {
18226
- this.labelEl_.innerHTML = this.player().playbackRate() + 'x';
18227
- }
18228
- };
18229
-
18230
- return PlaybackRateMenuButton;
18231
- }(MenuButton);
18232
-
18233
- /**
18234
- * The text that should display over the `FullscreenToggle`s controls. Added for localization.
18235
- *
18236
- * @type {string}
18237
- * @private
18238
- */
18239
-
18240
-
18241
- PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';
18242
-
18243
- Component.registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
18244
-
18245
- /**
18246
- * @file spacer.js
18247
- */
18248
-
18249
- /**
18250
- * Just an empty spacer element that can be used as an append point for plugins, etc.
18251
- * Also can be used to create space between elements when necessary.
18252
- *
18253
- * @extends Component
18254
- */
18255
-
18256
- var Spacer = function (_Component) {
18257
- inherits(Spacer, _Component);
18258
-
18259
- function Spacer() {
18260
- classCallCheck(this, Spacer);
18261
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
18262
- }
18263
-
18264
- /**
18265
- * Builds the default DOM `className`.
18266
- *
18267
- * @return {string}
18268
- * The DOM `className` for this object.
18269
- */
18270
- Spacer.prototype.buildCSSClass = function buildCSSClass() {
18271
- return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this);
18272
- };
18273
-
18274
- /**
18275
- * Create the `Component`'s DOM element
18276
- *
18277
- * @return {Element}
18278
- * The element that was created.
18279
- */
18280
-
18281
-
18282
- Spacer.prototype.createEl = function createEl() {
18283
- return _Component.prototype.createEl.call(this, 'div', {
18284
- className: this.buildCSSClass()
18285
- });
18286
- };
18287
-
18288
- return Spacer;
18289
- }(Component);
18290
-
18291
- Component.registerComponent('Spacer', Spacer);
18292
-
18293
- /**
18294
- * @file custom-control-spacer.js
18295
- */
18296
-
18297
- /**
18298
- * Spacer specifically meant to be used as an insertion point for new plugins, etc.
18299
- *
18300
- * @extends Spacer
18301
- */
18302
-
18303
- var CustomControlSpacer = function (_Spacer) {
18304
- inherits(CustomControlSpacer, _Spacer);
18305
-
18306
- function CustomControlSpacer() {
18307
- classCallCheck(this, CustomControlSpacer);
18308
- return possibleConstructorReturn(this, _Spacer.apply(this, arguments));
18309
- }
18310
-
18311
- /**
18312
- * Builds the default DOM `className`.
18313
- *
18314
- * @return {string}
18315
- * The DOM `className` for this object.
18316
- */
18317
- CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() {
18318
- return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this);
18319
- };
18320
-
18321
- /**
18322
- * Create the `Component`'s DOM element
18323
- *
18324
- * @return {Element}
18325
- * The element that was created.
18326
- */
18327
-
18328
-
18329
- CustomControlSpacer.prototype.createEl = function createEl() {
18330
- var el = _Spacer.prototype.createEl.call(this, {
18331
- className: this.buildCSSClass()
18332
- });
18333
-
18334
- // No-flex/table-cell mode requires there be some content
18335
- // in the cell to fill the remaining space of the table.
18336
- el.innerHTML = '\xA0';
18337
- return el;
18338
- };
18339
-
18340
- return CustomControlSpacer;
18341
- }(Spacer);
18342
-
18343
- Component.registerComponent('CustomControlSpacer', CustomControlSpacer);
18344
-
18345
- /**
18346
- * @file control-bar.js
18347
- */
18348
-
18349
- /**
18350
- * Container of main controls.
18351
- *
18352
- * @extends Component
18353
- */
18354
-
18355
- var ControlBar = function (_Component) {
18356
- inherits(ControlBar, _Component);
18357
-
18358
- function ControlBar() {
18359
- classCallCheck(this, ControlBar);
18360
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
18361
- }
18362
-
18363
- /**
18364
- * Create the `Component`'s DOM element
18365
- *
18366
- * @return {Element}
18367
- * The element that was created.
18368
- */
18369
- ControlBar.prototype.createEl = function createEl() {
18370
- return _Component.prototype.createEl.call(this, 'div', {
18371
- className: 'vjs-control-bar',
18372
- dir: 'ltr'
18373
- });
18374
- };
18375
-
18376
- return ControlBar;
18377
- }(Component);
18378
-
18379
- /**
18380
- * Default options for `ControlBar`
18381
- *
18382
- * @type {Object}
18383
- * @private
18384
- */
18385
-
18386
-
18387
- ControlBar.prototype.options_ = {
18388
- children: ['playToggle', 'volumePanel', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subsCapsButton', 'audioTrackButton', 'fullscreenToggle']
18389
- };
18390
-
18391
- Component.registerComponent('ControlBar', ControlBar);
18392
-
18393
- /**
18394
- * @file error-display.js
18395
- */
18396
-
18397
- /**
18398
- * A display that indicates an error has occurred. This means that the video
18399
- * is unplayable.
18400
- *
18401
- * @extends ModalDialog
18402
- */
18403
-
18404
- var ErrorDisplay = function (_ModalDialog) {
18405
- inherits(ErrorDisplay, _ModalDialog);
18406
-
18407
- /**
18408
- * Creates an instance of this class.
18409
- *
18410
- * @param {Player} player
18411
- * The `Player` that this class should be attached to.
18412
- *
18413
- * @param {Object} [options]
18414
- * The key/value store of player options.
18415
- */
18416
- function ErrorDisplay(player, options) {
18417
- classCallCheck(this, ErrorDisplay);
18418
-
18419
- var _this = possibleConstructorReturn(this, _ModalDialog.call(this, player, options));
18420
-
18421
- _this.on(player, 'error', _this.open);
18422
- return _this;
18423
- }
18424
-
18425
- /**
18426
- * Builds the default DOM `className`.
18427
- *
18428
- * @return {string}
18429
- * The DOM `className` for this object.
18430
- *
18431
- * @deprecated Since version 5.
18432
- */
18433
-
18434
-
18435
- ErrorDisplay.prototype.buildCSSClass = function buildCSSClass() {
18436
- return 'vjs-error-display ' + _ModalDialog.prototype.buildCSSClass.call(this);
18437
- };
18438
-
18439
- /**
18440
- * Gets the localized error message based on the `Player`s error.
18441
- *
18442
- * @return {string}
18443
- * The `Player`s error message localized or an empty string.
18444
- */
18445
-
18446
-
18447
- ErrorDisplay.prototype.content = function content() {
18448
- var error = this.player().error();
18449
-
18450
- return error ? this.localize(error.message) : '';
18451
- };
18452
-
18453
- return ErrorDisplay;
18454
- }(ModalDialog);
18455
-
18456
- /**
18457
- * The default options for an `ErrorDisplay`.
18458
- *
18459
- * @private
18460
- */
18461
-
18462
-
18463
- ErrorDisplay.prototype.options_ = mergeOptions(ModalDialog.prototype.options_, {
18464
- pauseOnOpen: false,
18465
- fillAlways: true,
18466
- temporary: false,
18467
- uncloseable: true
18468
- });
18469
-
18470
- Component.registerComponent('ErrorDisplay', ErrorDisplay);
18471
-
18472
- /**
18473
- * @file text-track-settings.js
18474
- */
18475
-
18476
- var LOCAL_STORAGE_KEY = 'vjs-text-track-settings';
18477
-
18478
- var COLOR_BLACK = ['#000', 'Black'];
18479
- var COLOR_BLUE = ['#00F', 'Blue'];
18480
- var COLOR_CYAN = ['#0FF', 'Cyan'];
18481
- var COLOR_GREEN = ['#0F0', 'Green'];
18482
- var COLOR_MAGENTA = ['#F0F', 'Magenta'];
18483
- var COLOR_RED = ['#F00', 'Red'];
18484
- var COLOR_WHITE = ['#FFF', 'White'];
18485
- var COLOR_YELLOW = ['#FF0', 'Yellow'];
18486
-
18487
- var OPACITY_OPAQUE = ['1', 'Opaque'];
18488
- var OPACITY_SEMI = ['0.5', 'Semi-Transparent'];
18489
- var OPACITY_TRANS = ['0', 'Transparent'];
18490
-
18491
- // Configuration for the various <select> elements in the DOM of this component.
18492
- //
18493
- // Possible keys include:
18494
- //
18495
- // `default`:
18496
- // The default option index. Only needs to be provided if not zero.
18497
- // `parser`:
18498
- // A function which is used to parse the value from the selected option in
18499
- // a customized way.
18500
- // `selector`:
18501
- // The selector used to find the associated <select> element.
18502
- var selectConfigs = {
18503
- backgroundColor: {
18504
- selector: '.vjs-bg-color > select',
18505
- id: 'captions-background-color-%s',
18506
- label: 'Color',
18507
- options: [COLOR_BLACK, COLOR_WHITE, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN]
18508
- },
18509
-
18510
- backgroundOpacity: {
18511
- selector: '.vjs-bg-opacity > select',
18512
- id: 'captions-background-opacity-%s',
18513
- label: 'Transparency',
18514
- options: [OPACITY_OPAQUE, OPACITY_SEMI, OPACITY_TRANS]
18515
- },
18516
-
18517
- color: {
18518
- selector: '.vjs-fg-color > select',
18519
- id: 'captions-foreground-color-%s',
18520
- label: 'Color',
18521
- options: [COLOR_WHITE, COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW, COLOR_MAGENTA, COLOR_CYAN]
18522
- },
18523
-
18524
- edgeStyle: {
18525
- selector: '.vjs-edge-style > select',
18526
- id: '%s',
18527
- label: 'Text Edge Style',
18528
- options: [['none', 'None'], ['raised', 'Raised'], ['depressed', 'Depressed'], ['uniform', 'Uniform'], ['dropshadow', 'Dropshadow']]
18529
- },
18530
-
18531
- fontFamily: {
18532
- selector: '.vjs-font-family > select',
18533
- id: 'captions-font-family-%s',
18534
- label: 'Font Family',
18535
- options: [['proportionalSansSerif', 'Proportional Sans-Serif'], ['monospaceSansSerif', 'Monospace Sans-Serif'], ['proportionalSerif', 'Proportional Serif'], ['monospaceSerif', 'Monospace Serif'], ['casual', 'Casual'], ['script', 'Script'], ['small-caps', 'Small Caps']]
18536
- },
18537
-
18538
- fontPercent: {
18539
- selector: '.vjs-font-percent > select',
18540
- id: 'captions-font-size-%s',
18541
- label: 'Font Size',
18542
- options: [['0.50', '50%'], ['0.75', '75%'], ['1.00', '100%'], ['1.25', '125%'], ['1.50', '150%'], ['1.75', '175%'], ['2.00', '200%'], ['3.00', '300%'], ['4.00', '400%']],
18543
- default: 2,
18544
- parser: function parser(v) {
18545
- return v === '1.00' ? null : Number(v);
18546
- }
18547
- },
18548
-
18549
- textOpacity: {
18550
- selector: '.vjs-text-opacity > select',
18551
- id: 'captions-foreground-opacity-%s',
18552
- label: 'Transparency',
18553
- options: [OPACITY_OPAQUE, OPACITY_SEMI]
18554
- },
18555
-
18556
- // Options for this object are defined below.
18557
- windowColor: {
18558
- selector: '.vjs-window-color > select',
18559
- id: 'captions-window-color-%s',
18560
- label: 'Color'
18561
- },
18562
-
18563
- // Options for this object are defined below.
18564
- windowOpacity: {
18565
- selector: '.vjs-window-opacity > select',
18566
- id: 'captions-window-opacity-%s',
18567
- label: 'Transparency',
18568
- options: [OPACITY_TRANS, OPACITY_SEMI, OPACITY_OPAQUE]
18569
- }
18570
- };
18571
-
18572
- selectConfigs.windowColor.options = selectConfigs.backgroundColor.options;
18573
-
18574
- /**
18575
- * Get the actual value of an option.
18576
- *
18577
- * @param {string} value
18578
- * The value to get
18579
- *
18580
- * @param {Function} [parser]
18581
- * Optional function to adjust the value.
18582
- *
18583
- * @return {Mixed}
18584
- * - Will be `undefined` if no value exists
18585
- * - Will be `undefined` if the given value is "none".
18586
- * - Will be the actual value otherwise.
18587
- *
18588
- * @private
18589
- */
18590
- function parseOptionValue(value, parser) {
18591
- if (parser) {
18592
- value = parser(value);
18593
- }
18594
-
18595
- if (value && value !== 'none') {
18596
- return value;
18597
- }
18598
- }
18599
-
18600
- /**
18601
- * Gets the value of the selected <option> element within a <select> element.
18602
- *
18603
- * @param {Element} el
18604
- * the element to look in
18605
- *
18606
- * @param {Function} [parser]
18607
- * Optional function to adjust the value.
18608
- *
18609
- * @return {Mixed}
18610
- * - Will be `undefined` if no value exists
18611
- * - Will be `undefined` if the given value is "none".
18612
- * - Will be the actual value otherwise.
18613
- *
18614
- * @private
18615
- */
18616
- function getSelectedOptionValue(el, parser) {
18617
- var value = el.options[el.options.selectedIndex].value;
18618
-
18619
- return parseOptionValue(value, parser);
18620
- }
18621
-
18622
- /**
18623
- * Sets the selected <option> element within a <select> element based on a
18624
- * given value.
18625
- *
18626
- * @param {Element} el
18627
- * The element to look in.
18628
- *
18629
- * @param {string} value
18630
- * the property to look on.
18631
- *
18632
- * @param {Function} [parser]
18633
- * Optional function to adjust the value before comparing.
18634
- *
18635
- * @private
18636
- */
18637
- function setSelectedOption(el, value, parser) {
18638
- if (!value) {
18639
- return;
18640
- }
18641
-
18642
- for (var i = 0; i < el.options.length; i++) {
18643
- if (parseOptionValue(el.options[i].value, parser) === value) {
18644
- el.selectedIndex = i;
18645
- break;
18646
- }
18647
- }
18648
- }
18649
-
18650
- /**
18651
- * Manipulate Text Tracks settings.
18652
- *
18653
- * @extends ModalDialog
18654
- */
18655
-
18656
- var TextTrackSettings = function (_ModalDialog) {
18657
- inherits(TextTrackSettings, _ModalDialog);
18658
-
18659
- /**
18660
- * Creates an instance of this class.
18661
- *
18662
- * @param {Player} player
18663
- * The `Player` that this class should be attached to.
18664
- *
18665
- * @param {Object} [options]
18666
- * The key/value store of player options.
18667
- */
18668
- function TextTrackSettings(player, options) {
18669
- classCallCheck(this, TextTrackSettings);
18670
-
18671
- options.temporary = false;
18672
-
18673
- var _this = possibleConstructorReturn(this, _ModalDialog.call(this, player, options));
18674
-
18675
- _this.updateDisplay = bind(_this, _this.updateDisplay);
18676
-
18677
- // fill the modal and pretend we have opened it
18678
- _this.fill();
18679
- _this.hasBeenOpened_ = _this.hasBeenFilled_ = true;
18680
-
18681
- _this.endDialog = createEl('p', {
18682
- className: 'vjs-control-text',
18683
- textContent: _this.localize('End of dialog window.')
18684
- });
18685
- _this.el().appendChild(_this.endDialog);
18686
-
18687
- _this.setDefaults();
18688
-
18689
- // Grab `persistTextTrackSettings` from the player options if not passed in child options
18690
- if (options.persistTextTrackSettings === undefined) {
18691
- _this.options_.persistTextTrackSettings = _this.options_.playerOptions.persistTextTrackSettings;
18692
- }
18693
-
18694
- _this.on(_this.$('.vjs-done-button'), 'click', function () {
18695
- _this.saveSettings();
18696
- _this.close();
18697
- });
18698
-
18699
- _this.on(_this.$('.vjs-default-button'), 'click', function () {
18700
- _this.setDefaults();
18701
- _this.updateDisplay();
18702
- });
18703
-
18704
- each(selectConfigs, function (config) {
18705
- _this.on(_this.$(config.selector), 'change', _this.updateDisplay);
18706
- });
18707
-
18708
- if (_this.options_.persistTextTrackSettings) {
18709
- _this.restoreSettings();
18710
- }
18711
- return _this;
18712
- }
18713
-
18714
- TextTrackSettings.prototype.dispose = function dispose() {
18715
- this.endDialog = null;
18716
-
18717
- _ModalDialog.prototype.dispose.call(this);
18718
- };
18719
-
18720
- /**
18721
- * Create a <select> element with configured options.
18722
- *
18723
- * @param {string} key
18724
- * Configuration key to use during creation.
18725
- *
18726
- * @return {string}
18727
- * An HTML string.
18728
- *
18729
- * @private
18730
- */
18731
-
18732
-
18733
- TextTrackSettings.prototype.createElSelect_ = function createElSelect_(key) {
18734
- var _this2 = this;
18735
-
18736
- var legendId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
18737
- var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'label';
18738
-
18739
- var config = selectConfigs[key];
18740
- var id = config.id.replace('%s', this.id_);
18741
- var selectLabelledbyIds = [legendId, id].join(' ').trim();
18742
-
18743
- return ['<' + type + ' id="' + id + '" class="' + (type === 'label' ? 'vjs-label' : '') + '">', this.localize(config.label), '</' + type + '>', '<select aria-labelledby="' + selectLabelledbyIds + '">'].concat(config.options.map(function (o) {
18744
- var optionId = id + '-' + o[1].replace(/\W+/g, '');
18745
-
18746
- return ['<option id="' + optionId + '" value="' + o[0] + '" ', 'aria-labelledby="' + selectLabelledbyIds + ' ' + optionId + '">', _this2.localize(o[1]), '</option>'].join('');
18747
- })).concat('</select>').join('');
18748
- };
18749
-
18750
- /**
18751
- * Create foreground color element for the component
18752
- *
18753
- * @return {string}
18754
- * An HTML string.
18755
- *
18756
- * @private
18757
- */
18758
-
18759
-
18760
- TextTrackSettings.prototype.createElFgColor_ = function createElFgColor_() {
18761
- var legendId = 'captions-text-legend-' + this.id_;
18762
-
18763
- return ['<fieldset class="vjs-fg-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Text'), '</legend>', this.createElSelect_('color', legendId), '<span class="vjs-text-opacity vjs-opacity">', this.createElSelect_('textOpacity', legendId), '</span>', '</fieldset>'].join('');
18764
- };
18765
-
18766
- /**
18767
- * Create background color element for the component
18768
- *
18769
- * @return {string}
18770
- * An HTML string.
18771
- *
18772
- * @private
18773
- */
18774
-
18775
-
18776
- TextTrackSettings.prototype.createElBgColor_ = function createElBgColor_() {
18777
- var legendId = 'captions-background-' + this.id_;
18778
-
18779
- return ['<fieldset class="vjs-bg-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Background'), '</legend>', this.createElSelect_('backgroundColor', legendId), '<span class="vjs-bg-opacity vjs-opacity">', this.createElSelect_('backgroundOpacity', legendId), '</span>', '</fieldset>'].join('');
18780
- };
18781
-
18782
- /**
18783
- * Create window color element for the component
18784
- *
18785
- * @return {string}
18786
- * An HTML string.
18787
- *
18788
- * @private
18789
- */
18790
-
18791
-
18792
- TextTrackSettings.prototype.createElWinColor_ = function createElWinColor_() {
18793
- var legendId = 'captions-window-' + this.id_;
18794
-
18795
- return ['<fieldset class="vjs-window-color vjs-track-setting">', '<legend id="' + legendId + '">', this.localize('Window'), '</legend>', this.createElSelect_('windowColor', legendId), '<span class="vjs-window-opacity vjs-opacity">', this.createElSelect_('windowOpacity', legendId), '</span>', '</fieldset>'].join('');
18796
- };
18797
-
18798
- /**
18799
- * Create color elements for the component
18800
- *
18801
- * @return {Element}
18802
- * The element that was created
18803
- *
18804
- * @private
18805
- */
18806
-
18807
-
18808
- TextTrackSettings.prototype.createElColors_ = function createElColors_() {
18809
- return createEl('div', {
18810
- className: 'vjs-track-settings-colors',
18811
- innerHTML: [this.createElFgColor_(), this.createElBgColor_(), this.createElWinColor_()].join('')
18812
- });
18813
- };
18814
-
18815
- /**
18816
- * Create font elements for the component
18817
- *
18818
- * @return {Element}
18819
- * The element that was created.
18820
- *
18821
- * @private
18822
- */
18823
-
18824
-
18825
- TextTrackSettings.prototype.createElFont_ = function createElFont_() {
18826
- return createEl('div', {
18827
- className: 'vjs-track-settings-font',
18828
- innerHTML: ['<fieldset class="vjs-font-percent vjs-track-setting">', this.createElSelect_('fontPercent', '', 'legend'), '</fieldset>', '<fieldset class="vjs-edge-style vjs-track-setting">', this.createElSelect_('edgeStyle', '', 'legend'), '</fieldset>', '<fieldset class="vjs-font-family vjs-track-setting">', this.createElSelect_('fontFamily', '', 'legend'), '</fieldset>'].join('')
18829
- });
18830
- };
18831
-
18832
- /**
18833
- * Create controls for the component
18834
- *
18835
- * @return {Element}
18836
- * The element that was created.
18837
- *
18838
- * @private
18839
- */
18840
-
18841
-
18842
- TextTrackSettings.prototype.createElControls_ = function createElControls_() {
18843
- var defaultsDescription = this.localize('restore all settings to the default values');
18844
-
18845
- return createEl('div', {
18846
- className: 'vjs-track-settings-controls',
18847
- innerHTML: ['<button class="vjs-default-button" title="' + defaultsDescription + '">', this.localize('Reset'), '<span class="vjs-control-text"> ' + defaultsDescription + '</span>', '</button>', '<button class="vjs-done-button">' + this.localize('Done') + '</button>'].join('')
18848
- });
18849
- };
18850
-
18851
- TextTrackSettings.prototype.content = function content() {
18852
- return [this.createElColors_(), this.createElFont_(), this.createElControls_()];
18853
- };
18854
-
18855
- TextTrackSettings.prototype.label = function label() {
18856
- return this.localize('Caption Settings Dialog');
18857
- };
18858
-
18859
- TextTrackSettings.prototype.description = function description() {
18860
- return this.localize('Beginning of dialog window. Escape will cancel and close the window.');
18861
- };
18862
-
18863
- TextTrackSettings.prototype.buildCSSClass = function buildCSSClass() {
18864
- return _ModalDialog.prototype.buildCSSClass.call(this) + ' vjs-text-track-settings';
18865
- };
18866
-
18867
- /**
18868
- * Gets an object of text track settings (or null).
18869
- *
18870
- * @return {Object}
18871
- * An object with config values parsed from the DOM or localStorage.
18872
- */
18873
-
18874
-
18875
- TextTrackSettings.prototype.getValues = function getValues() {
18876
- var _this3 = this;
18877
-
18878
- return reduce(selectConfigs, function (accum, config, key) {
18879
- var value = getSelectedOptionValue(_this3.$(config.selector), config.parser);
18880
-
18881
- if (value !== undefined) {
18882
- accum[key] = value;
18883
- }
18884
-
18885
- return accum;
18886
- }, {});
18887
- };
18888
-
18889
- /**
18890
- * Sets text track settings from an object of values.
18891
- *
18892
- * @param {Object} values
18893
- * An object with config values parsed from the DOM or localStorage.
18894
- */
18895
-
18896
-
18897
- TextTrackSettings.prototype.setValues = function setValues(values) {
18898
- var _this4 = this;
18899
-
18900
- each(selectConfigs, function (config, key) {
18901
- setSelectedOption(_this4.$(config.selector), values[key], config.parser);
18902
- });
18903
- };
18904
-
18905
- /**
18906
- * Sets all `<select>` elements to their default values.
18907
- */
18908
-
18909
-
18910
- TextTrackSettings.prototype.setDefaults = function setDefaults() {
18911
- var _this5 = this;
18912
-
18913
- each(selectConfigs, function (config) {
18914
- var index = config.hasOwnProperty('default') ? config.default : 0;
18915
-
18916
- _this5.$(config.selector).selectedIndex = index;
18917
- });
18918
- };
18919
-
18920
- /**
18921
- * Restore texttrack settings from localStorage
18922
- */
18923
-
18924
-
18925
- TextTrackSettings.prototype.restoreSettings = function restoreSettings() {
18926
- var values = void 0;
18927
-
18928
- try {
18929
- values = JSON.parse(window_1.localStorage.getItem(LOCAL_STORAGE_KEY));
18930
- } catch (err) {
18931
- log$1.warn(err);
18932
- }
18933
-
18934
- if (values) {
18935
- this.setValues(values);
18936
- }
18937
- };
18938
-
18939
- /**
18940
- * Save text track settings to localStorage
18941
- */
18942
-
18943
-
18944
- TextTrackSettings.prototype.saveSettings = function saveSettings() {
18945
- if (!this.options_.persistTextTrackSettings) {
18946
- return;
18947
- }
18948
-
18949
- var values = this.getValues();
18950
-
18951
- try {
18952
- if (Object.keys(values).length) {
18953
- window_1.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(values));
18954
- } else {
18955
- window_1.localStorage.removeItem(LOCAL_STORAGE_KEY);
18956
- }
18957
- } catch (err) {
18958
- log$1.warn(err);
18959
- }
18960
- };
18961
-
18962
- /**
18963
- * Update display of text track settings
18964
- */
18965
-
18966
-
18967
- TextTrackSettings.prototype.updateDisplay = function updateDisplay() {
18968
- var ttDisplay = this.player_.getChild('textTrackDisplay');
18969
-
18970
- if (ttDisplay) {
18971
- ttDisplay.updateDisplay();
18972
- }
18973
- };
18974
-
18975
- /**
18976
- * conditionally blur the element and refocus the captions button
18977
- *
18978
- * @private
18979
- */
18980
-
18981
-
18982
- TextTrackSettings.prototype.conditionalBlur_ = function conditionalBlur_() {
18983
- this.previouslyActiveEl_ = null;
18984
- this.off(document_1, 'keydown', this.handleKeyDown);
18985
-
18986
- var cb = this.player_.controlBar;
18987
- var subsCapsBtn = cb && cb.subsCapsButton;
18988
- var ccBtn = cb && cb.captionsButton;
18989
-
18990
- if (subsCapsBtn) {
18991
- subsCapsBtn.focus();
18992
- } else if (ccBtn) {
18993
- ccBtn.focus();
18994
- }
18995
- };
18996
-
18997
- return TextTrackSettings;
18998
- }(ModalDialog);
18999
-
19000
- Component.registerComponent('TextTrackSettings', TextTrackSettings);
19001
-
19002
- /**
19003
- * @file resize-manager.js
19004
- */
19005
-
19006
- /**
19007
- * A Resize Manager. It is in charge of triggering `playerresize` on the player in the right conditions.
19008
- *
19009
- * It'll either create an iframe and use a debounced resize handler on it or use the new {@link https://wicg.github.io/ResizeObserver/|ResizeObserver}.
19010
- *
19011
- * If the ResizeObserver is available natively, it will be used. A polyfill can be passed in as an option.
19012
- * If a `playerresize` event is not needed, the ResizeManager component can be removed from the player, see the example below.
19013
- * @example <caption>How to disable the resize manager</caption>
19014
- * const player = videojs('#vid', {
19015
- * resizeManager: false
19016
- * });
19017
- *
19018
- * @see {@link https://wicg.github.io/ResizeObserver/|ResizeObserver specification}
19019
- *
19020
- * @extends Component
19021
- */
19022
-
19023
- var ResizeManager = function (_Component) {
19024
- inherits(ResizeManager, _Component);
19025
-
19026
- /**
19027
- * Create the ResizeManager.
19028
- *
19029
- * @param {Object} player
19030
- * The `Player` that this class should be attached to.
19031
- *
19032
- * @param {Object} [options]
19033
- * The key/value store of ResizeManager options.
19034
- *
19035
- * @param {Object} [options.ResizeObserver]
19036
- * A polyfill for ResizeObserver can be passed in here.
19037
- * If this is set to null it will ignore the native ResizeObserver and fall back to the iframe fallback.
19038
- */
19039
- function ResizeManager(player, options) {
19040
- classCallCheck(this, ResizeManager);
19041
-
19042
- var RESIZE_OBSERVER_AVAILABLE = options.ResizeObserver || window_1.ResizeObserver;
19043
-
19044
- // if `null` was passed, we want to disable the ResizeObserver
19045
- if (options.ResizeObserver === null) {
19046
- RESIZE_OBSERVER_AVAILABLE = false;
19047
- }
19048
-
19049
- // Only create an element when ResizeObserver isn't available
19050
- var options_ = mergeOptions({ createEl: !RESIZE_OBSERVER_AVAILABLE }, options);
19051
-
19052
- var _this = possibleConstructorReturn(this, _Component.call(this, player, options_));
19053
-
19054
- _this.ResizeObserver = options.ResizeObserver || window_1.ResizeObserver;
19055
- _this.loadListener_ = null;
19056
- _this.resizeObserver_ = null;
19057
- _this.debouncedHandler_ = debounce(function () {
19058
- _this.resizeHandler();
19059
- }, 100, false, player);
19060
-
19061
- if (RESIZE_OBSERVER_AVAILABLE) {
19062
- _this.resizeObserver_ = new _this.ResizeObserver(_this.debouncedHandler_);
19063
- _this.resizeObserver_.observe(player.el());
19064
- } else {
19065
- _this.loadListener_ = function () {
19066
- if (_this.el_.contentWindow) {
19067
- on(_this.el_.contentWindow, 'resize', _this.debouncedHandler_);
19068
- }
19069
- _this.off('load', _this.loadListener_);
19070
- };
19071
-
19072
- _this.on('load', _this.loadListener_);
19073
- }
19074
- return _this;
19075
- }
19076
-
19077
- ResizeManager.prototype.createEl = function createEl() {
19078
- return _Component.prototype.createEl.call(this, 'iframe', {
19079
- className: 'vjs-resize-manager'
19080
- });
19081
- };
19082
-
19083
- /**
19084
- * Called when a resize is triggered on the iframe or a resize is observed via the ResizeObserver
19085
- *
19086
- * @fires Player#playerresize
19087
- */
19088
-
19089
-
19090
- ResizeManager.prototype.resizeHandler = function resizeHandler() {
19091
- /**
19092
- * Called when the player size has changed
19093
- *
19094
- * @event Player#playerresize
19095
- * @type {EventTarget~Event}
19096
- */
19097
- this.player_.trigger('playerresize');
19098
- };
19099
-
19100
- ResizeManager.prototype.dispose = function dispose() {
19101
- if (this.resizeObserver_) {
19102
- if (this.player_.el()) {
19103
- this.resizeObserver_.unobserve(this.player_.el());
19104
- }
19105
- this.resizeObserver_.disconnect();
19106
- }
19107
-
19108
- if (this.el_ && this.el_.contentWindow) {
19109
- off(this.el_.contentWindow, 'resize', this.debouncedHandler_);
19110
- }
19111
-
19112
- if (this.loadListener_) {
19113
- this.off('load', this.loadListener_);
19114
- }
19115
-
19116
- this.ResizeObserver = null;
19117
- this.resizeObserver = null;
19118
- this.debouncedHandler_ = null;
19119
- this.loadListener_ = null;
19120
- };
19121
-
19122
- return ResizeManager;
19123
- }(Component);
19124
-
19125
- Component.registerComponent('ResizeManager', ResizeManager);
19126
-
19127
- /**
19128
- * This function is used to fire a sourceset when there is something
19129
- * similar to `mediaEl.load()` being called. It will try to find the source via
19130
- * the `src` attribute and then the `<source>` elements. It will then fire `sourceset`
19131
- * with the source that was found or empty string if we cannot know. If it cannot
19132
- * find a source then `sourceset` will not be fired.
19133
- *
19134
- * @param {Html5} tech
19135
- * The tech object that sourceset was setup on
19136
- *
19137
- * @return {boolean}
19138
- * returns false if the sourceset was not fired and true otherwise.
19139
- */
19140
- var sourcesetLoad = function sourcesetLoad(tech) {
19141
- var el = tech.el();
19142
-
19143
- // if `el.src` is set, that source will be loaded.
19144
- if (el.hasAttribute('src')) {
19145
- tech.triggerSourceset(el.src);
19146
- return true;
19147
- }
19148
-
19149
- /**
19150
- * Since there isn't a src property on the media element, source elements will be used for
19151
- * implementing the source selection algorithm. This happens asynchronously and
19152
- * for most cases were there is more than one source we cannot tell what source will
19153
- * be loaded, without re-implementing the source selection algorithm. At this time we are not
19154
- * going to do that. There are three special cases that we do handle here though:
19155
- *
19156
- * 1. If there are no sources, do not fire `sourceset`.
19157
- * 2. If there is only one `<source>` with a `src` property/attribute that is our `src`
19158
- * 3. If there is more than one `<source>` but all of them have the same `src` url.
19159
- * That will be our src.
19160
- */
19161
- var sources = tech.$$('source');
19162
- var srcUrls = [];
19163
- var src = '';
19164
-
19165
- // if there are no sources, do not fire sourceset
19166
- if (!sources.length) {
19167
- return false;
19168
- }
19169
-
19170
- // only count valid/non-duplicate source elements
19171
- for (var i = 0; i < sources.length; i++) {
19172
- var url = sources[i].src;
19173
-
19174
- if (url && srcUrls.indexOf(url) === -1) {
19175
- srcUrls.push(url);
19176
- }
19177
- }
19178
-
19179
- // there were no valid sources
19180
- if (!srcUrls.length) {
19181
- return false;
19182
- }
19183
-
19184
- // there is only one valid source element url
19185
- // use that
19186
- if (srcUrls.length === 1) {
19187
- src = srcUrls[0];
19188
- }
19189
-
19190
- tech.triggerSourceset(src);
19191
- return true;
19192
- };
19193
-
19194
- /**
19195
- * our implementation of an `innerHTML` descriptor for browsers
19196
- * that do not have one.
19197
- */
19198
- var innerHTMLDescriptorPolyfill = Object.defineProperty({}, 'innerHTML', {
19199
- get: function get() {
19200
- return this.cloneNode(true).innerHTML;
19201
- },
19202
- set: function set(v) {
19203
- // make a dummy node to use innerHTML on
19204
- var dummy = document_1.createElement(this.nodeName.toLowerCase());
19205
-
19206
- // set innerHTML to the value provided
19207
- dummy.innerHTML = v;
19208
-
19209
- // make a document fragment to hold the nodes from dummy
19210
- var docFrag = document_1.createDocumentFragment();
19211
-
19212
- // copy all of the nodes created by the innerHTML on dummy
19213
- // to the document fragment
19214
- while (dummy.childNodes.length) {
19215
- docFrag.appendChild(dummy.childNodes[0]);
19216
- }
19217
-
19218
- // remove content
19219
- this.innerText = '';
19220
-
19221
- // now we add all of that html in one by appending the
19222
- // document fragment. This is how innerHTML does it.
19223
- window_1.Element.prototype.appendChild.call(this, docFrag);
19224
-
19225
- // then return the result that innerHTML's setter would
19226
- return this.innerHTML;
19227
- }
19228
- });
19229
-
19230
- /**
19231
- * Get a property descriptor given a list of priorities and the
19232
- * property to get.
19233
- */
19234
- var getDescriptor = function getDescriptor(priority, prop) {
19235
- var descriptor = {};
19236
-
19237
- for (var i = 0; i < priority.length; i++) {
19238
- descriptor = Object.getOwnPropertyDescriptor(priority[i], prop);
19239
-
19240
- if (descriptor && descriptor.set && descriptor.get) {
19241
- break;
19242
- }
19243
- }
19244
-
19245
- descriptor.enumerable = true;
19246
- descriptor.configurable = true;
19247
-
19248
- return descriptor;
19249
- };
19250
-
19251
- var getInnerHTMLDescriptor = function getInnerHTMLDescriptor(tech) {
19252
- return getDescriptor([tech.el(), window_1.HTMLMediaElement.prototype, window_1.Element.prototype, innerHTMLDescriptorPolyfill], 'innerHTML');
19253
- };
19254
-
19255
- /**
19256
- * Patches browser internal functions so that we can tell synchronously
19257
- * if a `<source>` was appended to the media element. For some reason this
19258
- * causes a `sourceset` if the the media element is ready and has no source.
19259
- * This happens when:
19260
- * - The page has just loaded and the media element does not have a source.
19261
- * - The media element was emptied of all sources, then `load()` was called.
19262
- *
19263
- * It does this by patching the following functions/properties when they are supported:
19264
- *
19265
- * - `append()` - can be used to add a `<source>` element to the media element
19266
- * - `appendChild()` - can be used to add a `<source>` element to the media element
19267
- * - `insertAdjacentHTML()` - can be used to add a `<source>` element to the media element
19268
- * - `innerHTML` - can be used to add a `<source>` element to the media element
19269
- *
19270
- * @param {Html5} tech
19271
- * The tech object that sourceset is being setup on.
19272
- */
19273
- var firstSourceWatch = function firstSourceWatch(tech) {
19274
- var el = tech.el();
19275
-
19276
- // make sure firstSourceWatch isn't setup twice.
19277
- if (el.resetSourceWatch_) {
19278
- return;
19279
- }
19280
-
19281
- var old = {};
19282
- var innerDescriptor = getInnerHTMLDescriptor(tech);
19283
- var appendWrapper = function appendWrapper(appendFn) {
19284
- return function () {
19285
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
19286
- args[_key] = arguments[_key];
19287
- }
19288
-
19289
- var retval = appendFn.apply(el, args);
19290
-
19291
- sourcesetLoad(tech);
19292
-
19293
- return retval;
19294
- };
19295
- };
19296
-
19297
- ['append', 'appendChild', 'insertAdjacentHTML'].forEach(function (k) {
19298
- if (!el[k]) {
19299
- return;
19300
- }
19301
-
19302
- // store the old function
19303
- old[k] = el[k];
19304
-
19305
- // call the old function with a sourceset if a source
19306
- // was loaded
19307
- el[k] = appendWrapper(old[k]);
19308
- });
19309
-
19310
- Object.defineProperty(el, 'innerHTML', mergeOptions(innerDescriptor, {
19311
- set: appendWrapper(innerDescriptor.set)
19312
- }));
19313
-
19314
- el.resetSourceWatch_ = function () {
19315
- el.resetSourceWatch_ = null;
19316
- Object.keys(old).forEach(function (k) {
19317
- el[k] = old[k];
19318
- });
19319
-
19320
- Object.defineProperty(el, 'innerHTML', innerDescriptor);
19321
- };
19322
-
19323
- // on the first sourceset, we need to revert our changes
19324
- tech.one('sourceset', el.resetSourceWatch_);
19325
- };
19326
-
19327
- /**
19328
- * our implementation of a `src` descriptor for browsers
19329
- * that do not have one.
19330
- */
19331
- var srcDescriptorPolyfill = Object.defineProperty({}, 'src', {
19332
- get: function get() {
19333
- if (this.hasAttribute('src')) {
19334
- return getAbsoluteURL(window_1.Element.prototype.getAttribute.call(this, 'src'));
19335
- }
19336
-
19337
- return '';
19338
- },
19339
- set: function set(v) {
19340
- window_1.Element.prototype.setAttribute.call(this, 'src', v);
19341
-
19342
- return v;
19343
- }
19344
- });
19345
-
19346
- var getSrcDescriptor = function getSrcDescriptor(tech) {
19347
- return getDescriptor([tech.el(), window_1.HTMLMediaElement.prototype, srcDescriptorPolyfill], 'src');
19348
- };
19349
-
19350
- /**
19351
- * setup `sourceset` handling on the `Html5` tech. This function
19352
- * patches the following element properties/functions:
19353
- *
19354
- * - `src` - to determine when `src` is set
19355
- * - `setAttribute()` - to determine when `src` is set
19356
- * - `load()` - this re-triggers the source selection algorithm, and can
19357
- * cause a sourceset.
19358
- *
19359
- * If there is no source when we are adding `sourceset` support or during a `load()`
19360
- * we also patch the functions listed in `firstSourceWatch`.
19361
- *
19362
- * @param {Html5} tech
19363
- * The tech to patch
19364
- */
19365
- var setupSourceset = function setupSourceset(tech) {
19366
- if (!tech.featuresSourceset) {
19367
- return;
19368
- }
19369
-
19370
- var el = tech.el();
19371
-
19372
- // make sure sourceset isn't setup twice.
19373
- if (el.resetSourceset_) {
19374
- return;
19375
- }
19376
-
19377
- var srcDescriptor = getSrcDescriptor(tech);
19378
- var oldSetAttribute = el.setAttribute;
19379
- var oldLoad = el.load;
19380
-
19381
- Object.defineProperty(el, 'src', mergeOptions(srcDescriptor, {
19382
- set: function set(v) {
19383
- var retval = srcDescriptor.set.call(el, v);
19384
-
19385
- // we use the getter here to get the actual value set on src
19386
- tech.triggerSourceset(el.src);
19387
-
19388
- return retval;
19389
- }
19390
- }));
19391
-
19392
- el.setAttribute = function (n, v) {
19393
- var retval = oldSetAttribute.call(el, n, v);
19394
-
19395
- if (/src/i.test(n)) {
19396
- tech.triggerSourceset(el.src);
19397
- }
19398
-
19399
- return retval;
19400
- };
19401
-
19402
- el.load = function () {
19403
- var retval = oldLoad.call(el);
19404
-
19405
- // if load was called, but there was no source to fire
19406
- // sourceset on. We have to watch for a source append
19407
- // as that can trigger a `sourceset` when the media element
19408
- // has no source
19409
- if (!sourcesetLoad(tech)) {
19410
- tech.triggerSourceset('');
19411
- firstSourceWatch(tech);
19412
- }
19413
-
19414
- return retval;
19415
- };
19416
-
19417
- if (el.currentSrc) {
19418
- tech.triggerSourceset(el.currentSrc);
19419
- } else if (!sourcesetLoad(tech)) {
19420
- firstSourceWatch(tech);
19421
- }
19422
-
19423
- el.resetSourceset_ = function () {
19424
- el.resetSourceset_ = null;
19425
- el.load = oldLoad;
19426
- el.setAttribute = oldSetAttribute;
19427
- Object.defineProperty(el, 'src', srcDescriptor);
19428
- if (el.resetSourceWatch_) {
19429
- el.resetSourceWatch_();
19430
- }
19431
- };
19432
- };
19433
-
19434
- var _templateObject$1 = taggedTemplateLiteralLoose(['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.'], ['Text Tracks are being loaded from another origin but the crossorigin attribute isn\'t used.\n This may prevent text tracks from loading.']);
19435
-
19436
- /**
19437
- * HTML5 Media Controller - Wrapper for HTML5 Media API
19438
- *
19439
- * @mixes Tech~SourceHandlerAdditions
19440
- * @extends Tech
19441
- */
19442
-
19443
- var Html5 = function (_Tech) {
19444
- inherits(Html5, _Tech);
19445
-
19446
- /**
19447
- * Create an instance of this Tech.
19448
- *
19449
- * @param {Object} [options]
19450
- * The key/value store of player options.
19451
- *
19452
- * @param {Component~ReadyCallback} ready
19453
- * Callback function to call when the `HTML5` Tech is ready.
19454
- */
19455
- function Html5(options, ready) {
19456
- classCallCheck(this, Html5);
19457
-
19458
- var _this = possibleConstructorReturn(this, _Tech.call(this, options, ready));
19459
-
19460
- var source = options.source;
19461
- var crossoriginTracks = false;
19462
-
19463
- // Set the source if one is provided
19464
- // 1) Check if the source is new (if not, we want to keep the original so playback isn't interrupted)
19465
- // 2) Check to see if the network state of the tag was failed at init, and if so, reset the source
19466
- // anyway so the error gets fired.
19467
- if (source && (_this.el_.currentSrc !== source.src || options.tag && options.tag.initNetworkState_ === 3)) {
19468
- _this.setSource(source);
19469
- } else {
19470
- _this.handleLateInit_(_this.el_);
19471
- }
19472
-
19473
- // setup sourceset after late sourceset/init
19474
- if (options.enableSourceset) {
19475
- _this.setupSourcesetHandling_();
19476
- }
19477
-
19478
- if (_this.el_.hasChildNodes()) {
19479
-
19480
- var nodes = _this.el_.childNodes;
19481
- var nodesLength = nodes.length;
19482
- var removeNodes = [];
19483
-
19484
- while (nodesLength--) {
19485
- var node = nodes[nodesLength];
19486
- var nodeName = node.nodeName.toLowerCase();
19487
-
19488
- if (nodeName === 'track') {
19489
- if (!_this.featuresNativeTextTracks) {
19490
- // Empty video tag tracks so the built-in player doesn't use them also.
19491
- // This may not be fast enough to stop HTML5 browsers from reading the tags
19492
- // so we'll need to turn off any default tracks if we're manually doing
19493
- // captions and subtitles. videoElement.textTracks
19494
- removeNodes.push(node);
19495
- } else {
19496
- // store HTMLTrackElement and TextTrack to remote list
19497
- _this.remoteTextTrackEls().addTrackElement_(node);
19498
- _this.remoteTextTracks().addTrack(node.track);
19499
- _this.textTracks().addTrack(node.track);
19500
- if (!crossoriginTracks && !_this.el_.hasAttribute('crossorigin') && isCrossOrigin(node.src)) {
19501
- crossoriginTracks = true;
19502
- }
19503
- }
19504
- }
19505
- }
19506
-
19507
- for (var i = 0; i < removeNodes.length; i++) {
19508
- _this.el_.removeChild(removeNodes[i]);
19509
- }
19510
- }
19511
-
19512
- _this.proxyNativeTracks_();
19513
- if (_this.featuresNativeTextTracks && crossoriginTracks) {
19514
- log$1.warn(tsml(_templateObject$1));
19515
- }
19516
-
19517
- // prevent iOS Safari from disabling metadata text tracks during native playback
19518
- _this.restoreMetadataTracksInIOSNativePlayer_();
19519
-
19520
- // Determine if native controls should be used
19521
- // Our goal should be to get the custom controls on mobile solid everywhere
19522
- // so we can remove this all together. Right now this will block custom
19523
- // controls on touch enabled laptops like the Chrome Pixel
19524
- if ((TOUCH_ENABLED || IS_IPHONE || IS_NATIVE_ANDROID) && options.nativeControlsForTouch === true) {
19525
- _this.setControls(true);
19526
- }
19527
-
19528
- // on iOS, we want to proxy `webkitbeginfullscreen` and `webkitendfullscreen`
19529
- // into a `fullscreenchange` event
19530
- _this.proxyWebkitFullscreen_();
19531
-
19532
- _this.triggerReady();
19533
- return _this;
19534
- }
19535
-
19536
- /**
19537
- * Dispose of `HTML5` media element and remove all tracks.
19538
- */
19539
-
19540
-
19541
- Html5.prototype.dispose = function dispose() {
19542
- if (this.el_ && this.el_.resetSourceset_) {
19543
- this.el_.resetSourceset_();
19544
- }
19545
- Html5.disposeMediaElement(this.el_);
19546
- this.options_ = null;
19547
-
19548
- // tech will handle clearing of the emulated track list
19549
- _Tech.prototype.dispose.call(this);
19550
- };
19551
-
19552
- /**
19553
- * Modify the media element so that we can detect when
19554
- * the source is changed. Fires `sourceset` just after the source has changed
19555
- */
19556
-
19557
-
19558
- Html5.prototype.setupSourcesetHandling_ = function setupSourcesetHandling_() {
19559
- setupSourceset(this);
19560
- };
19561
-
19562
- /**
19563
- * When a captions track is enabled in the iOS Safari native player, all other
19564
- * tracks are disabled (including metadata tracks), which nulls all of their
19565
- * associated cue points. This will restore metadata tracks to their pre-fullscreen
19566
- * state in those cases so that cue points are not needlessly lost.
19567
- *
19568
- * @private
19569
- */
19570
-
19571
-
19572
- Html5.prototype.restoreMetadataTracksInIOSNativePlayer_ = function restoreMetadataTracksInIOSNativePlayer_() {
19573
- var textTracks = this.textTracks();
19574
- var metadataTracksPreFullscreenState = void 0;
19575
-
19576
- // captures a snapshot of every metadata track's current state
19577
- var takeMetadataTrackSnapshot = function takeMetadataTrackSnapshot() {
19578
- metadataTracksPreFullscreenState = [];
19579
-
19580
- for (var i = 0; i < textTracks.length; i++) {
19581
- var track = textTracks[i];
19582
-
19583
- if (track.kind === 'metadata') {
19584
- metadataTracksPreFullscreenState.push({
19585
- track: track,
19586
- storedMode: track.mode
19587
- });
19588
- }
19589
- }
19590
- };
19591
-
19592
- // snapshot each metadata track's initial state, and update the snapshot
19593
- // each time there is a track 'change' event
19594
- takeMetadataTrackSnapshot();
19595
- textTracks.addEventListener('change', takeMetadataTrackSnapshot);
19596
-
19597
- this.on('dispose', function () {
19598
- return textTracks.removeEventListener('change', takeMetadataTrackSnapshot);
19599
- });
19600
-
19601
- var restoreTrackMode = function restoreTrackMode() {
19602
- for (var i = 0; i < metadataTracksPreFullscreenState.length; i++) {
19603
- var storedTrack = metadataTracksPreFullscreenState[i];
19604
-
19605
- if (storedTrack.track.mode === 'disabled' && storedTrack.track.mode !== storedTrack.storedMode) {
19606
- storedTrack.track.mode = storedTrack.storedMode;
19607
- }
19608
- }
19609
- // we only want this handler to be executed on the first 'change' event
19610
- textTracks.removeEventListener('change', restoreTrackMode);
19611
- };
19612
-
19613
- // when we enter fullscreen playback, stop updating the snapshot and
19614
- // restore all track modes to their pre-fullscreen state
19615
- this.on('webkitbeginfullscreen', function () {
19616
- textTracks.removeEventListener('change', takeMetadataTrackSnapshot);
19617
-
19618
- // remove the listener before adding it just in case it wasn't previously removed
19619
- textTracks.removeEventListener('change', restoreTrackMode);
19620
- textTracks.addEventListener('change', restoreTrackMode);
19621
- });
19622
-
19623
- // start updating the snapshot again after leaving fullscreen
19624
- this.on('webkitendfullscreen', function () {
19625
- // remove the listener before adding it just in case it wasn't previously removed
19626
- textTracks.removeEventListener('change', takeMetadataTrackSnapshot);
19627
- textTracks.addEventListener('change', takeMetadataTrackSnapshot);
19628
-
19629
- // remove the restoreTrackMode handler in case it wasn't triggered during fullscreen playback
19630
- textTracks.removeEventListener('change', restoreTrackMode);
19631
- });
19632
- };
19633
-
19634
- /**
19635
- * Attempt to force override of tracks for the given type
19636
- *
19637
- * @param {String} type - Track type to override, possible values include 'Audio',
19638
- * 'Video', and 'Text'.
19639
- * @param {Boolean} override - If set to true native audio/video will be overridden,
19640
- * otherwise native audio/video will potentially be used.
19641
- * @private
19642
- */
19643
-
19644
-
19645
- Html5.prototype.overrideNative_ = function overrideNative_(type, override) {
19646
- var _this2 = this;
19647
-
19648
- // If there is no behavioral change don't add/remove listeners
19649
- if (override !== this['featuresNative' + type + 'Tracks']) {
19650
- return;
19651
- }
19652
-
19653
- var lowerCaseType = type.toLowerCase();
19654
-
19655
- if (this[lowerCaseType + 'TracksListeners_']) {
19656
- Object.keys(this[lowerCaseType + 'TracksListeners_']).forEach(function (eventName) {
19657
- var elTracks = _this2.el()[lowerCaseType + 'Tracks'];
19658
-
19659
- elTracks.removeEventListener(eventName, _this2[lowerCaseType + 'TracksListeners_'][eventName]);
19660
- });
19661
- }
19662
-
19663
- this['featuresNative' + type + 'Tracks'] = !override;
19664
- this[lowerCaseType + 'TracksListeners_'] = null;
19665
-
19666
- this.proxyNativeTracksForType_(lowerCaseType);
19667
- };
19668
-
19669
- /**
19670
- * Attempt to force override of native audio tracks.
19671
- *
19672
- * @param {Boolean} override - If set to true native audio will be overridden,
19673
- * otherwise native audio will potentially be used.
19674
- */
19675
-
19676
-
19677
- Html5.prototype.overrideNativeAudioTracks = function overrideNativeAudioTracks(override) {
19678
- this.overrideNative_('Audio', override);
19679
- };
19680
-
19681
- /**
19682
- * Attempt to force override of native video tracks.
19683
- *
19684
- * @param {Boolean} override - If set to true native video will be overridden,
19685
- * otherwise native video will potentially be used.
19686
- */
19687
-
19688
-
19689
- Html5.prototype.overrideNativeVideoTracks = function overrideNativeVideoTracks(override) {
19690
- this.overrideNative_('Video', override);
19691
- };
19692
-
19693
- /**
19694
- * Proxy native track list events for the given type to our track
19695
- * lists if the browser we are playing in supports that type of track list.
19696
- *
19697
- * @param {string} name - Track type; values include 'audio', 'video', and 'text'
19698
- * @private
19699
- */
19700
-
19701
-
19702
- Html5.prototype.proxyNativeTracksForType_ = function proxyNativeTracksForType_(name) {
19703
- var _this3 = this;
19704
-
19705
- var props = NORMAL[name];
19706
- var elTracks = this.el()[props.getterName];
19707
- var techTracks = this[props.getterName]();
19708
-
19709
- if (!this['featuresNative' + props.capitalName + 'Tracks'] || !elTracks || !elTracks.addEventListener) {
19710
- return;
19711
- }
19712
- var listeners = {
19713
- change: function change(e) {
19714
- techTracks.trigger({
19715
- type: 'change',
19716
- target: techTracks,
19717
- currentTarget: techTracks,
19718
- srcElement: techTracks
19719
- });
19720
- },
19721
- addtrack: function addtrack(e) {
19722
- techTracks.addTrack(e.track);
19723
- },
19724
- removetrack: function removetrack(e) {
19725
- techTracks.removeTrack(e.track);
19726
- }
19727
- };
19728
- var removeOldTracks = function removeOldTracks() {
19729
- var removeTracks = [];
19730
-
19731
- for (var i = 0; i < techTracks.length; i++) {
19732
- var found = false;
19733
-
19734
- for (var j = 0; j < elTracks.length; j++) {
19735
- if (elTracks[j] === techTracks[i]) {
19736
- found = true;
19737
- break;
19738
- }
19739
- }
19740
-
19741
- if (!found) {
19742
- removeTracks.push(techTracks[i]);
19743
- }
19744
- }
19745
-
19746
- while (removeTracks.length) {
19747
- techTracks.removeTrack(removeTracks.shift());
19748
- }
19749
- };
19750
-
19751
- this[props.getterName + 'Listeners_'] = listeners;
19752
-
19753
- Object.keys(listeners).forEach(function (eventName) {
19754
- var listener = listeners[eventName];
19755
-
19756
- elTracks.addEventListener(eventName, listener);
19757
- _this3.on('dispose', function (e) {
19758
- return elTracks.removeEventListener(eventName, listener);
19759
- });
19760
- });
19761
-
19762
- // Remove (native) tracks that are not used anymore
19763
- this.on('loadstart', removeOldTracks);
19764
- this.on('dispose', function (e) {
19765
- return _this3.off('loadstart', removeOldTracks);
19766
- });
19767
- };
19768
-
19769
- /**
19770
- * Proxy all native track list events to our track lists if the browser we are playing
19771
- * in supports that type of track list.
19772
- *
19773
- * @private
19774
- */
19775
-
19776
-
19777
- Html5.prototype.proxyNativeTracks_ = function proxyNativeTracks_() {
19778
- var _this4 = this;
19779
-
19780
- NORMAL.names.forEach(function (name) {
19781
- _this4.proxyNativeTracksForType_(name);
19782
- });
19783
- };
19784
-
19785
- /**
19786
- * Create the `Html5` Tech's DOM element.
19787
- *
19788
- * @return {Element}
19789
- * The element that gets created.
19790
- */
19791
-
19792
-
19793
- Html5.prototype.createEl = function createEl$$1() {
19794
- var el = this.options_.tag;
19795
-
19796
- // Check if this browser supports moving the element into the box.
19797
- // On the iPhone video will break if you move the element,
19798
- // So we have to create a brand new element.
19799
- // If we ingested the player div, we do not need to move the media element.
19800
- if (!el || !(this.options_.playerElIngest || this.movingMediaElementInDOM)) {
19801
-
19802
- // If the original tag is still there, clone and remove it.
19803
- if (el) {
19804
- var clone = el.cloneNode(true);
19805
-
19806
- if (el.parentNode) {
19807
- el.parentNode.insertBefore(clone, el);
19808
- }
19809
- Html5.disposeMediaElement(el);
19810
- el = clone;
19811
- } else {
19812
- el = document_1.createElement('video');
19813
-
19814
- // determine if native controls should be used
19815
- var tagAttributes = this.options_.tag && getAttributes(this.options_.tag);
19816
- var attributes = mergeOptions({}, tagAttributes);
19817
-
19818
- if (!TOUCH_ENABLED || this.options_.nativeControlsForTouch !== true) {
19819
- delete attributes.controls;
19820
- }
19821
-
19822
- setAttributes(el, assign(attributes, {
19823
- id: this.options_.techId,
19824
- class: 'vjs-tech'
19825
- }));
19826
- }
19827
-
19828
- el.playerId = this.options_.playerId;
19829
- }
19830
-
19831
- if (typeof this.options_.preload !== 'undefined') {
19832
- setAttribute(el, 'preload', this.options_.preload);
19833
- }
19834
-
19835
- // Update specific tag settings, in case they were overridden
19836
- // `autoplay` has to be *last* so that `muted` and `playsinline` are present
19837
- // when iOS/Safari or other browsers attempt to autoplay.
19838
- var settingsAttrs = ['loop', 'muted', 'playsinline', 'autoplay'];
19839
-
19840
- for (var i = 0; i < settingsAttrs.length; i++) {
19841
- var attr = settingsAttrs[i];
19842
- var value = this.options_[attr];
19843
-
19844
- if (typeof value !== 'undefined') {
19845
- if (value) {
19846
- setAttribute(el, attr, attr);
19847
- } else {
19848
- removeAttribute(el, attr);
19849
- }
19850
- el[attr] = value;
19851
- }
19852
- }
19853
-
19854
- return el;
19855
- };
19856
-
19857
- /**
19858
- * This will be triggered if the loadstart event has already fired, before videojs was
19859
- * ready. Two known examples of when this can happen are:
19860
- * 1. If we're loading the playback object after it has started loading
19861
- * 2. The media is already playing the (often with autoplay on) then
19862
- *
19863
- * This function will fire another loadstart so that videojs can catchup.
19864
- *
19865
- * @fires Tech#loadstart
19866
- *
19867
- * @return {undefined}
19868
- * returns nothing.
19869
- */
19870
-
19871
-
19872
- Html5.prototype.handleLateInit_ = function handleLateInit_(el) {
19873
- if (el.networkState === 0 || el.networkState === 3) {
19874
- // The video element hasn't started loading the source yet
19875
- // or didn't find a source
19876
- return;
19877
- }
19878
-
19879
- if (el.readyState === 0) {
19880
- // NetworkState is set synchronously BUT loadstart is fired at the
19881
- // end of the current stack, usually before setInterval(fn, 0).
19882
- // So at this point we know loadstart may have already fired or is
19883
- // about to fire, and either way the player hasn't seen it yet.
19884
- // We don't want to fire loadstart prematurely here and cause a
19885
- // double loadstart so we'll wait and see if it happens between now
19886
- // and the next loop, and fire it if not.
19887
- // HOWEVER, we also want to make sure it fires before loadedmetadata
19888
- // which could also happen between now and the next loop, so we'll
19889
- // watch for that also.
19890
- var loadstartFired = false;
19891
- var setLoadstartFired = function setLoadstartFired() {
19892
- loadstartFired = true;
19893
- };
19894
-
19895
- this.on('loadstart', setLoadstartFired);
19896
-
19897
- var triggerLoadstart = function triggerLoadstart() {
19898
- // We did miss the original loadstart. Make sure the player
19899
- // sees loadstart before loadedmetadata
19900
- if (!loadstartFired) {
19901
- this.trigger('loadstart');
19902
- }
19903
- };
19904
-
19905
- this.on('loadedmetadata', triggerLoadstart);
19906
-
19907
- this.ready(function () {
19908
- this.off('loadstart', setLoadstartFired);
19909
- this.off('loadedmetadata', triggerLoadstart);
19910
-
19911
- if (!loadstartFired) {
19912
- // We did miss the original native loadstart. Fire it now.
19913
- this.trigger('loadstart');
19914
- }
19915
- });
19916
-
19917
- return;
19918
- }
19919
-
19920
- // From here on we know that loadstart already fired and we missed it.
19921
- // The other readyState events aren't as much of a problem if we double
19922
- // them, so not going to go to as much trouble as loadstart to prevent
19923
- // that unless we find reason to.
19924
- var eventsToTrigger = ['loadstart'];
19925
-
19926
- // loadedmetadata: newly equal to HAVE_METADATA (1) or greater
19927
- eventsToTrigger.push('loadedmetadata');
19928
-
19929
- // loadeddata: newly increased to HAVE_CURRENT_DATA (2) or greater
19930
- if (el.readyState >= 2) {
19931
- eventsToTrigger.push('loadeddata');
19932
- }
19933
-
19934
- // canplay: newly increased to HAVE_FUTURE_DATA (3) or greater
19935
- if (el.readyState >= 3) {
19936
- eventsToTrigger.push('canplay');
19937
- }
19938
-
19939
- // canplaythrough: newly equal to HAVE_ENOUGH_DATA (4)
19940
- if (el.readyState >= 4) {
19941
- eventsToTrigger.push('canplaythrough');
19942
- }
19943
-
19944
- // We still need to give the player time to add event listeners
19945
- this.ready(function () {
19946
- eventsToTrigger.forEach(function (type) {
19947
- this.trigger(type);
19948
- }, this);
19949
- });
19950
- };
19951
-
19952
- /**
19953
- * Set current time for the `HTML5` tech.
19954
- *
19955
- * @param {number} seconds
19956
- * Set the current time of the media to this.
19957
- */
19958
-
19959
-
19960
- Html5.prototype.setCurrentTime = function setCurrentTime(seconds) {
19961
- try {
19962
- this.el_.currentTime = seconds;
19963
- } catch (e) {
19964
- log$1(e, 'Video is not ready. (Video.js)');
19965
- // this.warning(VideoJS.warnings.videoNotReady);
19966
- }
19967
- };
19968
-
19969
- /**
19970
- * Get the current duration of the HTML5 media element.
19971
- *
19972
- * @return {number}
19973
- * The duration of the media or 0 if there is no duration.
19974
- */
19975
-
19976
-
19977
- Html5.prototype.duration = function duration() {
19978
- var _this5 = this;
19979
-
19980
- // Android Chrome will report duration as Infinity for VOD HLS until after
19981
- // playback has started, which triggers the live display erroneously.
19982
- // Return NaN if playback has not started and trigger a durationupdate once
19983
- // the duration can be reliably known.
19984
- if (this.el_.duration === Infinity && IS_ANDROID && IS_CHROME && this.el_.currentTime === 0) {
19985
- // Wait for the first `timeupdate` with currentTime > 0 - there may be
19986
- // several with 0
19987
- var checkProgress = function checkProgress() {
19988
- if (_this5.el_.currentTime > 0) {
19989
- // Trigger durationchange for genuinely live video
19990
- if (_this5.el_.duration === Infinity) {
19991
- _this5.trigger('durationchange');
19992
- }
19993
- _this5.off('timeupdate', checkProgress);
19994
- }
19995
- };
19996
-
19997
- this.on('timeupdate', checkProgress);
19998
- return NaN;
19999
- }
20000
- return this.el_.duration || NaN;
20001
- };
20002
-
20003
- /**
20004
- * Get the current width of the HTML5 media element.
20005
- *
20006
- * @return {number}
20007
- * The width of the HTML5 media element.
20008
- */
20009
-
20010
-
20011
- Html5.prototype.width = function width() {
20012
- return this.el_.offsetWidth;
20013
- };
20014
-
20015
- /**
20016
- * Get the current height of the HTML5 media element.
20017
- *
20018
- * @return {number}
20019
- * The height of the HTML5 media element.
20020
- */
20021
-
20022
-
20023
- Html5.prototype.height = function height() {
20024
- return this.el_.offsetHeight;
20025
- };
20026
-
20027
- /**
20028
- * Proxy iOS `webkitbeginfullscreen` and `webkitendfullscreen` into
20029
- * `fullscreenchange` event.
20030
- *
20031
- * @private
20032
- * @fires fullscreenchange
20033
- * @listens webkitendfullscreen
20034
- * @listens webkitbeginfullscreen
20035
- * @listens webkitbeginfullscreen
20036
- */
20037
-
20038
-
20039
- Html5.prototype.proxyWebkitFullscreen_ = function proxyWebkitFullscreen_() {
20040
- var _this6 = this;
20041
-
20042
- if (!('webkitDisplayingFullscreen' in this.el_)) {
20043
- return;
20044
- }
20045
-
20046
- var endFn = function endFn() {
20047
- this.trigger('fullscreenchange', { isFullscreen: false });
20048
- };
20049
-
20050
- var beginFn = function beginFn() {
20051
- if ('webkitPresentationMode' in this.el_ && this.el_.webkitPresentationMode !== 'picture-in-picture') {
20052
- this.one('webkitendfullscreen', endFn);
20053
-
20054
- this.trigger('fullscreenchange', { isFullscreen: true });
20055
- }
20056
- };
20057
-
20058
- this.on('webkitbeginfullscreen', beginFn);
20059
- this.on('dispose', function () {
20060
- _this6.off('webkitbeginfullscreen', beginFn);
20061
- _this6.off('webkitendfullscreen', endFn);
20062
- });
20063
- };
20064
-
20065
- /**
20066
- * Check if fullscreen is supported on the current playback device.
20067
- *
20068
- * @return {boolean}
20069
- * - True if fullscreen is supported.
20070
- * - False if fullscreen is not supported.
20071
- */
20072
-
20073
-
20074
- Html5.prototype.supportsFullScreen = function supportsFullScreen() {
20075
- if (typeof this.el_.webkitEnterFullScreen === 'function') {
20076
- var userAgent = window_1.navigator && window_1.navigator.userAgent || '';
20077
-
20078
- // Seems to be broken in Chromium/Chrome && Safari in Leopard
20079
- if (/Android/.test(userAgent) || !/Chrome|Mac OS X 10.5/.test(userAgent)) {
20080
- return true;
20081
- }
20082
- }
20083
- return false;
20084
- };
20085
-
20086
- /**
20087
- * Request that the `HTML5` Tech enter fullscreen.
20088
- */
20089
-
20090
-
20091
- Html5.prototype.enterFullScreen = function enterFullScreen() {
20092
- var video = this.el_;
20093
-
20094
- if (video.paused && video.networkState <= video.HAVE_METADATA) {
20095
- // attempt to prime the video element for programmatic access
20096
- // this isn't necessary on the desktop but shouldn't hurt
20097
- this.el_.play();
20098
-
20099
- // playing and pausing synchronously during the transition to fullscreen
20100
- // can get iOS ~6.1 devices into a play/pause loop
20101
- this.setTimeout(function () {
20102
- video.pause();
20103
- video.webkitEnterFullScreen();
20104
- }, 0);
20105
- } else {
20106
- video.webkitEnterFullScreen();
20107
- }
20108
- };
20109
-
20110
- /**
20111
- * Request that the `HTML5` Tech exit fullscreen.
20112
- */
20113
-
20114
-
20115
- Html5.prototype.exitFullScreen = function exitFullScreen() {
20116
- this.el_.webkitExitFullScreen();
20117
- };
20118
-
20119
- /**
20120
- * A getter/setter for the `Html5` Tech's source object.
20121
- * > Note: Please use {@link Html5#setSource}
20122
- *
20123
- * @param {Tech~SourceObject} [src]
20124
- * The source object you want to set on the `HTML5` techs element.
20125
- *
20126
- * @return {Tech~SourceObject|undefined}
20127
- * - The current source object when a source is not passed in.
20128
- * - undefined when setting
20129
- *
20130
- * @deprecated Since version 5.
20131
- */
20132
-
20133
-
20134
- Html5.prototype.src = function src(_src) {
20135
- if (_src === undefined) {
20136
- return this.el_.src;
20137
- }
20138
-
20139
- // Setting src through `src` instead of `setSrc` will be deprecated
20140
- this.setSrc(_src);
20141
- };
20142
-
20143
- /**
20144
- * Reset the tech by removing all sources and then calling
20145
- * {@link Html5.resetMediaElement}.
20146
- */
20147
-
20148
-
20149
- Html5.prototype.reset = function reset() {
20150
- Html5.resetMediaElement(this.el_);
20151
- };
20152
-
20153
- /**
20154
- * Get the current source on the `HTML5` Tech. Falls back to returning the source from
20155
- * the HTML5 media element.
20156
- *
20157
- * @return {Tech~SourceObject}
20158
- * The current source object from the HTML5 tech. With a fallback to the
20159
- * elements source.
20160
- */
20161
-
20162
-
20163
- Html5.prototype.currentSrc = function currentSrc() {
20164
- if (this.currentSource_) {
20165
- return this.currentSource_.src;
20166
- }
20167
- return this.el_.currentSrc;
20168
- };
20169
-
20170
- /**
20171
- * Set controls attribute for the HTML5 media Element.
20172
- *
20173
- * @param {string} val
20174
- * Value to set the controls attribute to
20175
- */
20176
-
20177
-
20178
- Html5.prototype.setControls = function setControls(val) {
20179
- this.el_.controls = !!val;
20180
- };
20181
-
20182
- /**
20183
- * Create and returns a remote {@link TextTrack} object.
20184
- *
20185
- * @param {string} kind
20186
- * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata)
20187
- *
20188
- * @param {string} [label]
20189
- * Label to identify the text track
20190
- *
20191
- * @param {string} [language]
20192
- * Two letter language abbreviation
20193
- *
20194
- * @return {TextTrack}
20195
- * The TextTrack that gets created.
20196
- */
20197
-
20198
-
20199
- Html5.prototype.addTextTrack = function addTextTrack(kind, label, language) {
20200
- if (!this.featuresNativeTextTracks) {
20201
- return _Tech.prototype.addTextTrack.call(this, kind, label, language);
20202
- }
20203
-
20204
- return this.el_.addTextTrack(kind, label, language);
20205
- };
20206
-
20207
- /**
20208
- * Creates either native TextTrack or an emulated TextTrack depending
20209
- * on the value of `featuresNativeTextTracks`
20210
- *
20211
- * @param {Object} options
20212
- * The object should contain the options to initialize the TextTrack with.
20213
- *
20214
- * @param {string} [options.kind]
20215
- * `TextTrack` kind (subtitles, captions, descriptions, chapters, or metadata).
20216
- *
20217
- * @param {string} [options.label]
20218
- * Label to identify the text track
20219
- *
20220
- * @param {string} [options.language]
20221
- * Two letter language abbreviation.
20222
- *
20223
- * @param {boolean} [options.default]
20224
- * Default this track to on.
20225
- *
20226
- * @param {string} [options.id]
20227
- * The internal id to assign this track.
20228
- *
20229
- * @param {string} [options.src]
20230
- * A source url for the track.
20231
- *
20232
- * @return {HTMLTrackElement}
20233
- * The track element that gets created.
20234
- */
20235
-
20236
-
20237
- Html5.prototype.createRemoteTextTrack = function createRemoteTextTrack(options) {
20238
- if (!this.featuresNativeTextTracks) {
20239
- return _Tech.prototype.createRemoteTextTrack.call(this, options);
20240
- }
20241
- var htmlTrackElement = document_1.createElement('track');
20242
-
20243
- if (options.kind) {
20244
- htmlTrackElement.kind = options.kind;
20245
- }
20246
- if (options.label) {
20247
- htmlTrackElement.label = options.label;
20248
- }
20249
- if (options.language || options.srclang) {
20250
- htmlTrackElement.srclang = options.language || options.srclang;
20251
- }
20252
- if (options.default) {
20253
- htmlTrackElement.default = options.default;
20254
- }
20255
- if (options.id) {
20256
- htmlTrackElement.id = options.id;
20257
- }
20258
- if (options.src) {
20259
- htmlTrackElement.src = options.src;
20260
- }
20261
-
20262
- return htmlTrackElement;
20263
- };
20264
-
20265
- /**
20266
- * Creates a remote text track object and returns an html track element.
20267
- *
20268
- * @param {Object} options The object should contain values for
20269
- * kind, language, label, and src (location of the WebVTT file)
20270
- * @param {Boolean} [manualCleanup=true] if set to false, the TextTrack will be
20271
- * automatically removed from the video element whenever the source changes
20272
- * @return {HTMLTrackElement} An Html Track Element.
20273
- * This can be an emulated {@link HTMLTrackElement} or a native one.
20274
- * @deprecated The default value of the "manualCleanup" parameter will default
20275
- * to "false" in upcoming versions of Video.js
20276
- */
20277
-
20278
-
20279
- Html5.prototype.addRemoteTextTrack = function addRemoteTextTrack(options, manualCleanup) {
20280
- var htmlTrackElement = _Tech.prototype.addRemoteTextTrack.call(this, options, manualCleanup);
20281
-
20282
- if (this.featuresNativeTextTracks) {
20283
- this.el().appendChild(htmlTrackElement);
20284
- }
20285
-
20286
- return htmlTrackElement;
20287
- };
20288
-
20289
- /**
20290
- * Remove remote `TextTrack` from `TextTrackList` object
20291
- *
20292
- * @param {TextTrack} track
20293
- * `TextTrack` object to remove
20294
- */
20295
-
20296
-
20297
- Html5.prototype.removeRemoteTextTrack = function removeRemoteTextTrack(track) {
20298
- _Tech.prototype.removeRemoteTextTrack.call(this, track);
20299
-
20300
- if (this.featuresNativeTextTracks) {
20301
- var tracks = this.$$('track');
20302
-
20303
- var i = tracks.length;
20304
-
20305
- while (i--) {
20306
- if (track === tracks[i] || track === tracks[i].track) {
20307
- this.el().removeChild(tracks[i]);
20308
- }
20309
- }
20310
- }
20311
- };
20312
-
20313
- /**
20314
- * Gets available media playback quality metrics as specified by the W3C's Media
20315
- * Playback Quality API.
20316
- *
20317
- * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
20318
- *
20319
- * @return {Object}
20320
- * An object with supported media playback quality metrics
20321
- */
20322
-
20323
-
20324
- Html5.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
20325
- if (typeof this.el().getVideoPlaybackQuality === 'function') {
20326
- return this.el().getVideoPlaybackQuality();
20327
- }
20328
-
20329
- var videoPlaybackQuality = {};
20330
-
20331
- if (typeof this.el().webkitDroppedFrameCount !== 'undefined' && typeof this.el().webkitDecodedFrameCount !== 'undefined') {
20332
- videoPlaybackQuality.droppedVideoFrames = this.el().webkitDroppedFrameCount;
20333
- videoPlaybackQuality.totalVideoFrames = this.el().webkitDecodedFrameCount;
20334
- }
20335
-
20336
- if (window_1.performance && typeof window_1.performance.now === 'function') {
20337
- videoPlaybackQuality.creationTime = window_1.performance.now();
20338
- } else if (window_1.performance && window_1.performance.timing && typeof window_1.performance.timing.navigationStart === 'number') {
20339
- videoPlaybackQuality.creationTime = window_1.Date.now() - window_1.performance.timing.navigationStart;
20340
- }
20341
-
20342
- return videoPlaybackQuality;
20343
- };
20344
-
20345
- return Html5;
20346
- }(Tech);
20347
-
20348
- /* HTML5 Support Testing ---------------------------------------------------- */
20349
-
20350
- if (isReal()) {
20351
-
20352
- /**
20353
- * Element for testing browser HTML5 media capabilities
20354
- *
20355
- * @type {Element}
20356
- * @constant
20357
- * @private
20358
- */
20359
- Html5.TEST_VID = document_1.createElement('video');
20360
- var track = document_1.createElement('track');
20361
-
20362
- track.kind = 'captions';
20363
- track.srclang = 'en';
20364
- track.label = 'English';
20365
- Html5.TEST_VID.appendChild(track);
20366
- }
20367
-
20368
- /**
20369
- * Check if HTML5 media is supported by this browser/device.
20370
- *
20371
- * @return {boolean}
20372
- * - True if HTML5 media is supported.
20373
- * - False if HTML5 media is not supported.
20374
- */
20375
- Html5.isSupported = function () {
20376
- // IE with no Media Player is a LIAR! (#984)
20377
- try {
20378
- Html5.TEST_VID.volume = 0.5;
20379
- } catch (e) {
20380
- return false;
20381
- }
20382
-
20383
- return !!(Html5.TEST_VID && Html5.TEST_VID.canPlayType);
20384
- };
20385
-
20386
- /**
20387
- * Check if the tech can support the given type
20388
- *
20389
- * @param {string} type
20390
- * The mimetype to check
20391
- * @return {string} 'probably', 'maybe', or '' (empty string)
20392
- */
20393
- Html5.canPlayType = function (type) {
20394
- return Html5.TEST_VID.canPlayType(type);
20395
- };
20396
-
20397
- /**
20398
- * Check if the tech can support the given source
20399
- * @param {Object} srcObj
20400
- * The source object
20401
- * @param {Object} options
20402
- * The options passed to the tech
20403
- * @return {string} 'probably', 'maybe', or '' (empty string)
20404
- */
20405
- Html5.canPlaySource = function (srcObj, options) {
20406
- return Html5.canPlayType(srcObj.type);
20407
- };
20408
-
20409
- /**
20410
- * Check if the volume can be changed in this browser/device.
20411
- * Volume cannot be changed in a lot of mobile devices.
20412
- * Specifically, it can't be changed from 1 on iOS.
20413
- *
20414
- * @return {boolean}
20415
- * - True if volume can be controlled
20416
- * - False otherwise
20417
- */
20418
- Html5.canControlVolume = function () {
20419
- // IE will error if Windows Media Player not installed #3315
20420
- try {
20421
- var volume = Html5.TEST_VID.volume;
20422
-
20423
- Html5.TEST_VID.volume = volume / 2 + 0.1;
20424
- return volume !== Html5.TEST_VID.volume;
20425
- } catch (e) {
20426
- return false;
20427
- }
20428
- };
20429
-
20430
- /**
20431
- * Check if the volume can be muted in this browser/device.
20432
- * Some devices, e.g. iOS, don't allow changing volume
20433
- * but permits muting/unmuting.
20434
- *
20435
- * @return {bolean}
20436
- * - True if volume can be muted
20437
- * - False otherwise
20438
- */
20439
- Html5.canMuteVolume = function () {
20440
- try {
20441
- var muted = Html5.TEST_VID.muted;
20442
-
20443
- // in some versions of iOS muted property doesn't always
20444
- // work, so we want to set both property and attribute
20445
- Html5.TEST_VID.muted = !muted;
20446
- if (Html5.TEST_VID.muted) {
20447
- setAttribute(Html5.TEST_VID, 'muted', 'muted');
20448
- } else {
20449
- removeAttribute(Html5.TEST_VID, 'muted', 'muted');
20450
- }
20451
- return muted !== Html5.TEST_VID.muted;
20452
- } catch (e) {
20453
- return false;
20454
- }
20455
- };
20456
-
20457
- /**
20458
- * Check if the playback rate can be changed in this browser/device.
20459
- *
20460
- * @return {boolean}
20461
- * - True if playback rate can be controlled
20462
- * - False otherwise
20463
- */
20464
- Html5.canControlPlaybackRate = function () {
20465
- // Playback rate API is implemented in Android Chrome, but doesn't do anything
20466
- // https://github.com/videojs/video.js/issues/3180
20467
- if (IS_ANDROID && IS_CHROME && CHROME_VERSION < 58) {
20468
- return false;
20469
- }
20470
- // IE will error if Windows Media Player not installed #3315
20471
- try {
20472
- var playbackRate = Html5.TEST_VID.playbackRate;
20473
-
20474
- Html5.TEST_VID.playbackRate = playbackRate / 2 + 0.1;
20475
- return playbackRate !== Html5.TEST_VID.playbackRate;
20476
- } catch (e) {
20477
- return false;
20478
- }
20479
- };
20480
-
20481
- /**
20482
- * Check if we can override a video/audio elements attributes, with
20483
- * Object.defineProperty.
20484
- *
20485
- * @return {boolean}
20486
- * - True if builtin attributes can be overridden
20487
- * - False otherwise
20488
- */
20489
- Html5.canOverrideAttributes = function () {
20490
- // if we cannot overwrite the src/innerHTML property, there is no support
20491
- // iOS 7 safari for instance cannot do this.
20492
- try {
20493
- var noop = function noop() {};
20494
-
20495
- Object.defineProperty(document_1.createElement('video'), 'src', { get: noop, set: noop });
20496
- Object.defineProperty(document_1.createElement('audio'), 'src', { get: noop, set: noop });
20497
- Object.defineProperty(document_1.createElement('video'), 'innerHTML', { get: noop, set: noop });
20498
- Object.defineProperty(document_1.createElement('audio'), 'innerHTML', { get: noop, set: noop });
20499
- } catch (e) {
20500
- return false;
20501
- }
20502
-
20503
- return true;
20504
- };
20505
-
20506
- /**
20507
- * Check to see if native `TextTrack`s are supported by this browser/device.
20508
- *
20509
- * @return {boolean}
20510
- * - True if native `TextTrack`s are supported.
20511
- * - False otherwise
20512
- */
20513
- Html5.supportsNativeTextTracks = function () {
20514
- return IS_ANY_SAFARI || IS_IOS && IS_CHROME;
20515
- };
20516
-
20517
- /**
20518
- * Check to see if native `VideoTrack`s are supported by this browser/device
20519
- *
20520
- * @return {boolean}
20521
- * - True if native `VideoTrack`s are supported.
20522
- * - False otherwise
20523
- */
20524
- Html5.supportsNativeVideoTracks = function () {
20525
- return !!(Html5.TEST_VID && Html5.TEST_VID.videoTracks);
20526
- };
20527
-
20528
- /**
20529
- * Check to see if native `AudioTrack`s are supported by this browser/device
20530
- *
20531
- * @return {boolean}
20532
- * - True if native `AudioTrack`s are supported.
20533
- * - False otherwise
20534
- */
20535
- Html5.supportsNativeAudioTracks = function () {
20536
- return !!(Html5.TEST_VID && Html5.TEST_VID.audioTracks);
20537
- };
20538
-
20539
- /**
20540
- * An array of events available on the Html5 tech.
20541
- *
20542
- * @private
20543
- * @type {Array}
20544
- */
20545
- Html5.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'resize', 'volumechange'];
20546
-
20547
- /**
20548
- * Boolean indicating whether the `Tech` supports volume control.
20549
- *
20550
- * @type {boolean}
20551
- * @default {@link Html5.canControlVolume}
20552
- */
20553
- Html5.prototype.featuresVolumeControl = Html5.canControlVolume();
20554
-
20555
- /**
20556
- * Boolean indicating whether the `Tech` supports muting volume.
20557
- *
20558
- * @type {bolean}
20559
- * @default {@link Html5.canMuteVolume}
20560
- */
20561
- Html5.prototype.featuresMuteControl = Html5.canMuteVolume();
20562
-
20563
- /**
20564
- * Boolean indicating whether the `Tech` supports changing the speed at which the media
20565
- * plays. Examples:
20566
- * - Set player to play 2x (twice) as fast
20567
- * - Set player to play 0.5x (half) as fast
20568
- *
20569
- * @type {boolean}
20570
- * @default {@link Html5.canControlPlaybackRate}
20571
- */
20572
- Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate();
20573
-
20574
- /**
20575
- * Boolean indicating whether the `Tech` supports the `sourceset` event.
20576
- *
20577
- * @type {boolean}
20578
- * @default
20579
- */
20580
- Html5.prototype.featuresSourceset = Html5.canOverrideAttributes();
20581
-
20582
- /**
20583
- * Boolean indicating whether the `HTML5` tech currently supports the media element
20584
- * moving in the DOM. iOS breaks if you move the media element, so this is set this to
20585
- * false there. Everywhere else this should be true.
20586
- *
20587
- * @type {boolean}
20588
- * @default
20589
- */
20590
- Html5.prototype.movingMediaElementInDOM = !IS_IOS;
20591
-
20592
- // TODO: Previous comment: No longer appears to be used. Can probably be removed.
20593
- // Is this true?
20594
- /**
20595
- * Boolean indicating whether the `HTML5` tech currently supports automatic media resize
20596
- * when going into fullscreen.
20597
- *
20598
- * @type {boolean}
20599
- * @default
20600
- */
20601
- Html5.prototype.featuresFullscreenResize = true;
20602
-
20603
- /**
20604
- * Boolean indicating whether the `HTML5` tech currently supports the progress event.
20605
- * If this is false, manual `progress` events will be triggered instead.
20606
- *
20607
- * @type {boolean}
20608
- * @default
20609
- */
20610
- Html5.prototype.featuresProgressEvents = true;
20611
-
20612
- /**
20613
- * Boolean indicating whether the `HTML5` tech currently supports the timeupdate event.
20614
- * If this is false, manual `timeupdate` events will be triggered instead.
20615
- *
20616
- * @default
20617
- */
20618
- Html5.prototype.featuresTimeupdateEvents = true;
20619
-
20620
- /**
20621
- * Boolean indicating whether the `HTML5` tech currently supports native `TextTrack`s.
20622
- *
20623
- * @type {boolean}
20624
- * @default {@link Html5.supportsNativeTextTracks}
20625
- */
20626
- Html5.prototype.featuresNativeTextTracks = Html5.supportsNativeTextTracks();
20627
-
20628
- /**
20629
- * Boolean indicating whether the `HTML5` tech currently supports native `VideoTrack`s.
20630
- *
20631
- * @type {boolean}
20632
- * @default {@link Html5.supportsNativeVideoTracks}
20633
- */
20634
- Html5.prototype.featuresNativeVideoTracks = Html5.supportsNativeVideoTracks();
20635
-
20636
- /**
20637
- * Boolean indicating whether the `HTML5` tech currently supports native `AudioTrack`s.
20638
- *
20639
- * @type {boolean}
20640
- * @default {@link Html5.supportsNativeAudioTracks}
20641
- */
20642
- Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks();
20643
-
20644
- // HTML5 Feature detection and Device Fixes --------------------------------- //
20645
- var canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType;
20646
- var mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i;
20647
-
20648
- Html5.patchCanPlayType = function () {
20649
-
20650
- // Android 4.0 and above can play HLS to some extent but it reports being unable to do so
20651
- // Firefox and Chrome report correctly
20652
- if (ANDROID_VERSION >= 4.0 && !IS_FIREFOX && !IS_CHROME) {
20653
- Html5.TEST_VID.constructor.prototype.canPlayType = function (type) {
20654
- if (type && mpegurlRE.test(type)) {
20655
- return 'maybe';
20656
- }
20657
- return canPlayType.call(this, type);
20658
- };
20659
- }
20660
- };
20661
-
20662
- Html5.unpatchCanPlayType = function () {
20663
- var r = Html5.TEST_VID.constructor.prototype.canPlayType;
20664
-
20665
- Html5.TEST_VID.constructor.prototype.canPlayType = canPlayType;
20666
- return r;
20667
- };
20668
-
20669
- // by default, patch the media element
20670
- Html5.patchCanPlayType();
20671
-
20672
- Html5.disposeMediaElement = function (el) {
20673
- if (!el) {
20674
- return;
20675
- }
20676
-
20677
- if (el.parentNode) {
20678
- el.parentNode.removeChild(el);
20679
- }
20680
-
20681
- // remove any child track or source nodes to prevent their loading
20682
- while (el.hasChildNodes()) {
20683
- el.removeChild(el.firstChild);
20684
- }
20685
-
20686
- // remove any src reference. not setting `src=''` because that causes a warning
20687
- // in firefox
20688
- el.removeAttribute('src');
20689
-
20690
- // force the media element to update its loading state by calling load()
20691
- // however IE on Windows 7N has a bug that throws an error so need a try/catch (#793)
20692
- if (typeof el.load === 'function') {
20693
- // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
20694
- (function () {
20695
- try {
20696
- el.load();
20697
- } catch (e) {
20698
- // not supported
20699
- }
20700
- })();
20701
- }
20702
- };
20703
-
20704
- Html5.resetMediaElement = function (el) {
20705
- if (!el) {
20706
- return;
20707
- }
20708
-
20709
- var sources = el.querySelectorAll('source');
20710
- var i = sources.length;
20711
-
20712
- while (i--) {
20713
- el.removeChild(sources[i]);
20714
- }
20715
-
20716
- // remove any src reference.
20717
- // not setting `src=''` because that throws an error
20718
- el.removeAttribute('src');
20719
-
20720
- if (typeof el.load === 'function') {
20721
- // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
20722
- (function () {
20723
- try {
20724
- el.load();
20725
- } catch (e) {
20726
- // satisfy linter
20727
- }
20728
- })();
20729
- }
20730
- };
20731
-
20732
- /* Native HTML5 element property wrapping ----------------------------------- */
20733
- // Wrap native boolean attributes with getters that check both property and attribute
20734
- // The list is as followed:
20735
- // muted, defaultMuted, autoplay, controls, loop, playsinline
20736
- [
20737
- /**
20738
- * Get the value of `muted` from the media element. `muted` indicates
20739
- * that the volume for the media should be set to silent. This does not actually change
20740
- * the `volume` attribute.
20741
- *
20742
- * @method Html5#muted
20743
- * @return {boolean}
20744
- * - True if the value of `volume` should be ignored and the audio set to silent.
20745
- * - False if the value of `volume` should be used.
20746
- *
20747
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
20748
- */
20749
- 'muted',
20750
-
20751
- /**
20752
- * Get the value of `defaultMuted` from the media element. `defaultMuted` indicates
20753
- * whether the media should start muted or not. Only changes the default state of the
20754
- * media. `muted` and `defaultMuted` can have different values. {@link Html5#muted} indicates the
20755
- * current state.
20756
- *
20757
- * @method Html5#defaultMuted
20758
- * @return {boolean}
20759
- * - The value of `defaultMuted` from the media element.
20760
- * - True indicates that the media should start muted.
20761
- * - False indicates that the media should not start muted
20762
- *
20763
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
20764
- */
20765
- 'defaultMuted',
20766
-
20767
- /**
20768
- * Get the value of `autoplay` from the media element. `autoplay` indicates
20769
- * that the media should start to play as soon as the page is ready.
20770
- *
20771
- * @method Html5#autoplay
20772
- * @return {boolean}
20773
- * - The value of `autoplay` from the media element.
20774
- * - True indicates that the media should start as soon as the page loads.
20775
- * - False indicates that the media should not start as soon as the page loads.
20776
- *
20777
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
20778
- */
20779
- 'autoplay',
20780
-
20781
- /**
20782
- * Get the value of `controls` from the media element. `controls` indicates
20783
- * whether the native media controls should be shown or hidden.
20784
- *
20785
- * @method Html5#controls
20786
- * @return {boolean}
20787
- * - The value of `controls` from the media element.
20788
- * - True indicates that native controls should be showing.
20789
- * - False indicates that native controls should be hidden.
20790
- *
20791
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls}
20792
- */
20793
- 'controls',
20794
-
20795
- /**
20796
- * Get the value of `loop` from the media element. `loop` indicates
20797
- * that the media should return to the start of the media and continue playing once
20798
- * it reaches the end.
20799
- *
20800
- * @method Html5#loop
20801
- * @return {boolean}
20802
- * - The value of `loop` from the media element.
20803
- * - True indicates that playback should seek back to start once
20804
- * the end of a media is reached.
20805
- * - False indicates that playback should not loop back to the start when the
20806
- * end of the media is reached.
20807
- *
20808
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
20809
- */
20810
- 'loop',
20811
-
20812
- /**
20813
- * Get the value of `playsinline` from the media element. `playsinline` indicates
20814
- * to the browser that non-fullscreen playback is preferred when fullscreen
20815
- * playback is the native default, such as in iOS Safari.
20816
- *
20817
- * @method Html5#playsinline
20818
- * @return {boolean}
20819
- * - The value of `playsinline` from the media element.
20820
- * - True indicates that the media should play inline.
20821
- * - False indicates that the media should not play inline.
20822
- *
20823
- * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
20824
- */
20825
- 'playsinline'].forEach(function (prop) {
20826
- Html5.prototype[prop] = function () {
20827
- return this.el_[prop] || this.el_.hasAttribute(prop);
20828
- };
20829
- });
20830
-
20831
- // Wrap native boolean attributes with setters that set both property and attribute
20832
- // The list is as followed:
20833
- // setMuted, setDefaultMuted, setAutoplay, setLoop, setPlaysinline
20834
- // setControls is special-cased above
20835
- [
20836
- /**
20837
- * Set the value of `muted` on the media element. `muted` indicates that the current
20838
- * audio level should be silent.
20839
- *
20840
- * @method Html5#setMuted
20841
- * @param {boolean} muted
20842
- * - True if the audio should be set to silent
20843
- * - False otherwise
20844
- *
20845
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-muted}
20846
- */
20847
- 'muted',
20848
-
20849
- /**
20850
- * Set the value of `defaultMuted` on the media element. `defaultMuted` indicates that the current
20851
- * audio level should be silent, but will only effect the muted level on intial playback..
20852
- *
20853
- * @method Html5.prototype.setDefaultMuted
20854
- * @param {boolean} defaultMuted
20855
- * - True if the audio should be set to silent
20856
- * - False otherwise
20857
- *
20858
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultmuted}
20859
- */
20860
- 'defaultMuted',
20861
-
20862
- /**
20863
- * Set the value of `autoplay` on the media element. `autoplay` indicates
20864
- * that the media should start to play as soon as the page is ready.
20865
- *
20866
- * @method Html5#setAutoplay
20867
- * @param {boolean} autoplay
20868
- * - True indicates that the media should start as soon as the page loads.
20869
- * - False indicates that the media should not start as soon as the page loads.
20870
- *
20871
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay}
20872
- */
20873
- 'autoplay',
20874
-
20875
- /**
20876
- * Set the value of `loop` on the media element. `loop` indicates
20877
- * that the media should return to the start of the media and continue playing once
20878
- * it reaches the end.
20879
- *
20880
- * @method Html5#setLoop
20881
- * @param {boolean} loop
20882
- * - True indicates that playback should seek back to start once
20883
- * the end of a media is reached.
20884
- * - False indicates that playback should not loop back to the start when the
20885
- * end of the media is reached.
20886
- *
20887
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop}
20888
- */
20889
- 'loop',
20890
-
20891
- /**
20892
- * Set the value of `playsinline` from the media element. `playsinline` indicates
20893
- * to the browser that non-fullscreen playback is preferred when fullscreen
20894
- * playback is the native default, such as in iOS Safari.
20895
- *
20896
- * @method Html5#setPlaysinline
20897
- * @param {boolean} playsinline
20898
- * - True indicates that the media should play inline.
20899
- * - False indicates that the media should not play inline.
20900
- *
20901
- * @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
20902
- */
20903
- 'playsinline'].forEach(function (prop) {
20904
- Html5.prototype['set' + toTitleCase(prop)] = function (v) {
20905
- this.el_[prop] = v;
20906
-
20907
- if (v) {
20908
- this.el_.setAttribute(prop, prop);
20909
- } else {
20910
- this.el_.removeAttribute(prop);
20911
- }
20912
- };
20913
- });
20914
-
20915
- // Wrap native properties with a getter
20916
- // The list is as followed
20917
- // paused, currentTime, buffered, volume, poster, preload, error, seeking
20918
- // seekable, ended, playbackRate, defaultPlaybackRate, played, networkState
20919
- // readyState, videoWidth, videoHeight
20920
- [
20921
- /**
20922
- * Get the value of `paused` from the media element. `paused` indicates whether the media element
20923
- * is currently paused or not.
20924
- *
20925
- * @method Html5#paused
20926
- * @return {boolean}
20927
- * The value of `paused` from the media element.
20928
- *
20929
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-paused}
20930
- */
20931
- 'paused',
20932
-
20933
- /**
20934
- * Get the value of `currentTime` from the media element. `currentTime` indicates
20935
- * the current second that the media is at in playback.
20936
- *
20937
- * @method Html5#currentTime
20938
- * @return {number}
20939
- * The value of `currentTime` from the media element.
20940
- *
20941
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-currenttime}
20942
- */
20943
- 'currentTime',
20944
-
20945
- /**
20946
- * Get the value of `buffered` from the media element. `buffered` is a `TimeRange`
20947
- * object that represents the parts of the media that are already downloaded and
20948
- * available for playback.
20949
- *
20950
- * @method Html5#buffered
20951
- * @return {TimeRange}
20952
- * The value of `buffered` from the media element.
20953
- *
20954
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-buffered}
20955
- */
20956
- 'buffered',
20957
-
20958
- /**
20959
- * Get the value of `volume` from the media element. `volume` indicates
20960
- * the current playback volume of audio for a media. `volume` will be a value from 0
20961
- * (silent) to 1 (loudest and default).
20962
- *
20963
- * @method Html5#volume
20964
- * @return {number}
20965
- * The value of `volume` from the media element. Value will be between 0-1.
20966
- *
20967
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
20968
- */
20969
- 'volume',
20970
-
20971
- /**
20972
- * Get the value of `poster` from the media element. `poster` indicates
20973
- * that the url of an image file that can/will be shown when no media data is available.
20974
- *
20975
- * @method Html5#poster
20976
- * @return {string}
20977
- * The value of `poster` from the media element. Value will be a url to an
20978
- * image.
20979
- *
20980
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-video-poster}
20981
- */
20982
- 'poster',
20983
-
20984
- /**
20985
- * Get the value of `preload` from the media element. `preload` indicates
20986
- * what should download before the media is interacted with. It can have the following
20987
- * values:
20988
- * - none: nothing should be downloaded
20989
- * - metadata: poster and the first few frames of the media may be downloaded to get
20990
- * media dimensions and other metadata
20991
- * - auto: allow the media and metadata for the media to be downloaded before
20992
- * interaction
20993
- *
20994
- * @method Html5#preload
20995
- * @return {string}
20996
- * The value of `preload` from the media element. Will be 'none', 'metadata',
20997
- * or 'auto'.
20998
- *
20999
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
21000
- */
21001
- 'preload',
21002
-
21003
- /**
21004
- * Get the value of the `error` from the media element. `error` indicates any
21005
- * MediaError that may have occurred during playback. If error returns null there is no
21006
- * current error.
21007
- *
21008
- * @method Html5#error
21009
- * @return {MediaError|null}
21010
- * The value of `error` from the media element. Will be `MediaError` if there
21011
- * is a current error and null otherwise.
21012
- *
21013
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-error}
21014
- */
21015
- 'error',
21016
-
21017
- /**
21018
- * Get the value of `seeking` from the media element. `seeking` indicates whether the
21019
- * media is currently seeking to a new position or not.
21020
- *
21021
- * @method Html5#seeking
21022
- * @return {boolean}
21023
- * - The value of `seeking` from the media element.
21024
- * - True indicates that the media is currently seeking to a new position.
21025
- * - False indicates that the media is not seeking to a new position at this time.
21026
- *
21027
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seeking}
21028
- */
21029
- 'seeking',
21030
-
21031
- /**
21032
- * Get the value of `seekable` from the media element. `seekable` returns a
21033
- * `TimeRange` object indicating ranges of time that can currently be `seeked` to.
21034
- *
21035
- * @method Html5#seekable
21036
- * @return {TimeRange}
21037
- * The value of `seekable` from the media element. A `TimeRange` object
21038
- * indicating the current ranges of time that can be seeked to.
21039
- *
21040
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-seekable}
21041
- */
21042
- 'seekable',
21043
-
21044
- /**
21045
- * Get the value of `ended` from the media element. `ended` indicates whether
21046
- * the media has reached the end or not.
21047
- *
21048
- * @method Html5#ended
21049
- * @return {boolean}
21050
- * - The value of `ended` from the media element.
21051
- * - True indicates that the media has ended.
21052
- * - False indicates that the media has not ended.
21053
- *
21054
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
21055
- */
21056
- 'ended',
21057
-
21058
- /**
21059
- * Get the value of `playbackRate` from the media element. `playbackRate` indicates
21060
- * the rate at which the media is currently playing back. Examples:
21061
- * - if playbackRate is set to 2, media will play twice as fast.
21062
- * - if playbackRate is set to 0.5, media will play half as fast.
21063
- *
21064
- * @method Html5#playbackRate
21065
- * @return {number}
21066
- * The value of `playbackRate` from the media element. A number indicating
21067
- * the current playback speed of the media, where 1 is normal speed.
21068
- *
21069
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
21070
- */
21071
- 'playbackRate',
21072
-
21073
- /**
21074
- * Get the value of `defaultPlaybackRate` from the media element. `defaultPlaybackRate` indicates
21075
- * the rate at which the media is currently playing back. This value will not indicate the current
21076
- * `playbackRate` after playback has started, use {@link Html5#playbackRate} for that.
21077
- *
21078
- * Examples:
21079
- * - if defaultPlaybackRate is set to 2, media will play twice as fast.
21080
- * - if defaultPlaybackRate is set to 0.5, media will play half as fast.
21081
- *
21082
- * @method Html5.prototype.defaultPlaybackRate
21083
- * @return {number}
21084
- * The value of `defaultPlaybackRate` from the media element. A number indicating
21085
- * the current playback speed of the media, where 1 is normal speed.
21086
- *
21087
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
21088
- */
21089
- 'defaultPlaybackRate',
21090
-
21091
- /**
21092
- * Get the value of `played` from the media element. `played` returns a `TimeRange`
21093
- * object representing points in the media timeline that have been played.
21094
- *
21095
- * @method Html5#played
21096
- * @return {TimeRange}
21097
- * The value of `played` from the media element. A `TimeRange` object indicating
21098
- * the ranges of time that have been played.
21099
- *
21100
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-played}
21101
- */
21102
- 'played',
21103
-
21104
- /**
21105
- * Get the value of `networkState` from the media element. `networkState` indicates
21106
- * the current network state. It returns an enumeration from the following list:
21107
- * - 0: NETWORK_EMPTY
21108
- * - 1: NETWORK_IDLE
21109
- * - 2: NETWORK_LOADING
21110
- * - 3: NETWORK_NO_SOURCE
21111
- *
21112
- * @method Html5#networkState
21113
- * @return {number}
21114
- * The value of `networkState` from the media element. This will be a number
21115
- * from the list in the description.
21116
- *
21117
- * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-networkstate}
21118
- */
21119
- 'networkState',
21120
-
21121
- /**
21122
- * Get the value of `readyState` from the media element. `readyState` indicates
21123
- * the current state of the media element. It returns an enumeration from the
21124
- * following list:
21125
- * - 0: HAVE_NOTHING
21126
- * - 1: HAVE_METADATA
21127
- * - 2: HAVE_CURRENT_DATA
21128
- * - 3: HAVE_FUTURE_DATA
21129
- * - 4: HAVE_ENOUGH_DATA
21130
- *
21131
- * @method Html5#readyState
21132
- * @return {number}
21133
- * The value of `readyState` from the media element. This will be a number
21134
- * from the list in the description.
21135
- *
21136
- * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#ready-states}
21137
- */
21138
- 'readyState',
21139
-
21140
- /**
21141
- * Get the value of `videoWidth` from the video element. `videoWidth` indicates
21142
- * the current width of the video in css pixels.
21143
- *
21144
- * @method Html5#videoWidth
21145
- * @return {number}
21146
- * The value of `videoWidth` from the video element. This will be a number
21147
- * in css pixels.
21148
- *
21149
- * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
21150
- */
21151
- 'videoWidth',
21152
-
21153
- /**
21154
- * Get the value of `videoHeight` from the video element. `videoHeight` indicates
21155
- * the current height of the video in css pixels.
21156
- *
21157
- * @method Html5#videoHeight
21158
- * @return {number}
21159
- * The value of `videoHeight` from the video element. This will be a number
21160
- * in css pixels.
21161
- *
21162
- * @see [Spec] {@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-video-videowidth}
21163
- */
21164
- 'videoHeight'].forEach(function (prop) {
21165
- Html5.prototype[prop] = function () {
21166
- return this.el_[prop];
21167
- };
21168
- });
21169
-
21170
- // Wrap native properties with a setter in this format:
21171
- // set + toTitleCase(name)
21172
- // The list is as follows:
21173
- // setVolume, setSrc, setPoster, setPreload, setPlaybackRate, setDefaultPlaybackRate
21174
- [
21175
- /**
21176
- * Set the value of `volume` on the media element. `volume` indicates the current
21177
- * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
21178
- * so on.
21179
- *
21180
- * @method Html5#setVolume
21181
- * @param {number} percentAsDecimal
21182
- * The volume percent as a decimal. Valid range is from 0-1.
21183
- *
21184
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-a-volume}
21185
- */
21186
- 'volume',
21187
-
21188
- /**
21189
- * Set the value of `src` on the media element. `src` indicates the current
21190
- * {@link Tech~SourceObject} for the media.
21191
- *
21192
- * @method Html5#setSrc
21193
- * @param {Tech~SourceObject} src
21194
- * The source object to set as the current source.
21195
- *
21196
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-src}
21197
- */
21198
- 'src',
21199
-
21200
- /**
21201
- * Set the value of `poster` on the media element. `poster` is the url to
21202
- * an image file that can/will be shown when no media data is available.
21203
- *
21204
- * @method Html5#setPoster
21205
- * @param {string} poster
21206
- * The url to an image that should be used as the `poster` for the media
21207
- * element.
21208
- *
21209
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-poster}
21210
- */
21211
- 'poster',
21212
-
21213
- /**
21214
- * Set the value of `preload` on the media element. `preload` indicates
21215
- * what should download before the media is interacted with. It can have the following
21216
- * values:
21217
- * - none: nothing should be downloaded
21218
- * - metadata: poster and the first few frames of the media may be downloaded to get
21219
- * media dimensions and other metadata
21220
- * - auto: allow the media and metadata for the media to be downloaded before
21221
- * interaction
21222
- *
21223
- * @method Html5#setPreload
21224
- * @param {string} preload
21225
- * The value of `preload` to set on the media element. Must be 'none', 'metadata',
21226
- * or 'auto'.
21227
- *
21228
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-preload}
21229
- */
21230
- 'preload',
21231
-
21232
- /**
21233
- * Set the value of `playbackRate` on the media element. `playbackRate` indicates
21234
- * the rate at which the media should play back. Examples:
21235
- * - if playbackRate is set to 2, media will play twice as fast.
21236
- * - if playbackRate is set to 0.5, media will play half as fast.
21237
- *
21238
- * @method Html5#setPlaybackRate
21239
- * @return {number}
21240
- * The value of `playbackRate` from the media element. A number indicating
21241
- * the current playback speed of the media, where 1 is normal speed.
21242
- *
21243
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-playbackrate}
21244
- */
21245
- 'playbackRate',
21246
-
21247
- /**
21248
- * Set the value of `defaultPlaybackRate` on the media element. `defaultPlaybackRate` indicates
21249
- * the rate at which the media should play back upon initial startup. Changing this value
21250
- * after a video has started will do nothing. Instead you should used {@link Html5#setPlaybackRate}.
21251
- *
21252
- * Example Values:
21253
- * - if playbackRate is set to 2, media will play twice as fast.
21254
- * - if playbackRate is set to 0.5, media will play half as fast.
21255
- *
21256
- * @method Html5.prototype.setDefaultPlaybackRate
21257
- * @return {number}
21258
- * The value of `defaultPlaybackRate` from the media element. A number indicating
21259
- * the current playback speed of the media, where 1 is normal speed.
21260
- *
21261
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-defaultplaybackrate}
21262
- */
21263
- 'defaultPlaybackRate'].forEach(function (prop) {
21264
- Html5.prototype['set' + toTitleCase(prop)] = function (v) {
21265
- this.el_[prop] = v;
21266
- };
21267
- });
21268
-
21269
- // wrap native functions with a function
21270
- // The list is as follows:
21271
- // pause, load, play
21272
- [
21273
- /**
21274
- * A wrapper around the media elements `pause` function. This will call the `HTML5`
21275
- * media elements `pause` function.
21276
- *
21277
- * @method Html5#pause
21278
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-pause}
21279
- */
21280
- 'pause',
21281
-
21282
- /**
21283
- * A wrapper around the media elements `load` function. This will call the `HTML5`s
21284
- * media element `load` function.
21285
- *
21286
- * @method Html5#load
21287
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-load}
21288
- */
21289
- 'load',
21290
-
21291
- /**
21292
- * A wrapper around the media elements `play` function. This will call the `HTML5`s
21293
- * media element `play` function.
21294
- *
21295
- * @method Html5#play
21296
- * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-play}
21297
- */
21298
- 'play'].forEach(function (prop) {
21299
- Html5.prototype[prop] = function () {
21300
- return this.el_[prop]();
21301
- };
21302
- });
21303
-
21304
- Tech.withSourceHandlers(Html5);
21305
-
21306
- /**
21307
- * Native source handler for Html5, simply passes the source to the media element.
21308
- *
21309
- * @property {Tech~SourceObject} source
21310
- * The source object
21311
- *
21312
- * @property {Html5} tech
21313
- * The instance of the HTML5 tech.
21314
- */
21315
- Html5.nativeSourceHandler = {};
21316
-
21317
- /**
21318
- * Check if the media element can play the given mime type.
21319
- *
21320
- * @param {string} type
21321
- * The mimetype to check
21322
- *
21323
- * @return {string}
21324
- * 'probably', 'maybe', or '' (empty string)
21325
- */
21326
- Html5.nativeSourceHandler.canPlayType = function (type) {
21327
- // IE without MediaPlayer throws an error (#519)
21328
- try {
21329
- return Html5.TEST_VID.canPlayType(type);
21330
- } catch (e) {
21331
- return '';
21332
- }
21333
- };
21334
-
21335
- /**
21336
- * Check if the media element can handle a source natively.
21337
- *
21338
- * @param {Tech~SourceObject} source
21339
- * The source object
21340
- *
21341
- * @param {Object} [options]
21342
- * Options to be passed to the tech.
21343
- *
21344
- * @return {string}
21345
- * 'probably', 'maybe', or '' (empty string).
21346
- */
21347
- Html5.nativeSourceHandler.canHandleSource = function (source, options) {
21348
-
21349
- // If a type was provided we should rely on that
21350
- if (source.type) {
21351
- return Html5.nativeSourceHandler.canPlayType(source.type);
21352
-
21353
- // If no type, fall back to checking 'video/[EXTENSION]'
21354
- } else if (source.src) {
21355
- var ext = getFileExtension(source.src);
21356
-
21357
- return Html5.nativeSourceHandler.canPlayType('video/' + ext);
21358
- }
21359
-
21360
- return '';
21361
- };
21362
-
21363
- /**
21364
- * Pass the source to the native media element.
21365
- *
21366
- * @param {Tech~SourceObject} source
21367
- * The source object
21368
- *
21369
- * @param {Html5} tech
21370
- * The instance of the Html5 tech
21371
- *
21372
- * @param {Object} [options]
21373
- * The options to pass to the source
21374
- */
21375
- Html5.nativeSourceHandler.handleSource = function (source, tech, options) {
21376
- tech.setSrc(source.src);
21377
- };
21378
-
21379
- /**
21380
- * A noop for the native dispose function, as cleanup is not needed.
21381
- */
21382
- Html5.nativeSourceHandler.dispose = function () {};
21383
-
21384
- // Register the native source handler
21385
- Html5.registerSourceHandler(Html5.nativeSourceHandler);
21386
-
21387
- Tech.registerTech('Html5', Html5);
21388
-
21389
- var _templateObject$2 = taggedTemplateLiteralLoose(['\n Using the tech directly can be dangerous. I hope you know what you\'re doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n '], ['\n Using the tech directly can be dangerous. I hope you know what you\'re doing.\n See https://github.com/videojs/video.js/issues/2617 for more info.\n ']);
21390
-
21391
- // The following tech events are simply re-triggered
21392
- // on the player when they happen
21393
- var TECH_EVENTS_RETRIGGER = [
21394
- /**
21395
- * Fired while the user agent is downloading media data.
21396
- *
21397
- * @event Player#progress
21398
- * @type {EventTarget~Event}
21399
- */
21400
- /**
21401
- * Retrigger the `progress` event that was triggered by the {@link Tech}.
21402
- *
21403
- * @private
21404
- * @method Player#handleTechProgress_
21405
- * @fires Player#progress
21406
- * @listens Tech#progress
21407
- */
21408
- 'progress',
21409
-
21410
- /**
21411
- * Fires when the loading of an audio/video is aborted.
21412
- *
21413
- * @event Player#abort
21414
- * @type {EventTarget~Event}
21415
- */
21416
- /**
21417
- * Retrigger the `abort` event that was triggered by the {@link Tech}.
21418
- *
21419
- * @private
21420
- * @method Player#handleTechAbort_
21421
- * @fires Player#abort
21422
- * @listens Tech#abort
21423
- */
21424
- 'abort',
21425
-
21426
- /**
21427
- * Fires when the browser is intentionally not getting media data.
21428
- *
21429
- * @event Player#suspend
21430
- * @type {EventTarget~Event}
21431
- */
21432
- /**
21433
- * Retrigger the `suspend` event that was triggered by the {@link Tech}.
21434
- *
21435
- * @private
21436
- * @method Player#handleTechSuspend_
21437
- * @fires Player#suspend
21438
- * @listens Tech#suspend
21439
- */
21440
- 'suspend',
21441
-
21442
- /**
21443
- * Fires when the current playlist is empty.
21444
- *
21445
- * @event Player#emptied
21446
- * @type {EventTarget~Event}
21447
- */
21448
- /**
21449
- * Retrigger the `emptied` event that was triggered by the {@link Tech}.
21450
- *
21451
- * @private
21452
- * @method Player#handleTechEmptied_
21453
- * @fires Player#emptied
21454
- * @listens Tech#emptied
21455
- */
21456
- 'emptied',
21457
- /**
21458
- * Fires when the browser is trying to get media data, but data is not available.
21459
- *
21460
- * @event Player#stalled
21461
- * @type {EventTarget~Event}
21462
- */
21463
- /**
21464
- * Retrigger the `stalled` event that was triggered by the {@link Tech}.
21465
- *
21466
- * @private
21467
- * @method Player#handleTechStalled_
21468
- * @fires Player#stalled
21469
- * @listens Tech#stalled
21470
- */
21471
- 'stalled',
21472
-
21473
- /**
21474
- * Fires when the browser has loaded meta data for the audio/video.
21475
- *
21476
- * @event Player#loadedmetadata
21477
- * @type {EventTarget~Event}
21478
- */
21479
- /**
21480
- * Retrigger the `stalled` event that was triggered by the {@link Tech}.
21481
- *
21482
- * @private
21483
- * @method Player#handleTechLoadedmetadata_
21484
- * @fires Player#loadedmetadata
21485
- * @listens Tech#loadedmetadata
21486
- */
21487
- 'loadedmetadata',
21488
-
21489
- /**
21490
- * Fires when the browser has loaded the current frame of the audio/video.
21491
- *
21492
- * @event Player#loadeddata
21493
- * @type {event}
21494
- */
21495
- /**
21496
- * Retrigger the `loadeddata` event that was triggered by the {@link Tech}.
21497
- *
21498
- * @private
21499
- * @method Player#handleTechLoaddeddata_
21500
- * @fires Player#loadeddata
21501
- * @listens Tech#loadeddata
21502
- */
21503
- 'loadeddata',
21504
-
21505
- /**
21506
- * Fires when the current playback position has changed.
21507
- *
21508
- * @event Player#timeupdate
21509
- * @type {event}
21510
- */
21511
- /**
21512
- * Retrigger the `timeupdate` event that was triggered by the {@link Tech}.
21513
- *
21514
- * @private
21515
- * @method Player#handleTechTimeUpdate_
21516
- * @fires Player#timeupdate
21517
- * @listens Tech#timeupdate
21518
- */
21519
- 'timeupdate',
21520
-
21521
- /**
21522
- * Fires when the video's intrinsic dimensions change
21523
- *
21524
- * @event Player#resize
21525
- * @type {event}
21526
- */
21527
- /**
21528
- * Retrigger the `resize` event that was triggered by the {@link Tech}.
21529
- *
21530
- * @private
21531
- * @method Player#handleTechResize_
21532
- * @fires Player#resize
21533
- * @listens Tech#resize
21534
- */
21535
- 'resize',
21536
-
21537
- /**
21538
- * Fires when the volume has been changed
21539
- *
21540
- * @event Player#volumechange
21541
- * @type {event}
21542
- */
21543
- /**
21544
- * Retrigger the `volumechange` event that was triggered by the {@link Tech}.
21545
- *
21546
- * @private
21547
- * @method Player#handleTechVolumechange_
21548
- * @fires Player#volumechange
21549
- * @listens Tech#volumechange
21550
- */
21551
- 'volumechange',
21552
-
21553
- /**
21554
- * Fires when the text track has been changed
21555
- *
21556
- * @event Player#texttrackchange
21557
- * @type {event}
21558
- */
21559
- /**
21560
- * Retrigger the `texttrackchange` event that was triggered by the {@link Tech}.
21561
- *
21562
- * @private
21563
- * @method Player#handleTechTexttrackchange_
21564
- * @fires Player#texttrackchange
21565
- * @listens Tech#texttrackchange
21566
- */
21567
- 'texttrackchange'];
21568
-
21569
- // events to queue when playback rate is zero
21570
- // this is a hash for the sole purpose of mapping non-camel-cased event names
21571
- // to camel-cased function names
21572
- var TECH_EVENTS_QUEUE = {
21573
- canplay: 'CanPlay',
21574
- canplaythrough: 'CanPlayThrough',
21575
- playing: 'Playing',
21576
- seeked: 'Seeked'
21577
- };
21578
-
21579
- /**
21580
- * An instance of the `Player` class is created when any of the Video.js setup methods
21581
- * are used to initialize a video.
21582
- *
21583
- * After an instance has been created it can be accessed globally in two ways:
21584
- * 1. By calling `videojs('example_video_1');`
21585
- * 2. By using it directly via `videojs.players.example_video_1;`
21586
- *
21587
- * @extends Component
21588
- */
21589
-
21590
- var Player = function (_Component) {
21591
- inherits(Player, _Component);
21592
-
21593
- /**
21594
- * Create an instance of this class.
21595
- *
21596
- * @param {Element} tag
21597
- * The original video DOM element used for configuring options.
21598
- *
21599
- * @param {Object} [options]
21600
- * Object of option names and values.
21601
- *
21602
- * @param {Component~ReadyCallback} [ready]
21603
- * Ready callback function.
21604
- */
21605
- function Player(tag, options, ready) {
21606
- classCallCheck(this, Player);
21607
-
21608
- // Make sure tag ID exists
21609
- tag.id = tag.id || options.id || 'vjs_video_' + newGUID();
21610
-
21611
- // Set Options
21612
- // The options argument overrides options set in the video tag
21613
- // which overrides globally set options.
21614
- // This latter part coincides with the load order
21615
- // (tag must exist before Player)
21616
- options = assign(Player.getTagSettings(tag), options);
21617
-
21618
- // Delay the initialization of children because we need to set up
21619
- // player properties first, and can't use `this` before `super()`
21620
- options.initChildren = false;
21621
-
21622
- // Same with creating the element
21623
- options.createEl = false;
21624
-
21625
- // don't auto mixin the evented mixin
21626
- options.evented = false;
21627
-
21628
- // we don't want the player to report touch activity on itself
21629
- // see enableTouchActivity in Component
21630
- options.reportTouchActivity = false;
21631
-
21632
- // If language is not set, get the closest lang attribute
21633
- if (!options.language) {
21634
- if (typeof tag.closest === 'function') {
21635
- var closest = tag.closest('[lang]');
21636
-
21637
- if (closest && closest.getAttribute) {
21638
- options.language = closest.getAttribute('lang');
21639
- }
21640
- } else {
21641
- var element = tag;
21642
-
21643
- while (element && element.nodeType === 1) {
21644
- if (getAttributes(element).hasOwnProperty('lang')) {
21645
- options.language = element.getAttribute('lang');
21646
- break;
21647
- }
21648
- element = element.parentNode;
21649
- }
21650
- }
21651
- }
21652
-
21653
- // Run base component initializing with new options
21654
-
21655
- // Tracks when a tech changes the poster
21656
- var _this = possibleConstructorReturn(this, _Component.call(this, null, options, ready));
21657
-
21658
- _this.isPosterFromTech_ = false;
21659
-
21660
- // Holds callback info that gets queued when playback rate is zero
21661
- // and a seek is happening
21662
- _this.queuedCallbacks_ = [];
21663
-
21664
- // Turn off API access because we're loading a new tech that might load asynchronously
21665
- _this.isReady_ = false;
21666
-
21667
- // Init state hasStarted_
21668
- _this.hasStarted_ = false;
21669
-
21670
- // Init state userActive_
21671
- _this.userActive_ = false;
21672
-
21673
- // if the global option object was accidentally blown away by
21674
- // someone, bail early with an informative error
21675
- if (!_this.options_ || !_this.options_.techOrder || !_this.options_.techOrder.length) {
21676
- throw new Error('No techOrder specified. Did you overwrite ' + 'videojs.options instead of just changing the ' + 'properties you want to override?');
21677
- }
21678
-
21679
- // Store the original tag used to set options
21680
- _this.tag = tag;
21681
-
21682
- // Store the tag attributes used to restore html5 element
21683
- _this.tagAttributes = tag && getAttributes(tag);
21684
-
21685
- // Update current language
21686
- _this.language(_this.options_.language);
21687
-
21688
- // Update Supported Languages
21689
- if (options.languages) {
21690
- // Normalise player option languages to lowercase
21691
- var languagesToLower = {};
21692
-
21693
- Object.getOwnPropertyNames(options.languages).forEach(function (name$$1) {
21694
- languagesToLower[name$$1.toLowerCase()] = options.languages[name$$1];
21695
- });
21696
- _this.languages_ = languagesToLower;
21697
- } else {
21698
- _this.languages_ = Player.prototype.options_.languages;
21699
- }
21700
-
21701
- // Cache for video property values.
21702
- _this.cache_ = {};
21703
-
21704
- // Set poster
21705
- _this.poster_ = options.poster || '';
21706
-
21707
- // Set controls
21708
- _this.controls_ = !!options.controls;
21709
-
21710
- // Set default values for lastVolume
21711
- _this.cache_.lastVolume = 1;
21712
-
21713
- // Original tag settings stored in options
21714
- // now remove immediately so native controls don't flash.
21715
- // May be turned back on by HTML5 tech if nativeControlsForTouch is true
21716
- tag.controls = false;
21717
- tag.removeAttribute('controls');
21718
-
21719
- // the attribute overrides the option
21720
- if (tag.hasAttribute('autoplay')) {
21721
- _this.options_.autoplay = true;
21722
- } else {
21723
- // otherwise use the setter to validate and
21724
- // set the correct value.
21725
- _this.autoplay(_this.options_.autoplay);
21726
- }
21727
-
21728
- /*
21729
- * Store the internal state of scrubbing
21730
- *
21731
- * @private
21732
- * @return {Boolean} True if the user is scrubbing
21733
- */
21734
- _this.scrubbing_ = false;
21735
-
21736
- _this.el_ = _this.createEl();
21737
-
21738
- // Set default value for lastPlaybackRate
21739
- _this.cache_.lastPlaybackRate = _this.defaultPlaybackRate();
21740
-
21741
- // Make this an evented object and use `el_` as its event bus.
21742
- evented(_this, { eventBusKey: 'el_' });
21743
-
21744
- // We also want to pass the original player options to each component and plugin
21745
- // as well so they don't need to reach back into the player for options later.
21746
- // We also need to do another copy of this.options_ so we don't end up with
21747
- // an infinite loop.
21748
- var playerOptionsCopy = mergeOptions(_this.options_);
21749
-
21750
- // Load plugins
21751
- if (options.plugins) {
21752
- var plugins = options.plugins;
21753
-
21754
- Object.keys(plugins).forEach(function (name$$1) {
21755
- if (typeof this[name$$1] === 'function') {
21756
- this[name$$1](plugins[name$$1]);
21757
- } else {
21758
- throw new Error('plugin "' + name$$1 + '" does not exist');
21759
- }
21760
- }, _this);
21761
- }
21762
-
21763
- _this.options_.playerOptions = playerOptionsCopy;
21764
-
21765
- _this.middleware_ = [];
21766
-
21767
- _this.initChildren();
21768
-
21769
- // Set isAudio based on whether or not an audio tag was used
21770
- _this.isAudio(tag.nodeName.toLowerCase() === 'audio');
21771
-
21772
- // Update controls className. Can't do this when the controls are initially
21773
- // set because the element doesn't exist yet.
21774
- if (_this.controls()) {
21775
- _this.addClass('vjs-controls-enabled');
21776
- } else {
21777
- _this.addClass('vjs-controls-disabled');
21778
- }
21779
-
21780
- // Set ARIA label and region role dep