wai-website-theme 1.3.1 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/different.html +2 -1
  3. data/_includes/external.html +2 -1
  4. data/_includes/header.html +2 -1
  5. data/_includes/menuitem.html +6 -2
  6. data/_includes/peoplelist.html +21 -0
  7. data/_includes/prevnext-navigation.html +56 -0
  8. data/_includes/{prevnext.html → prevnext-order.html} +9 -0
  9. data/_includes/translation-note-msg.html +5 -3
  10. data/_includes/video-player.html +2 -2
  11. data/_layouts/default.html +8 -1
  12. data/_layouts/news.html +7 -1
  13. data/_layouts/policy.html +7 -1
  14. data/_layouts/sidenav.html +8 -1
  15. data/_layouts/sidenavsidebar.html +8 -1
  16. data/assets/ableplayer/Gruntfile.js +2 -1
  17. data/assets/ableplayer/README.md +158 -85
  18. data/assets/ableplayer/build/ableplayer.dist.js +15445 -13823
  19. data/assets/ableplayer/build/ableplayer.js +15445 -13823
  20. data/assets/ableplayer/build/ableplayer.min.css +1 -2
  21. data/assets/ableplayer/build/ableplayer.min.js +3 -10
  22. data/assets/ableplayer/package-lock.json +944 -346
  23. data/assets/ableplayer/package.json +8 -8
  24. data/assets/ableplayer/scripts/ableplayer-base.js +515 -524
  25. data/assets/ableplayer/scripts/browser.js +158 -158
  26. data/assets/ableplayer/scripts/buildplayer.js +1750 -1682
  27. data/assets/ableplayer/scripts/caption.js +424 -401
  28. data/assets/ableplayer/scripts/chapters.js +259 -259
  29. data/assets/ableplayer/scripts/control.js +1831 -1594
  30. data/assets/ableplayer/scripts/description.js +333 -256
  31. data/assets/ableplayer/scripts/dialog.js +145 -145
  32. data/assets/ableplayer/scripts/dragdrop.js +746 -749
  33. data/assets/ableplayer/scripts/event.js +875 -696
  34. data/assets/ableplayer/scripts/initialize.js +819 -912
  35. data/assets/ableplayer/scripts/langs.js +979 -743
  36. data/assets/ableplayer/scripts/metadata.js +124 -124
  37. data/assets/ableplayer/scripts/misc.js +170 -137
  38. data/assets/ableplayer/scripts/preference.js +904 -904
  39. data/assets/ableplayer/scripts/search.js +172 -172
  40. data/assets/ableplayer/scripts/sign.js +82 -78
  41. data/assets/ableplayer/scripts/slider.js +449 -448
  42. data/assets/ableplayer/scripts/track.js +409 -309
  43. data/assets/ableplayer/scripts/transcript.js +684 -595
  44. data/assets/ableplayer/scripts/translation.js +63 -67
  45. data/assets/ableplayer/scripts/ttml2webvtt.js +85 -85
  46. data/assets/ableplayer/scripts/vimeo.js +448 -0
  47. data/assets/ableplayer/scripts/volume.js +395 -380
  48. data/assets/ableplayer/scripts/vts.js +1077 -1077
  49. data/assets/ableplayer/scripts/webvtt.js +766 -763
  50. data/assets/ableplayer/scripts/youtube.js +695 -478
  51. data/assets/ableplayer/styles/ableplayer.css +54 -46
  52. data/assets/ableplayer/translations/nl.js +54 -54
  53. data/assets/ableplayer/translations/pt-br.js +311 -0
  54. data/assets/ableplayer/translations/tr.js +311 -0
  55. data/assets/ableplayer/translations/zh-tw.js +1 -1
  56. data/assets/css/style.css +1 -1
  57. data/assets/css/style.css.map +1 -1
  58. data/assets/images/icons.svg +5 -5
  59. data/assets/scripts/main.js +7 -0
  60. data/assets/search/tipuesearch.js +3 -3
  61. metadata +8 -3
@@ -1,915 +1,822 @@
1
1
  (function ($) {
2
- // Set default variable values.
3
- AblePlayer.prototype.setDefaults = function () {
4
-
5
- this.playing = false; // will change to true after 'playing' event is triggered
6
- this.clickedPlay = false; // will change to true temporarily if user clicks 'play' (or pause)
7
-
8
- this.getUserAgent();
9
- this.setIconColor();
10
- this.setButtonImages();
11
- };
12
-
13
- AblePlayer.prototype.getRootPath = function() {
14
-
15
- // returns Able Player root path (assumes ableplayer.js is in /build, one directory removed from root)
16
- var scripts, i, scriptSrc, scriptFile, fullPath, ablePath, parentFolderIndex, rootPath;
17
- scripts= document.getElementsByTagName('script');
18
- for (i=0; i < scripts.length; i++) {
19
- scriptSrc = scripts[i].src;
20
- scriptFile = scriptSrc.substr(scriptSrc.lastIndexOf('/'));
21
- if (scriptFile.indexOf('ableplayer') !== -1) {
22
- // this is the ableplayerscript
23
- fullPath = scriptSrc.split('?')[0]; // remove any ? params
24
- break;
25
- }
26
- }
27
- ablePath= fullPath.split('/').slice(0, -1).join('/'); // remove last filename part of path
28
- parentFolderIndex = ablePath.lastIndexOf('/');
29
- rootPath = ablePath.substring(0, parentFolderIndex) + '/';
30
- return rootPath;
31
- }
32
-
33
- AblePlayer.prototype.setIconColor = function() {
34
-
35
- // determine the best color choice (white or black) for icons,
36
- // given the background-color of their container elements
37
- // Source for relative luminance formula:
38
- // https://en.wikipedia.org/wiki/Relative_luminance
39
-
40
- // We need to know the color *before* creating the element
41
- // so the element doesn't exist yet when this function is called
42
- // therefore, need to create a temporary element then remove it after color is determined
43
- // Temp element must be added to the DOM or WebKit can't retrieve its CSS properties
44
-
45
- var $elements, i, $el, bgColor, rgb, red, green, blue, luminance, iconColor;
46
-
47
- $elements = ['controller', 'toolbar'];
48
- for (i=0; i<$elements.length; i++) {
49
- if ($elements[i] == 'controller') {
50
- $el = $('<div>', {
51
- 'class': 'able-controller'
52
- }).hide();
53
- }
54
- else if ($elements[i] === 'toolbar') {
55
- $el = $('<div>', {
56
- 'class': 'able-window-toolbar'
57
- }).hide();
58
- }
59
- $('body').append($el);
60
- bgColor = $el.css('background-color');
61
- // bgColor is a string in the form 'rgb(R, G, B)', perhaps with a 4th item for alpha;
62
- // split the 3 or 4 channels into an array
63
- rgb = bgColor.replace(/[^\d,]/g, '').split(',');
64
- red = rgb[0];
65
- green = rgb[1];
66
- blue = rgb[2];
67
- luminance = (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
68
- // range is 1 - 255; therefore 125 is the tipping point
69
- if (luminance < 125) { // background is dark
70
- iconColor = 'white';
71
- }
72
- else { // background is light
73
- iconColor = 'black';
74
- }
75
- if ($elements[i] === 'controller') {
76
- this.iconColor = iconColor;
77
- }
78
- else if ($elements[i] === 'toolbar') {
79
- this.toolbarIconColor = iconColor;
80
- }
81
- $el.remove();
82
- }
83
- };
84
-
85
- AblePlayer.prototype.setButtonImages = function() {
86
-
87
- // NOTE: volume button images are now set dynamically within volume.js
88
- this.imgPath = this.rootPath + 'button-icons/' + this.iconColor + '/';
89
- this.playButtonImg = this.imgPath + 'play.png';
90
- this.pauseButtonImg = this.imgPath + 'pause.png';
91
-
92
- this.restartButtonImg = this.imgPath + 'restart.png';
93
-
94
- this.rewindButtonImg = this.imgPath + 'rewind.png';
95
- this.forwardButtonImg = this.imgPath + 'forward.png';
96
-
97
- this.previousButtonImg = this.imgPath + 'previous.png';
98
- this.nextButtonImg = this.imgPath + 'next.png';
99
-
100
- if (this.speedIcons === 'arrows') {
101
- this.fasterButtonImg = this.imgPath + 'slower.png';
102
- this.slowerButtonImg = this.imgPath + 'faster.png';
103
- }
104
- else if (this.speedIcons === 'animals') {
105
- this.fasterButtonImg = this.imgPath + 'rabbit.png';
106
- this.slowerButtonImg = this.imgPath + 'turtle.png';
107
- }
108
-
109
- this.captionsButtonImg = this.imgPath + 'captions.png';
110
- this.chaptersButtonImg = this.imgPath + 'chapters.png';
111
- this.signButtonImg = this.imgPath + 'sign.png';
112
- this.transcriptButtonImg = this.imgPath + 'transcript.png';
113
- this.descriptionsButtonImg = this.imgPath + 'descriptions.png';
114
-
115
- this.fullscreenExpandButtonImg = this.imgPath + 'fullscreen-expand.png';
116
- this.fullscreenCollapseButtonImg = this.imgPath + 'fullscreen-collapse.png';
117
-
118
- this.prefsButtonImg = this.imgPath + 'preferences.png';
119
- this.helpButtonImg = this.imgPath + 'help.png';
120
- };
121
-
122
- AblePlayer.prototype.getSvgData = function(button) {
123
-
124
- // returns array of values for creating <svg> tag for specified button
125
- // 0 = <svg> viewBox attribute
126
- // 1 = <path> d (description) attribute
127
- var svg = Array();
128
-
129
- switch (button) {
130
-
131
- case 'play':
132
- svg[0] = '0 0 16 20';
133
- svg[1] = 'M0 18.393v-16.429q0-0.29 0.184-0.402t0.441 0.033l14.821 8.237q0.257 0.145 0.257 0.346t-0.257 0.346l-14.821 8.237q-0.257 0.145-0.441 0.033t-0.184-0.402z';
134
- break;
135
-
136
- case 'pause':
137
- svg[0] = '0 0 20 20';
138
- svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502zM10 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502z';
139
- break;
140
-
141
- case 'stop':
142
- svg[0] = '0 0 20 20';
143
- svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h15.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-15.714q-0.29 0-0.502-0.212t-0.212-0.502z';
144
- break;
145
-
146
- case 'restart':
147
- svg[0] = '0 0 20 20';
148
- svg[1] = 'M18 8h-6l2.243-2.243c-1.133-1.133-2.64-1.757-4.243-1.757s-3.109 0.624-4.243 1.757c-1.133 1.133-1.757 2.64-1.757 4.243s0.624 3.109 1.757 4.243c1.133 1.133 2.64 1.757 4.243 1.757s3.109-0.624 4.243-1.757c0.095-0.095 0.185-0.192 0.273-0.292l1.505 1.317c-1.466 1.674-3.62 2.732-6.020 2.732-4.418 0-8-3.582-8-8s3.582-8 8-8c2.209 0 4.209 0.896 5.656 2.344l2.344-2.344v6z';
149
- break;
150
-
151
- case 'rewind':
152
- svg[0] = '0 0 20 20';
153
- svg[1] = 'M11.25 3.125v6.25l6.25-6.25v13.75l-6.25-6.25v6.25l-6.875-6.875z';
154
- break;
155
-
156
- case 'forward':
157
- svg[0] = '0 0 20 20';
158
- svg[1] = 'M10 16.875v-6.25l-6.25 6.25v-13.75l6.25 6.25v-6.25l6.875 6.875z';
159
- break;
160
-
161
- case 'previous':
162
- svg[0] = '0 0 20 20';
163
- svg[1] = 'M5 17.5v-15h2.5v6.875l6.25-6.25v13.75l-6.25-6.25v6.875z';
164
- break;
165
-
166
- case 'next':
167
- svg[0] = '0 0 20 20';
168
- svg[1] = 'M15 2.5v15h-2.5v-6.875l-6.25 6.25v-13.75l6.25 6.25v-6.875z';
169
- break;
170
-
171
- case 'slower':
172
- svg[0] = '0 0 20 20';
173
- svg[1] = 'M0 7.321q0-0.29 0.212-0.502t0.502-0.212h10q0.29 0 0.502 0.212t0.212 0.502-0.212 0.502l-5 5q-0.212 0.212-0.502 0.212t-0.502-0.212l-5-5q-0.212-0.212-0.212-0.502z';
174
- break;
175
-
176
- case 'faster':
177
- svg[0] = '0 0 11 20';
178
- svg[1] = 'M0 12.411q0-0.29 0.212-0.502l5-5q0.212-0.212 0.502-0.212t0.502 0.212l5 5q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-10q-0.29 0-0.502-0.212t-0.212-0.502z';
179
- break;
180
-
181
- case 'turtle':
182
- svg[0] = '0 0 20 20';
183
- svg[1] = 'M17.212 3.846c-0.281-0.014-0.549 0.025-0.817 0.144-1.218 0.542-1.662 2.708-2.163 3.942-1.207 2.972-7.090 4.619-11.755 5.216-0.887 0.114-1.749 0.74-2.428 1.466 0.82-0.284 2.126-0.297 2.74 0.144 0.007 0.488-0.376 1.062-0.625 1.37-0.404 0.5-0.398 0.793 0.12 0.793 0.473 0 0.752 0.007 1.635 0 0.393-0.003 0.618-0.16 1.49-1.49 3.592 0.718 5.986-0.264 5.986-0.264s0.407 1.755 1.418 1.755h1.49c0.633 0 0.667-0.331 0.625-0.433-0.448-1.082-0.68-1.873-0.769-2.5-0.263-1.857 0.657-3.836 2.524-5.457 0.585 0.986 2.253 0.845 2.909-0.096s0.446-2.268-0.192-3.221c-0.49-0.732-1.345-1.327-2.188-1.37zM8.221 4.663c-0.722-0.016-1.536 0.111-2.5 0.409-4.211 1.302-4.177 4.951-3.51 5.745 0 0-0.955 0.479-0.409 1.274 0.448 0.652 3.139 0.191 5.409-0.529s4.226-1.793 5.312-2.692c0.948-0.785 0.551-2.106-0.505-1.947-0.494-0.98-1.632-2.212-3.798-2.26zM18.846 5.962c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577z';
184
- break;
185
-
186
- case 'rabbit':
187
- svg[0] = '0 0 20 20';
188
- svg[1] = 'M10.817 0c-2.248 0-1.586 0.525-1.154 0.505 1.551-0.072 5.199 0.044 6.851 2.428 0 0-1.022-2.933-5.697-2.933zM10.529 0.769c-2.572 0-2.837 0.51-2.837 1.106 0 0.545 1.526 0.836 2.524 0.697 2.778-0.386 4.231-0.12 5.264 0.865-1.010 0.779-0.75 1.401-1.274 1.851-1.093 0.941-2.643-0.673-4.976-0.673-2.496 0-4.712 1.92-4.712 4.76-0.157-0.537-0.769-0.913-1.442-0.913-0.974 0-1.514 0.637-1.514 1.49 0 0.769 1.13 1.791 2.861 0.938 0.499 1.208 2.265 1.364 2.452 1.418 0.538 0.154 1.875 0.098 1.875 0.865 0 0.794-1.034 1.094-1.034 1.707 0 1.070 1.758 0.873 2.284 1.034 1.683 0.517 2.103 1.214 2.788 2.212 0.771 1.122 2.572 1.408 2.572 0.625 0-3.185-4.413-4.126-4.399-4.135 0.608-0.382 2.139-1.397 2.139-3.534 0-1.295-0.703-2.256-1.755-2.861 1.256 0.094 2.572 1.205 2.572 2.74 0 1.877-0.653 2.823-0.769 2.957 1.975-1.158 3.193-3.91 3.029-6.37 0.61 0.401 1.27 0.577 1.971 0.625 0.751 0.052 1.475-0.225 1.635-0.529 0.38-0.723 0.162-2.321-0.12-2.837-0.763-1.392-2.236-1.73-3.606-1.683-1.202-1.671-3.812-2.356-5.529-2.356zM1.37 3.077l-0.553 1.538h3.726c0.521-0.576 1.541-1.207 2.284-1.538h-5.457zM18.846 5.192c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577zM0.553 5.385l-0.553 1.538h3.197c0.26-0.824 0.586-1.328 0.769-1.538h-3.413z';
189
- break;
190
-
191
- case 'ellipsis':
192
- svg[0] = '0 0 20 20';
193
- svg[1] = 'M10.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2zM3.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.986 2.199-2.2s-0.984-2.2-2.199-2.2zM17.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2z';
194
- break;
195
-
196
- case 'pipe':
197
- svg[0] = '0 0 20 20';
198
- svg[1] = 'M10.15 0.179h0.623c0.069 0 0.127 0.114 0.127 0.253v19.494c0 0.139-0.057 0.253-0.127 0.253h-1.247c-0.069 0-0.126-0.114-0.126-0.253v-19.494c0-0.139 0.057-0.253 0.126-0.253h0.623z';
199
- break;
200
-
201
- case 'captions':
202
- svg[0] = '0 0 20 20';
203
- svg[1] = 'M0.033 3.624h19.933v12.956h-19.933v-12.956zM18.098 10.045c-0.025-2.264-0.124-3.251-0.743-3.948-0.112-0.151-0.322-0.236-0.496-0.344-0.606-0.386-3.465-0.526-6.782-0.526s-6.313 0.14-6.907 0.526c-0.185 0.108-0.396 0.193-0.519 0.344-0.607 0.697-0.693 1.684-0.731 3.948 0.037 2.265 0.124 3.252 0.731 3.949 0.124 0.161 0.335 0.236 0.519 0.344 0.594 0.396 3.59 0.526 6.907 0.547 3.317-0.022 6.176-0.151 6.782-0.547 0.174-0.108 0.384-0.183 0.496-0.344 0.619-0.697 0.717-1.684 0.743-3.949v0 0zM9.689 9.281c-0.168-1.77-1.253-2.813-3.196-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.442-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.977zM16.607 9.281c-0.167-1.77-1.252-2.813-3.194-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.441-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.976z';
204
- break;
205
-
206
- case 'descriptions':
207
- svg[0] = '0 0 20 20';
208
- svg[1] = 'M17.623 3.57h-1.555c1.754 1.736 2.763 4.106 2.763 6.572 0 2.191-0.788 4.286-2.189 5.943h1.484c1.247-1.704 1.945-3.792 1.945-5.943-0-2.418-0.886-4.754-2.447-6.572v0zM14.449 3.57h-1.55c1.749 1.736 2.757 4.106 2.757 6.572 0 2.191-0.788 4.286-2.187 5.943h1.476c1.258-1.704 1.951-3.792 1.951-5.943-0-2.418-0.884-4.754-2.447-6.572v0zM11.269 3.57h-1.542c1.752 1.736 2.752 4.106 2.752 6.572 0 2.191-0.791 4.286-2.181 5.943h1.473c1.258-1.704 1.945-3.792 1.945-5.943 0-2.418-0.876-4.754-2.447-6.572v0zM10.24 9.857c0 3.459-2.826 6.265-6.303 6.265v0.011h-3.867v-12.555h3.896c3.477 0 6.274 2.806 6.274 6.279v0zM6.944 9.857c0-1.842-1.492-3.338-3.349-3.338h-0.876v6.686h0.876c1.858 0 3.349-1.498 3.349-3.348v0z';
209
- break;
210
-
211
- case 'sign':
212
- svg[0] = '0 0 20 20';
213
- svg[1] = 'M10.954 10.307c0.378 0.302 0.569 1.202 0.564 1.193 0.697 0.221 1.136 0.682 1.136 0.682 1.070-0.596 1.094-0.326 1.558-0.682 0.383-0.263 0.366-0.344 0.567-1.048 0.187-0.572-0.476-0.518-1.021-1.558-0.95 0.358-1.463 0.196-1.784 0.167-0.145-0.020-0.12 0.562-1.021 1.247zM14.409 17.196c-0.133 0.182-0.196 0.218-0.363 0.454-0.28 0.361 0.076 0.906 0.253 0.82 0.206-0.076 0.341-0.488 0.567-0.623 0.115-0.061 0.422-0.513 0.709-0.82 0.211-0.238 0.363-0.344 0.564-0.594 0.341-0.422 0.412-0.744 0.709-1.193 0.184-0.236 0.312-0.307 0.481-0.594 0.886-1.679 0.628-2.432 1.475-3.629 0.26-0.353 0.552-0.442 0.964-0.653 0.383-2.793-0.888-4.356-0.879-4.361-1.067 0.623-1.644 0.879-2.751 0.82-0.417-0.005-0.636-0.182-1.048-0.145-0.385 0.015-0.582 0.159-0.964 0.29-0.589 0.182-0.91 0.344-1.529 0.535-0.393 0.11-0.643 0.115-1.050 0.255-0.348 0.147-0.182 0.029-0.427 0.312-0.317 0.348-0.238 0.623-0.535 1.222-0.371 0.785-0.326 0.891-0.115 0.987-0.14 0.402-0.174 0.672-0.14 1.107 0.039 0.331-0.101 0.562 0.255 0.825 0.483 0.361 1.499 1.205 1.757 1.217 0.39-0.012 1.521 0.029 2.096-0.368 0.13-0.081 0.167-0.162 0.056 0.145-0.022 0.037-1.433 1.136-1.585 1.131-1.794 0.056-1.193 0.157-1.303 0.115-0.091 0-0.955-1.055-1.477-0.682-0.196 0.12-0.287 0.236-0.363 0.452 0.066 0.137 0.383 0.358 0.675 0.54 0.422 0.27 0.461 0.552 0.881 0.653 0.513 0.115 1.060 0.039 1.387 0.081 0.125 0.034 1.256-0.297 1.961-0.675 0.65-0.336-0.898 0.648-1.276 1.131-1.141 0.358-0.82 0.373-1.362 0.483-0.503 0.115-0.479 0.086-0.822 0.196-0.356 0.086-0.648 0.572-0.312 0.825 0.201 0.167 0.827-0.066 1.445-0.086 0.275-0.005 1.391-0.518 1.644-0.653 0.633-0.339 1.099-0.81 1.472-1.077 0.518-0.361-0.584 0.991-1.050 1.558zM8.855 9.799c-0.378-0.312-0.569-1.212-0.564-1.217-0.697-0.206-1.136-0.667-1.136-0.653-1.070 0.582-1.099 0.312-1.558 0.653-0.388 0.277-0.366 0.363-0.567 1.045-0.187 0.594 0.471 0.535 1.021 1.561 0.95-0.344 1.463-0.182 1.784-0.142 0.145 0.010 0.12-0.572 1.021-1.247zM5.4 2.911c0.133-0.191 0.196-0.228 0.368-0.454 0.27-0.371-0.081-0.915-0.253-0.849-0.211 0.096-0.346 0.508-0.599 0.653-0.093 0.052-0.4 0.503-0.682 0.82-0.211 0.228-0.363 0.334-0.564 0.599-0.346 0.407-0.412 0.729-0.709 1.161-0.184 0.258-0.317 0.324-0.481 0.621-0.886 1.669-0.631 2.422-1.475 3.6-0.26 0.38-0.552 0.461-0.964 0.682-0.383 2.788 0.883 4.346 0.879 4.336 1.068-0.609 1.639-0.861 2.751-0.825 0.417 0.025 0.636 0.201 1.048 0.174 0.385-0.025 0.582-0.169 0.964-0.285 0.589-0.196 0.91-0.358 1.499-0.54 0.422-0.12 0.672-0.125 1.080-0.285 0.348-0.128 0.182-0.010 0.427-0.282 0.312-0.358 0.238-0.633 0.508-1.217 0.398-0.8 0.353-0.906 0.142-0.991 0.135-0.412 0.174-0.677 0.14-1.107-0.044-0.336 0.101-0.572-0.255-0.82-0.483-0.375-1.499-1.22-1.752-1.222-0.395 0.002-1.526-0.039-2.101 0.339-0.13 0.101-0.167 0.182-0.056-0.11 0.022-0.052 1.433-1.148 1.585-1.163 1.794-0.039 1.193-0.14 1.303-0.088 0.091-0.007 0.955 1.045 1.477 0.682 0.191-0.13 0.287-0.245 0.368-0.452-0.071-0.147-0.388-0.368-0.68-0.537-0.422-0.282-0.464-0.564-0.881-0.655-0.513-0.125-1.065-0.049-1.387-0.11-0.125-0.015-1.256 0.317-1.956 0.68-0.66 0.351 0.893-0.631 1.276-1.136 1.136-0.339 0.81-0.353 1.36-0.479 0.501-0.101 0.476-0.071 0.82-0.172 0.351-0.096 0.648-0.577 0.312-0.849-0.206-0.152-0.827 0.081-1.44 0.086-0.28 0.020-1.396 0.533-1.649 0.677-0.633 0.329-1.099 0.8-1.472 1.048-0.523 0.38 0.584-0.967 1.050-1.529z';
214
- break;
215
-
216
- case 'mute':
217
- svg[0] = '0 0 20 20';
218
- svg[1] = 'M7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714zM18.75 12.093v1.657h-1.657l-2.093-2.093-2.093 2.093h-1.657v-1.657l2.093-2.093-2.093-2.093v-1.657h1.657l2.093 2.093 2.093-2.093h1.657v1.657l-2.093 2.093z';
219
- break;
220
-
221
- case 'volume-mute':
222
- svg[0] = '0 0 20 20';
223
- svg[1] = 'M10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
224
- break;
225
-
226
- case 'volume-medium':
227
- svg[0] = '0 0 20 20';
228
- svg[1] = 'M14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
229
- break;
230
-
231
- case 'volume-loud':
232
- svg[0] = '0 0 21 20';
233
- svg[1] = 'M17.384 18.009c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.712-1.712 2.654-3.988 2.654-6.408s-0.943-4.696-2.654-6.408c-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.066 2.066 3.204 4.813 3.204 7.734s-1.138 5.668-3.204 7.734c-0.183 0.183-0.423 0.275-0.663 0.275zM14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
234
- break;
235
-
236
- case 'chapters':
237
- svg[0] = '0 0 20 20';
238
- svg[1] = 'M5 2.5v17.5l6.25-6.25 6.25 6.25v-17.5zM15 0h-12.5v17.5l1.25-1.25v-15h11.25z';
239
- break;
240
-
241
- case 'transcript':
242
- svg[0] = '0 0 20 20';
243
- svg[1] = 'M0 19.107v-17.857q0-0.446 0.313-0.759t0.759-0.313h8.929v6.071q0 0.446 0.313 0.759t0.759 0.313h6.071v11.786q0 0.446-0.313 0.759t-0.759 0.312h-15q-0.446 0-0.759-0.313t-0.313-0.759zM4.286 15.536q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 12.679q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 9.821q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM11.429 5.893v-5.268q0.246 0.156 0.402 0.313l4.554 4.554q0.156 0.156 0.313 0.402h-5.268z';
244
- break;
245
-
246
- case 'preferences':
247
- svg[0] = '0 0 20 20';
248
- svg[1] = 'M18.238 11.919c-1.049-1.817-0.418-4.147 1.409-5.205l-1.965-3.404c-0.562 0.329-1.214 0.518-1.911 0.518-2.1 0-3.803-1.714-3.803-3.828h-3.931c0.005 0.653-0.158 1.314-0.507 1.919-1.049 1.818-3.382 2.436-5.212 1.382l-1.965 3.404c0.566 0.322 1.056 0.793 1.404 1.396 1.048 1.815 0.42 4.139-1.401 5.2l1.965 3.404c0.56-0.326 1.209-0.513 1.902-0.513 2.094 0 3.792 1.703 3.803 3.808h3.931c-0.002-0.646 0.162-1.3 0.507-1.899 1.048-1.815 3.375-2.433 5.203-1.387l1.965-3.404c-0.562-0.322-1.049-0.791-1.395-1.391zM10 14.049c-2.236 0-4.050-1.813-4.050-4.049s1.813-4.049 4.050-4.049 4.049 1.813 4.049 4.049c-0 2.237-1.813 4.049-4.049 4.049z';
249
- break;
250
-
251
- case 'close':
252
- svg[0] = '0 0 16 20';
253
- svg[1] = 'M1.228 14.933q0-0.446 0.312-0.759l3.281-3.281-3.281-3.281q-0.313-0.313-0.313-0.759t0.313-0.759l1.518-1.518q0.313-0.313 0.759-0.313t0.759 0.313l3.281 3.281 3.281-3.281q0.313-0.313 0.759-0.313t0.759 0.313l1.518 1.518q0.313 0.313 0.313 0.759t-0.313 0.759l-3.281 3.281 3.281 3.281q0.313 0.313 0.313 0.759t-0.313 0.759l-1.518 1.518q-0.313 0.313-0.759 0.313t-0.759-0.313l-3.281-3.281-3.281 3.281q-0.313 0.313-0.759 0.313t-0.759-0.313l-1.518-1.518q-0.313-0.313-0.313-0.759z';
254
- break;
255
-
256
- case 'fullscreen-expand':
257
- svg[0] = '0 0 20 20';
258
- svg[1] = 'M0 18.036v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502zM8.717 8.393q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257z';
259
- break;
260
-
261
- case 'fullscreen-collapse':
262
- svg[0] = '0 0 20 20';
263
- svg[1] = 'M0.145 16.964q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257zM8.571 9.464v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502z';
264
- break;
265
-
266
- case 'help':
267
- svg[0] = '0 0 11 20';
268
- svg[1] = 'M0.577 6.317q-0.028-0.167 0.061-0.313 1.786-2.969 5.179-2.969 0.893 0 1.797 0.346t1.629 0.926 1.183 1.423 0.458 1.769q0 0.603-0.173 1.127t-0.391 0.854-0.614 0.664-0.642 0.485-0.681 0.396q-0.458 0.257-0.765 0.725t-0.307 0.748q0 0.19-0.134 0.363t-0.313 0.173h-2.679q-0.167 0-0.285-0.206t-0.117-0.419v-0.502q0-0.926 0.725-1.747t1.596-1.211q0.658-0.301 0.938-0.625t0.279-0.848q0-0.469-0.519-0.826t-1.2-0.357q-0.725 0-1.205 0.324-0.391 0.279-1.194 1.283-0.145 0.179-0.346 0.179-0.134 0-0.279-0.089l-1.83-1.395q-0.145-0.112-0.173-0.279zM3.786 16.875v-2.679q0-0.179 0.134-0.313t0.313-0.134h2.679q0.179 0 0.313 0.134t0.134 0.313v2.679q0 0.179-0.134 0.313t-0.313 0.134h-2.679q-0.179 0-0.313-0.134t-0.134-0.313z';
269
- break;
270
- }
271
-
272
- return svg;
273
- };
274
-
275
- // Initialize player based on data on page.
276
- // This sets some variables, but does not modify anything. Safe to call multiple times.
277
- // Can call again after updating this.media so long as new media element has the same ID.
278
- AblePlayer.prototype.reinitialize = function () {
279
-
280
- var deferred, promise, thisObj, errorMsg, srcFile;
281
-
282
- deferred = new $.Deferred();
283
- promise = deferred.promise();
284
- thisObj = this;
285
-
286
- // if F12 Developer Tools aren't open in IE (through 9, no longer a problen in IE10)
287
- // console.log causes an error - can't use debug without a console to log messages to
288
- if (! window.console) {
289
- this.debug = false;
290
- }
291
-
292
- this.startedPlaying = false;
293
- // TODO: Move this setting to cookie.
294
- this.autoScrollTranscript = true;
295
- //this.autoScrollTranscript = this.getCookie(autoScrollTranscript); // (doesn't work)
296
-
297
- // Bootstrap from this.media possibly being an ID or other selector.
298
- this.$media = $(this.media).first();
299
- this.media = this.$media[0];
300
-
301
- // Set media type to 'audio' or 'video'; this determines some of the behavior of player creation.
302
- if (this.$media.is('audio')) {
303
- this.mediaType = 'audio';
304
- }
305
- else if (this.$media.is('video')) {
306
- this.mediaType = 'video';
307
- }
308
- else {
309
- // Able Player was initialized with some element other than <video> or <audio>
310
- this.provideFallback();
311
- deferred.fail();
312
- return promise;
313
- }
314
-
315
- this.$sources = this.$media.find('source');
316
-
317
- this.player = this.getPlayer();
318
- if (!this.player) {
319
- // an error was generated in getPlayer()
320
- this.provideFallback();
321
- }
322
- this.setIconType();
323
- this.setDimensions();
324
-
325
- deferred.resolve();
326
- return promise;
327
- };
328
-
329
- AblePlayer.prototype.setDimensions = function() {
330
- // if media element includes width and height attributes,
331
- // use these to set the max-width and max-height of the player
332
- if (this.$media.attr('width') && this.$media.attr('height')) {
333
- this.playerMaxWidth = parseInt(this.$media.attr('width'), 10);
334
- this.playerMaxHeight = parseInt(this.$media.attr('height'), 10);
335
- }
336
- else if (this.$media.attr('width')) {
337
- // media element includes a width attribute, but not height
338
- this.playerMaxWidth = parseInt(this.$media.attr('width'), 10);
339
- }
340
- else {
341
- // set width to width of #player
342
- // don't set height though; YouTube will automatically set that to match width
343
- this.playerMaxWidth = this.$media.parent().width();
344
- this.playerMaxHeight = this.getMatchingHeight(this.playerMaxWidth);
345
- }
346
- // override width and height attributes with in-line CSS to make video responsive
347
- this.$media.css({
348
- 'width': '100%',
349
- 'height': 'auto'
350
- });
351
- };
352
-
353
- AblePlayer.prototype.getMatchingHeight = function(width) {
354
-
355
- // returns likely height for a video, given width
356
- // These calculations assume 16:9 aspect ratio (the YouTube standard)
357
- // Videos recorded in other resolutions will be sized to fit, with black bars on each side
358
- // This function is only called if the <video> element does not have width and height attributes
359
-
360
- var widths, heights, closestWidth, closestIndex, closestHeight, height;
361
-
362
- widths = [ 3840, 2560, 1920, 1280, 854, 640, 426 ];
363
- heights = [ 2160, 1440, 1080, 720, 480, 360, 240 ];
364
- closestWidth = null;
365
- closestIndex = null;
366
-
367
- $.each(widths, function(index){
368
- if (closestWidth == null || Math.abs(this - width) < Math.abs(closestWidth - width)) {
369
- closestWidth = this;
370
- closestIndex = index;
371
- }
372
- });
373
- closestHeight = heights[closestIndex];
374
- this.aspectRatio = closestWidth / closestHeight;
375
- height = Math.round(width / this.aspectRatio);
376
- return height;
377
- };
378
-
379
- AblePlayer.prototype.setIconType = function() {
380
-
381
- // returns either "svg", "font" or "image" (in descending order of preference)
382
- // Test for support of each type. If not supported, test the next type.
383
- // last resort is image icons
384
-
385
- var $tempButton, $testButton, controllerFont;
386
-
387
- if (this.forceIconType) {
388
- // use value specified in data-icon-type
389
- return false;
390
- }
391
-
392
- // test for SVG support
393
- // Test this method widely; failed as expected on IE8 and below
394
- // https://stackoverflow.com/a/27568129/744281
395
- if (!!(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect)) {
396
- // browser supports SVG
397
- this.iconType = 'svg';
398
- }
399
- else {
400
- // browser does NOT support SVG
401
- // test whether browser can support icon fonts, and whether user has overriding the default style sheet
402
- // which could cause problems with proper display of the icon fonts
403
- if (window.getComputedStyle) {
404
-
405
- // webkit doesn't return calculated styles unless element has been added to the DOM
406
- // and is visible (note: visibly clipped is considered "visible")
407
- // use playpauseButton for font-family test if it exists; otherwise must create a new temp button
408
- if ($('span.icon-play').length) {
409
- $testButton = $('span.icon-play');
410
- }
411
- else {
412
- $tempButton = $('<span>',{
413
- 'class': 'icon-play able-clipped'
414
- });
415
- $('body').append($tempButton);
416
- $testButton = $tempButton;
417
- }
418
-
419
- // the following retrieves the computed value of font-family
420
- // tested in Firefox 45.x with "Allow pages to choose their own fonts" unchecked - works!
421
- // tested in Chrome 49.x with Font Changer plugin - works!
422
- // tested in IE with user-defined style sheet enables - works!
423
- // It does NOT account for users who have "ignore font styles on web pages" checked in IE
424
- // There is no known way to check for that ???
425
- controllerFont = window.getComputedStyle($testButton.get(0), null).getPropertyValue('font-family');
426
- if (typeof controllerFont !== 'undefined') {
427
- if (controllerFont.indexOf('able') !== -1) {
428
- this.iconType = 'font';
429
- }
430
- else {
431
- this.iconType = 'image';
432
- }
433
- }
434
- else {
435
- // couldn't get computed font-family; use images to be safe
436
- this.iconType = 'image';
437
- }
438
- }
439
- else { // window.getComputedStyle is not supported (IE 8 and earlier)
440
- // No known way to detect computed font
441
- // The following retrieves the value from the style sheet, not the computed font
442
- // controllerFont = $tempButton.get(0).currentStyle.fontFamily;
443
- // It will therefore return "able", even if the user is overriding that with a custom style sheet
444
- // To be safe, use images
445
- this.iconType = 'image';
446
- }
447
- if (this.debug) {
448
- console.log('Using ' + this.iconType + 's for player controls');
449
- }
450
- if (typeof $tempButton !== 'undefined') {
451
- $tempButton.remove();
452
- }
453
- }
454
- };
455
-
456
- // Perform one-time setup for this instance of player; called after player is first initialized.
457
- AblePlayer.prototype.setupInstance = function () {
458
- var deferred = new $.Deferred();
459
- var promise = deferred.promise();
460
-
461
- if (this.$media.attr('id')) {
462
- this.mediaId = this.$media.attr('id');
463
- }
464
- else {
465
- // Ensure the base media element always has an ID.
466
- this.mediaId = "ableMediaId_" + this.ableIndex;
467
- this.$media.attr('id', this.mediaId);
468
- }
469
- // get playlist for this media element
470
- this.setupInstancePlaylist();
471
-
472
- deferred.resolve();
473
- return promise;
474
- };
475
-
476
- AblePlayer.prototype.setupInstancePlaylist = function() {
477
- // find a matching playlist and set this.hasPlaylist
478
- // if there is one, also set this.$playlist, this.playlistIndex, & this.playlistEmbed
479
- var thisObj = this;
480
-
481
- this.hasPlaylist = false; // will change to true if a matching playlist is found
482
-
483
- $('.able-playlist').each(function() {
484
- if ($(this).data('player') === thisObj.mediaId) {
485
- // this is the playlist for the current player
486
- thisObj.hasPlaylist = true;
487
- // If using an embedded player, we'll replace $playlist with the clone later.
488
- thisObj.$playlist = $(this).find('li');
489
- // add tabindex to each list item
490
- $(this).find('li').attr('tabindex', '0');
491
- thisObj.playlistIndex = 0;
492
- var dataEmbedded = $(this).data('embedded');
493
- if (typeof dataEmbedded !== 'undefined' && dataEmbedded !== false) {
494
- // embed playlist within player
495
- thisObj.playlistEmbed = true;
496
- }
497
- else {
498
- thisObj.playlistEmbed = false;
499
- }
500
- }
501
- });
502
-
503
- if (this.hasPlaylist && this.loop) {
504
- // browser will loop the current track in the playlist, rather than the playlist
505
- // therefore, need to remove loop attribute from media element
506
- // but keep this.loop as true and handle the playlist looping ourselves
507
- this.media.removeAttribute('loop');
508
- }
509
-
510
- if (this.hasPlaylist && this.playlistEmbed) {
511
- // Copy the playlist out of the dom, so we can reinject when we build the player.
512
- var parent = this.$playlist.parent();
513
- this.$playlistDom = parent.clone();
514
- parent.remove();
515
- }
516
- };
517
-
518
- // Creates the appropriate player for the current source.
519
- AblePlayer.prototype.recreatePlayer = function () {
520
- var thisObj, prefsGroups, i;
521
- thisObj = this;
522
-
523
- // TODO: Ensure when recreating player that we carry over the mediaId
524
- if (!this.player) {
525
- console.log("Can't create player; no appropriate player type detected.");
526
- return;
527
- }
528
-
529
- this.loadCurrentPreferences();
530
-
531
- this.injectPlayerCode();
532
- this.initSignLanguage();
533
- this.setupTracks().then(function() {
534
-
535
- thisObj.setupAltCaptions().then(function() {
536
-
537
- if (thisObj.transcriptType === 'external' || thisObj.transcriptType === 'popup') {
538
- if (thisObj.captions.length <= 1) {
539
- // without captions/subtitles in multiple languages,
540
- // there is no need for a transcript language selector
541
- thisObj.$transcriptLanguageSelect.parent().remove();
542
- }
543
- }
544
-
545
- thisObj.initDescription();
546
- thisObj.initDefaultCaption();
547
-
548
- thisObj.initPlayer().then(function() { // initPlayer success
549
- thisObj.initializing = false;
550
-
551
- // setMediaAttributes() sets textTrack.mode to 'disabled' for all tracks
552
- // This tells browsers to ignore the text tracks so Able Player can handle them
553
- // However, timing is critical as browsers - especially Safari - tend to ignore this request
554
- // unless it's sent late in the intialization process.
555
- // If browsers ignore the request, the result is redundant captions
556
- thisObj.setMediaAttributes();
557
-
558
- // inject each of the hidden forms that will be accessed from the Preferences popup menu
559
- prefsGroups = thisObj.getPreferencesGroups();
560
- for (i = 0; i < prefsGroups.length; i++) {
561
- thisObj.injectPrefsForm(prefsGroups[i]);
562
- }
563
- thisObj.setupPopups();
564
- thisObj.updateCaption();
565
- thisObj.updateTranscript();
566
- thisObj.injectVTS();
567
- if (thisObj.chaptersDivLocation) {
568
- thisObj.populateChaptersDiv();
569
- }
570
- thisObj.showSearchResults();
571
- },
572
- function() { // initPlayer fail
573
- thisObj.provideFallback();
574
- }
575
- );
576
- });
577
- });
578
- };
579
-
580
- AblePlayer.prototype.initPlayer = function () {
581
-
582
- var thisObj = this;
583
- var playerPromise;
584
-
585
- // First run player specific initialization.
586
- if (this.player === 'html5') {
587
- playerPromise = this.initHtml5Player();
588
- }
589
- else if (this.player === 'jw') {
590
- playerPromise = this.initJwPlayer();
591
- }
592
- else if (this.player === 'youtube') {
593
- playerPromise = this.initYouTubePlayer();
594
- }
595
-
596
- // After player specific initialization is done, run remaining general initialization.
597
- var deferred = new $.Deferred();
598
- var promise = deferred.promise();
599
- playerPromise.done(
600
- function () { // done/resolved
601
- if (thisObj.useFixedSeekInterval === false) {
602
- thisObj.setSeekInterval();
603
- }
604
- thisObj.addControls();
605
- thisObj.addEventListeners();
606
- // Calling these set functions also initializes some icons.
607
- if (thisObj.Volume) {
608
- thisObj.setMute(false);
609
- }
610
- thisObj.setFullscreen(false);
611
- thisObj.setVolume(thisObj.defaultVolume);
612
- thisObj.refreshControls();
613
-
614
- // Go ahead and load media, without user requesting it
615
- // Normally, we wait until user clicks play, rather than unnecessarily consume their bandwidth
616
- // Exceptions are if the video is intended to autostart or if running on iOS (a workaround for iOS issues)
617
- // TODO: Confirm that this is still necessary with iOS (this would added early, & I don't remember what the issues were)
618
- if (thisObj.player === 'html5' && (thisObj.isIOS() || thisObj.startTime > 0 || thisObj.autoplay)) {
619
- thisObj.$media[0].load();
620
- }
621
- deferred.resolve();
622
- }
623
- ).fail(function () { // failed
624
- deferred.reject();
625
- }
626
- );
627
-
628
- return promise;
629
- };
630
-
631
- AblePlayer.prototype.setSeekInterval = function () {
632
- // this function is only called if this.useFixedSeekInterval is false
633
- // if this.useChapterTimes, this is called as each new chapter is loaded
634
- // otherwise, it's called once, as the player is initialized
635
- var duration;
636
- this.seekInterval = this.defaultSeekInterval;
637
- if (this.useChapterTimes) {
638
- duration = this.chapterDuration;
639
- }
640
- else {
641
- duration = this.getDuration();
642
- }
643
- if (typeof duration === 'undefined' || duration < 1) {
644
- // no duration; just use default for now but keep trying until duration is available
645
- this.seekIntervalCalculated = false;
646
- return;
647
- }
648
- else {
649
- if (duration <= 20) {
650
- this.seekInterval = 5; // 4 steps max
651
- }
652
- else if (duration <= 30) {
653
- this.seekInterval = 6; // 5 steps max
654
- }
655
- else if (duration <= 40) {
656
- this.seekInterval = 8; // 5 steps max
657
- }
658
- else if (duration <= 100) {
659
- this.seekInterval = 10; // 10 steps max
660
- }
661
- else {
662
- // never more than 10 steps from start to end
663
- this.seekInterval = (duration / 10);
664
- }
665
- this.seekIntervalCalculated = true;
666
- }
667
- };
668
-
669
- AblePlayer.prototype.initDefaultCaption = function () {
670
-
671
- var captions, i;
672
-
673
- if (this.usingYouTubeCaptions) {
674
- captions = this.ytCaptions;
675
- }
676
- else {
677
- captions = this.captions;
678
- }
679
-
680
- if (captions.length > 0) {
681
- for (i=0; i<captions.length; i++) {
682
- if (captions[i].def === true) {
683
- this.captionLang = captions[i].language;
684
- this.selectedCaptions = captions[i];
685
- }
686
- }
687
- if (typeof this.captionLang === 'undefined') {
688
- // No caption track was flagged as default
689
- // find and use a caption language that matches the player language
690
- for (i=0; i<captions.length; i++) {
691
- if (captions[i].language === this.lang) {
692
- this.captionLang = captions[i].language;
693
- this.selectedCaptions = captions[i];
694
- }
695
- }
696
- }
697
- if (typeof this.captionLang === 'undefined') {
698
- // Still no matching caption track
699
- // just use the first track
700
- this.captionLang = captions[0].language;
701
- this.selectedCaptions = captions[0];
702
- }
703
- if (typeof this.captionLang !== 'undefined') {
704
- // reset transcript selected <option> to this.captionLang
705
- if (this.$transcriptLanguageSelect) {
706
- this.$transcriptLanguageSelect.find('option[lang=' + this.captionLang + ']').prop('selected',true);
707
- }
708
- // sync all other tracks to this same languge
709
- this.syncTrackLanguages('init',this.captionLang);
710
- }
711
- }
712
- };
713
-
714
- AblePlayer.prototype.initHtml5Player = function () {
715
- // Nothing special to do!
716
- var deferred = new $.Deferred();
717
- var promise = deferred.promise();
718
- deferred.resolve();
719
- return promise;
720
- };
721
-
722
- AblePlayer.prototype.initJwPlayer = function () {
723
-
724
- var jwHeight;
725
- var thisObj = this;
726
- var deferred = new $.Deferred();
727
- var promise = deferred.promise();
728
-
729
- $.ajax({
730
- async: false,
731
- url: this.fallbackPath + 'jwplayer.js',
732
- dataType: 'script',
733
- success: function( data, textStatus, jqXHR) {
734
- // add jwplayer key for selfhosted when fallback is activated
735
- if (thisObj.fallbackJwKey) {
736
- $('head').append(
737
- '<script type="text/javascript">jwplayer.key="' +
738
- thisObj.fallbackJwKey +
739
- '";</script>'
740
- );
741
- }
742
-
743
- // Successfully loaded the JW Player
744
- // add an id to div.able-media-container (JW Player needs this)
745
- thisObj.jwId = thisObj.mediaId + '_fallback';
746
- thisObj.$mediaContainer.attr('id', thisObj.jwId);
747
- if (thisObj.mediaType === 'audio') {
748
- // JW Player always shows its own controls if height <= 40
749
- // Must set height to 0 to hide them
750
- jwHeight = 0;
751
- }
752
- else {
753
- jwHeight = thisObj.playerHeight;
754
- }
755
- var sources = [];
756
- $.each(thisObj.$sources, function (ii, source) {
757
- sources.push({file: $(source).attr('src')});
758
- });
759
-
760
- var flashplayer = thisObj.fallbackPath + 'jwplayer.flash.swf';
761
- var html5player = thisObj.fallbackPath + 'jwplayer.html5.js';
762
-
763
- // Initializing JW Player with width:100% results in player that is either the size of the video
764
- // or scaled down to fit the container if container is smaller
765
- // After onReady event fires, actual dimensions will be collected for future use
766
- // in preserving the video ratio
767
- if (thisObj.mediaType === 'video') {
768
- thisObj.jwPlayer = jwplayer(thisObj.jwId).setup({
769
- playlist: [{
770
- image: thisObj.$media.attr('poster'),
771
- sources: sources
772
- }],
773
- flashplayer: flashplayer,
774
- html5player: html5player,
775
- controls: false,
776
- volume: thisObj.defaultVolume * 100,
777
- width: '100%',
778
- fallback: false,
779
- primary: 'flash',
780
- wmode: 'transparent' // necessary to get HTML captions to appear as overlay
781
- });
782
- }
783
- else { // if this is an audio player
784
- thisObj.jwPlayer = jwplayer(thisObj.jwId).setup({
785
- playlist: [{
786
- sources: sources
787
- }],
788
- flashplayer: flashplayer,
789
- html5player: html5player,
790
- controls: false,
791
- volume: this.defaultVolume * 100,
792
- height: 0,
793
- width: '100%',
794
- fallback: false,
795
- primary: 'flash'
796
- });
797
- }
798
- // remove the media element - we're done with it
799
- // keeping it would cause too many potential problems with HTML5 & JW event listeners both firing
800
- thisObj.$media.remove();
801
-
802
- deferred.resolve();
803
- },
804
- error: function(jqXHR, textStatus, errorThrown) {
805
- // Loading the JW Player failed
806
- deferred.reject();
807
- }
808
- });
809
- // Done with JW Player initialization.
810
- return promise;
811
- };
812
-
813
- // Sets media/track/source attributes; is called whenever player is recreated since $media may have changed.
814
- AblePlayer.prototype.setMediaAttributes = function () {
815
- // Firefox puts videos in tab order; remove.
816
- this.$media.attr('tabindex', -1);
817
-
818
- // Keep native player from displaying captions/subtitles by setting textTrack.mode='disabled'
819
- // https://dev.w3.org/html5/spec-author-view/video.html#text-track-mode
820
- // This *should* work but historically hasn't been supported in all browsers
821
- // Workaround for non-supporting browsers is to remove default attribute
822
- // We're doing that too in track.js > setupCaptions()
823
- var textTracks = this.$media.get(0).textTracks;
824
- if (textTracks) {
825
- var i = 0;
826
- while (i < textTracks.length) {
827
- textTracks[i].mode = 'disabled';
828
- i += 1;
829
- }
830
- }
831
- };
832
-
833
- AblePlayer.prototype.getPlayer = function() {
834
-
835
- // Determine which player to use, if any
836
- // return 'html5', 'jw' or null
837
- var i, sourceType, $newItem;
838
- if (this.youTubeId) {
839
- if (this.mediaType !== 'video') {
840
- // attempting to play a YouTube video using an element other than <video>
841
- return null;
842
- }
843
- else {
844
- return 'youtube';
845
- }
846
- }
847
- else if (this.testFallback ||
848
- ((this.isUserAgent('msie 7') || this.isUserAgent('msie 8') || this.isUserAgent('msie 9')) && this.mediaType === 'video') ||
849
- (this.isIOS() && (this.isIOS(4) || this.isIOS(5) || this.isIOS(6)))
850
- ) {
851
- // the user wants to test the fallback player, or
852
- // the user is using an older version of IE or IOS,
853
- // both of which had buggy implementation of HTML5 video
854
- if (this.fallback === 'jw') {
855
- if (this.jwCanPlay()) {
856
- return 'jw';
857
- }
858
- else {
859
- // JW Player is available as fallback, but can't play this source file
860
- return null;
861
- }
862
- }
863
- else {
864
- // browser doesn't support HTML5 video and there is no fallback player
865
- return null;
866
- }
867
- }
868
- else if (this.media.canPlayType) {
869
- return 'html5';
870
- }
871
- else {
872
- // Browser does not support the available media file
873
- return null;
874
- }
875
- };
876
-
877
- AblePlayer.prototype.jwCanPlay = function() {
878
- // Determine whether there are media files that JW supports
879
- var i, sourceType, $firstItem;
880
-
881
- if (this.$sources.length > 0) { // this media has one or more <source> elements
882
- for (i = 0; i < this.$sources.length; i++) {
883
- sourceType = this.$sources[i].getAttribute('type');
884
- if ((this.mediaType === 'video' && sourceType === 'video/mp4') ||
885
- (this.mediaType === 'audio' && sourceType === 'audio/mpeg')) {
886
- // JW Player can play this
887
- return true;
888
- }
889
- }
890
- }
891
- // still here? That means there's no source that JW can play
892
- // check for an mp3 or mp4 in a able-playlist
893
- // TODO: Implement this more efficiently
894
- // Playlist is initialized later in setupInstancePlaylist()
895
- // but we can't wait for that...
896
- if ($('.able-playlist')) {
897
- // there's at least one playlist on this page
898
- // get the first item from the first playlist
899
- // if JW Player can play that one, assume it can play all items in all playlists
900
- $firstItem = $('.able-playlist').eq(0).find('li').eq(0);
901
- if (this.mediaType === 'audio') {
902
- if ($firstItem.attr('data-mp3')) {
903
- return true;
904
- }
905
- else if (this.mediaType === 'video') {
906
- if ($firstItem.attr('data-mp4')) {
907
- return true;
908
- }
909
- }
910
- }
911
- }
912
- return false;
913
- };
2
+ // Set default variable values.
3
+ AblePlayer.prototype.setDefaults = function () {
4
+
5
+ this.playerCreated = false; // will set to true after recreatePlayer() is complete the first time
6
+ this.playing = false; // will change to true after 'playing' event is triggered
7
+ this.paused = true; // will always be the opposite of this.playing (available for convenience)
8
+ this.clickedPlay = false; // will change to true temporarily if user clicks 'play' (or pause)
9
+ this.fullscreen = false; // will change to true if player is in full screen mode
10
+ this.swappingSrc = false; // will change to true temporarily while media source is being swapped
11
+ this.initializing = false; // will change to true temporarily while initPlayer() is processing
12
+ this.cueingPlaylistItems = false; // will change to true temporarily while cueing next playlist item
13
+ this.okToPlay = false; // will change to true if conditions are acceptible for automatic playback after media loads
14
+
15
+ this.getUserAgent();
16
+ this.setIconColor();
17
+ this.setButtonImages();
18
+ };
19
+
20
+ AblePlayer.prototype.getRootPath = function() {
21
+
22
+ // returns Able Player root path (assumes ableplayer.js is in /build, one directory removed from root)
23
+ var scripts, i, scriptSrc, scriptFile, fullPath, ablePath, parentFolderIndex, rootPath;
24
+ scripts= document.getElementsByTagName('script');
25
+ for (i=0; i < scripts.length; i++) {
26
+ scriptSrc = scripts[i].src;
27
+ scriptFile = scriptSrc.substr(scriptSrc.lastIndexOf('/'));
28
+ if (scriptFile.indexOf('ableplayer') !== -1) {
29
+ // this is the ableplayerscript
30
+ fullPath = scriptSrc.split('?')[0]; // remove any ? params
31
+ break;
32
+ }
33
+ }
34
+ ablePath= fullPath.split('/').slice(0, -1).join('/'); // remove last filename part of path
35
+ parentFolderIndex = ablePath.lastIndexOf('/');
36
+ rootPath = ablePath.substring(0, parentFolderIndex) + '/';
37
+ return rootPath;
38
+ }
39
+
40
+ AblePlayer.prototype.setIconColor = function() {
41
+
42
+ // determine the best color choice (white or black) for icons,
43
+ // given the background-color of their container elements
44
+ // Source for relative luminance formula:
45
+ // https://en.wikipedia.org/wiki/Relative_luminance
46
+
47
+ // We need to know the color *before* creating the element
48
+ // so the element doesn't exist yet when this function is called
49
+ // therefore, need to create a temporary element then remove it after color is determined
50
+ // Temp element must be added to the DOM or WebKit can't retrieve its CSS properties
51
+
52
+ var $elements, i, $el, bgColor, rgb, red, green, blue, luminance, iconColor;
53
+
54
+ $elements = ['controller', 'toolbar'];
55
+ for (i=0; i<$elements.length; i++) {
56
+ if ($elements[i] == 'controller') {
57
+ $el = $('<div>', {
58
+ 'class': 'able-controller'
59
+ }).hide();
60
+ }
61
+ else if ($elements[i] === 'toolbar') {
62
+ $el = $('<div>', {
63
+ 'class': 'able-window-toolbar'
64
+ }).hide();
65
+ }
66
+ $('body').append($el);
67
+ bgColor = $el.css('background-color');
68
+ // bgColor is a string in the form 'rgb(R, G, B)', perhaps with a 4th item for alpha;
69
+ // split the 3 or 4 channels into an array
70
+ rgb = bgColor.replace(/[^\d,]/g, '').split(',');
71
+ red = rgb[0];
72
+ green = rgb[1];
73
+ blue = rgb[2];
74
+ luminance = (0.2126 * red) + (0.7152 * green) + (0.0722 * blue);
75
+ // range is 1 - 255; therefore 125 is the tipping point
76
+ if (luminance < 125) { // background is dark
77
+ iconColor = 'white';
78
+ }
79
+ else { // background is light
80
+ iconColor = 'black';
81
+ }
82
+ if ($elements[i] === 'controller') {
83
+ this.iconColor = iconColor;
84
+ }
85
+ else if ($elements[i] === 'toolbar') {
86
+ this.toolbarIconColor = iconColor;
87
+ }
88
+ $el.remove();
89
+ }
90
+ };
91
+
92
+ AblePlayer.prototype.setButtonImages = function() {
93
+
94
+ // NOTE: volume button images are now set dynamically within volume.js
95
+ this.imgPath = this.rootPath + 'button-icons/' + this.iconColor + '/';
96
+ this.playButtonImg = this.imgPath + 'play.png';
97
+ this.pauseButtonImg = this.imgPath + 'pause.png';
98
+
99
+ this.restartButtonImg = this.imgPath + 'restart.png';
100
+
101
+ this.rewindButtonImg = this.imgPath + 'rewind.png';
102
+ this.forwardButtonImg = this.imgPath + 'forward.png';
103
+
104
+ this.previousButtonImg = this.imgPath + 'previous.png';
105
+ this.nextButtonImg = this.imgPath + 'next.png';
106
+
107
+ if (this.speedIcons === 'arrows') {
108
+ this.fasterButtonImg = this.imgPath + 'slower.png';
109
+ this.slowerButtonImg = this.imgPath + 'faster.png';
110
+ }
111
+ else if (this.speedIcons === 'animals') {
112
+ this.fasterButtonImg = this.imgPath + 'rabbit.png';
113
+ this.slowerButtonImg = this.imgPath + 'turtle.png';
114
+ }
115
+
116
+ this.captionsButtonImg = this.imgPath + 'captions.png';
117
+ this.chaptersButtonImg = this.imgPath + 'chapters.png';
118
+ this.signButtonImg = this.imgPath + 'sign.png';
119
+ this.transcriptButtonImg = this.imgPath + 'transcript.png';
120
+ this.descriptionsButtonImg = this.imgPath + 'descriptions.png';
121
+
122
+ this.fullscreenExpandButtonImg = this.imgPath + 'fullscreen-expand.png';
123
+ this.fullscreenCollapseButtonImg = this.imgPath + 'fullscreen-collapse.png';
124
+
125
+ this.prefsButtonImg = this.imgPath + 'preferences.png';
126
+ this.helpButtonImg = this.imgPath + 'help.png';
127
+ };
128
+
129
+ AblePlayer.prototype.getSvgData = function(button) {
130
+
131
+ // returns array of values for creating <svg> tag for specified button
132
+ // 0 = <svg> viewBox attribute
133
+ // 1 = <path> d (description) attribute
134
+ var svg = Array();
135
+
136
+ switch (button) {
137
+
138
+ case 'play':
139
+ svg[0] = '0 0 16 20';
140
+ svg[1] = 'M0 18.393v-16.429q0-0.29 0.184-0.402t0.441 0.033l14.821 8.237q0.257 0.145 0.257 0.346t-0.257 0.346l-14.821 8.237q-0.257 0.145-0.441 0.033t-0.184-0.402z';
141
+ break;
142
+
143
+ case 'pause':
144
+ svg[0] = '0 0 20 20';
145
+ svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502zM10 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h5.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-5.714q-0.29 0-0.502-0.212t-0.212-0.502z';
146
+ break;
147
+
148
+ case 'stop':
149
+ svg[0] = '0 0 20 20';
150
+ svg[1] = 'M0 18.036v-15.714q0-0.29 0.212-0.502t0.502-0.212h15.714q0.29 0 0.502 0.212t0.212 0.502v15.714q0 0.29-0.212 0.502t-0.502 0.212h-15.714q-0.29 0-0.502-0.212t-0.212-0.502z';
151
+ break;
152
+
153
+ case 'restart':
154
+ svg[0] = '0 0 20 20';
155
+ svg[1] = 'M18 8h-6l2.243-2.243c-1.133-1.133-2.64-1.757-4.243-1.757s-3.109 0.624-4.243 1.757c-1.133 1.133-1.757 2.64-1.757 4.243s0.624 3.109 1.757 4.243c1.133 1.133 2.64 1.757 4.243 1.757s3.109-0.624 4.243-1.757c0.095-0.095 0.185-0.192 0.273-0.292l1.505 1.317c-1.466 1.674-3.62 2.732-6.020 2.732-4.418 0-8-3.582-8-8s3.582-8 8-8c2.209 0 4.209 0.896 5.656 2.344l2.344-2.344v6z';
156
+ break;
157
+
158
+ case 'rewind':
159
+ svg[0] = '0 0 20 20';
160
+ svg[1] = 'M11.25 3.125v6.25l6.25-6.25v13.75l-6.25-6.25v6.25l-6.875-6.875z';
161
+ break;
162
+
163
+ case 'forward':
164
+ svg[0] = '0 0 20 20';
165
+ svg[1] = 'M10 16.875v-6.25l-6.25 6.25v-13.75l6.25 6.25v-6.25l6.875 6.875z';
166
+ break;
167
+
168
+ case 'previous':
169
+ svg[0] = '0 0 20 20';
170
+ svg[1] = 'M5 17.5v-15h2.5v6.875l6.25-6.25v13.75l-6.25-6.25v6.875z';
171
+ break;
172
+
173
+ case 'next':
174
+ svg[0] = '0 0 20 20';
175
+ svg[1] = 'M15 2.5v15h-2.5v-6.875l-6.25 6.25v-13.75l6.25 6.25v-6.875z';
176
+ break;
177
+
178
+ case 'slower':
179
+ svg[0] = '0 0 20 20';
180
+ svg[1] = 'M0 7.321q0-0.29 0.212-0.502t0.502-0.212h10q0.29 0 0.502 0.212t0.212 0.502-0.212 0.502l-5 5q-0.212 0.212-0.502 0.212t-0.502-0.212l-5-5q-0.212-0.212-0.212-0.502z';
181
+ break;
182
+
183
+ case 'faster':
184
+ svg[0] = '0 0 11 20';
185
+ svg[1] = 'M0 12.411q0-0.29 0.212-0.502l5-5q0.212-0.212 0.502-0.212t0.502 0.212l5 5q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-10q-0.29 0-0.502-0.212t-0.212-0.502z';
186
+ break;
187
+
188
+ case 'turtle':
189
+ svg[0] = '0 0 20 20';
190
+ svg[1] = 'M17.212 3.846c-0.281-0.014-0.549 0.025-0.817 0.144-1.218 0.542-1.662 2.708-2.163 3.942-1.207 2.972-7.090 4.619-11.755 5.216-0.887 0.114-1.749 0.74-2.428 1.466 0.82-0.284 2.126-0.297 2.74 0.144 0.007 0.488-0.376 1.062-0.625 1.37-0.404 0.5-0.398 0.793 0.12 0.793 0.473 0 0.752 0.007 1.635 0 0.393-0.003 0.618-0.16 1.49-1.49 3.592 0.718 5.986-0.264 5.986-0.264s0.407 1.755 1.418 1.755h1.49c0.633 0 0.667-0.331 0.625-0.433-0.448-1.082-0.68-1.873-0.769-2.5-0.263-1.857 0.657-3.836 2.524-5.457 0.585 0.986 2.253 0.845 2.909-0.096s0.446-2.268-0.192-3.221c-0.49-0.732-1.345-1.327-2.188-1.37zM8.221 4.663c-0.722-0.016-1.536 0.111-2.5 0.409-4.211 1.302-4.177 4.951-3.51 5.745 0 0-0.955 0.479-0.409 1.274 0.448 0.652 3.139 0.191 5.409-0.529s4.226-1.793 5.312-2.692c0.948-0.785 0.551-2.106-0.505-1.947-0.494-0.98-1.632-2.212-3.798-2.26zM18.846 5.962c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577z';
191
+ break;
192
+
193
+ case 'rabbit':
194
+ svg[0] = '0 0 20 20';
195
+ svg[1] = 'M10.817 0c-2.248 0-1.586 0.525-1.154 0.505 1.551-0.072 5.199 0.044 6.851 2.428 0 0-1.022-2.933-5.697-2.933zM10.529 0.769c-2.572 0-2.837 0.51-2.837 1.106 0 0.545 1.526 0.836 2.524 0.697 2.778-0.386 4.231-0.12 5.264 0.865-1.010 0.779-0.75 1.401-1.274 1.851-1.093 0.941-2.643-0.673-4.976-0.673-2.496 0-4.712 1.92-4.712 4.76-0.157-0.537-0.769-0.913-1.442-0.913-0.974 0-1.514 0.637-1.514 1.49 0 0.769 1.13 1.791 2.861 0.938 0.499 1.208 2.265 1.364 2.452 1.418 0.538 0.154 1.875 0.098 1.875 0.865 0 0.794-1.034 1.094-1.034 1.707 0 1.070 1.758 0.873 2.284 1.034 1.683 0.517 2.103 1.214 2.788 2.212 0.771 1.122 2.572 1.408 2.572 0.625 0-3.185-4.413-4.126-4.399-4.135 0.608-0.382 2.139-1.397 2.139-3.534 0-1.295-0.703-2.256-1.755-2.861 1.256 0.094 2.572 1.205 2.572 2.74 0 1.877-0.653 2.823-0.769 2.957 1.975-1.158 3.193-3.91 3.029-6.37 0.61 0.401 1.27 0.577 1.971 0.625 0.751 0.052 1.475-0.225 1.635-0.529 0.38-0.723 0.162-2.321-0.12-2.837-0.763-1.392-2.236-1.73-3.606-1.683-1.202-1.671-3.812-2.356-5.529-2.356zM1.37 3.077l-0.553 1.538h3.726c0.521-0.576 1.541-1.207 2.284-1.538h-5.457zM18.846 5.192c0.325 0 0.577 0.252 0.577 0.577s-0.252 0.577-0.577 0.577c-0.325 0-0.577-0.252-0.577-0.577s0.252-0.577 0.577-0.577zM0.553 5.385l-0.553 1.538h3.197c0.26-0.824 0.586-1.328 0.769-1.538h-3.413z';
196
+ break;
197
+
198
+ case 'ellipsis':
199
+ svg[0] = '0 0 20 20';
200
+ svg[1] = 'M10.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2zM3.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.986 2.199-2.2s-0.984-2.2-2.199-2.2zM17.001 7.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2z';
201
+ break;
202
+
203
+ case 'pipe':
204
+ svg[0] = '0 0 20 20';
205
+ svg[1] = 'M10.15 0.179h0.623c0.069 0 0.127 0.114 0.127 0.253v19.494c0 0.139-0.057 0.253-0.127 0.253h-1.247c-0.069 0-0.126-0.114-0.126-0.253v-19.494c0-0.139 0.057-0.253 0.126-0.253h0.623z';
206
+ break;
207
+
208
+ case 'captions':
209
+ svg[0] = '0 0 20 20';
210
+ svg[1] = 'M0.033 3.624h19.933v12.956h-19.933v-12.956zM18.098 10.045c-0.025-2.264-0.124-3.251-0.743-3.948-0.112-0.151-0.322-0.236-0.496-0.344-0.606-0.386-3.465-0.526-6.782-0.526s-6.313 0.14-6.907 0.526c-0.185 0.108-0.396 0.193-0.519 0.344-0.607 0.697-0.693 1.684-0.731 3.948 0.037 2.265 0.124 3.252 0.731 3.949 0.124 0.161 0.335 0.236 0.519 0.344 0.594 0.396 3.59 0.526 6.907 0.547 3.317-0.022 6.176-0.151 6.782-0.547 0.174-0.108 0.384-0.183 0.496-0.344 0.619-0.697 0.717-1.684 0.743-3.949v0 0zM9.689 9.281c-0.168-1.77-1.253-2.813-3.196-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.442-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.977zM16.607 9.281c-0.167-1.77-1.252-2.813-3.194-2.813-1.773 0-3.168 1.387-3.168 3.617 0 2.239 1.271 3.636 3.372 3.636 1.676 0 2.851-1.071 3.035-2.852h-2.003c-0.079 0.661-0.397 1.168-1.068 1.168-1.059 0-1.253-0.91-1.253-1.876 0-1.33 0.441-2.010 1.174-2.010 0.653 0 1.068 0.412 1.13 1.129h1.976z';
211
+ break;
212
+
213
+ case 'descriptions':
214
+ svg[0] = '0 0 20 20';
215
+ svg[1] = 'M17.623 3.57h-1.555c1.754 1.736 2.763 4.106 2.763 6.572 0 2.191-0.788 4.286-2.189 5.943h1.484c1.247-1.704 1.945-3.792 1.945-5.943-0-2.418-0.886-4.754-2.447-6.572v0zM14.449 3.57h-1.55c1.749 1.736 2.757 4.106 2.757 6.572 0 2.191-0.788 4.286-2.187 5.943h1.476c1.258-1.704 1.951-3.792 1.951-5.943-0-2.418-0.884-4.754-2.447-6.572v0zM11.269 3.57h-1.542c1.752 1.736 2.752 4.106 2.752 6.572 0 2.191-0.791 4.286-2.181 5.943h1.473c1.258-1.704 1.945-3.792 1.945-5.943 0-2.418-0.876-4.754-2.447-6.572v0zM10.24 9.857c0 3.459-2.826 6.265-6.303 6.265v0.011h-3.867v-12.555h3.896c3.477 0 6.274 2.806 6.274 6.279v0zM6.944 9.857c0-1.842-1.492-3.338-3.349-3.338h-0.876v6.686h0.876c1.858 0 3.349-1.498 3.349-3.348v0z';
216
+ break;
217
+
218
+ case 'sign':
219
+ svg[0] = '0 0 20 20';
220
+ svg[1] = 'M10.954 10.307c0.378 0.302 0.569 1.202 0.564 1.193 0.697 0.221 1.136 0.682 1.136 0.682 1.070-0.596 1.094-0.326 1.558-0.682 0.383-0.263 0.366-0.344 0.567-1.048 0.187-0.572-0.476-0.518-1.021-1.558-0.95 0.358-1.463 0.196-1.784 0.167-0.145-0.020-0.12 0.562-1.021 1.247zM14.409 17.196c-0.133 0.182-0.196 0.218-0.363 0.454-0.28 0.361 0.076 0.906 0.253 0.82 0.206-0.076 0.341-0.488 0.567-0.623 0.115-0.061 0.422-0.513 0.709-0.82 0.211-0.238 0.363-0.344 0.564-0.594 0.341-0.422 0.412-0.744 0.709-1.193 0.184-0.236 0.312-0.307 0.481-0.594 0.886-1.679 0.628-2.432 1.475-3.629 0.26-0.353 0.552-0.442 0.964-0.653 0.383-2.793-0.888-4.356-0.879-4.361-1.067 0.623-1.644 0.879-2.751 0.82-0.417-0.005-0.636-0.182-1.048-0.145-0.385 0.015-0.582 0.159-0.964 0.29-0.589 0.182-0.91 0.344-1.529 0.535-0.393 0.11-0.643 0.115-1.050 0.255-0.348 0.147-0.182 0.029-0.427 0.312-0.317 0.348-0.238 0.623-0.535 1.222-0.371 0.785-0.326 0.891-0.115 0.987-0.14 0.402-0.174 0.672-0.14 1.107 0.039 0.331-0.101 0.562 0.255 0.825 0.483 0.361 1.499 1.205 1.757 1.217 0.39-0.012 1.521 0.029 2.096-0.368 0.13-0.081 0.167-0.162 0.056 0.145-0.022 0.037-1.433 1.136-1.585 1.131-1.794 0.056-1.193 0.157-1.303 0.115-0.091 0-0.955-1.055-1.477-0.682-0.196 0.12-0.287 0.236-0.363 0.452 0.066 0.137 0.383 0.358 0.675 0.54 0.422 0.27 0.461 0.552 0.881 0.653 0.513 0.115 1.060 0.039 1.387 0.081 0.125 0.034 1.256-0.297 1.961-0.675 0.65-0.336-0.898 0.648-1.276 1.131-1.141 0.358-0.82 0.373-1.362 0.483-0.503 0.115-0.479 0.086-0.822 0.196-0.356 0.086-0.648 0.572-0.312 0.825 0.201 0.167 0.827-0.066 1.445-0.086 0.275-0.005 1.391-0.518 1.644-0.653 0.633-0.339 1.099-0.81 1.472-1.077 0.518-0.361-0.584 0.991-1.050 1.558zM8.855 9.799c-0.378-0.312-0.569-1.212-0.564-1.217-0.697-0.206-1.136-0.667-1.136-0.653-1.070 0.582-1.099 0.312-1.558 0.653-0.388 0.277-0.366 0.363-0.567 1.045-0.187 0.594 0.471 0.535 1.021 1.561 0.95-0.344 1.463-0.182 1.784-0.142 0.145 0.010 0.12-0.572 1.021-1.247zM5.4 2.911c0.133-0.191 0.196-0.228 0.368-0.454 0.27-0.371-0.081-0.915-0.253-0.849-0.211 0.096-0.346 0.508-0.599 0.653-0.093 0.052-0.4 0.503-0.682 0.82-0.211 0.228-0.363 0.334-0.564 0.599-0.346 0.407-0.412 0.729-0.709 1.161-0.184 0.258-0.317 0.324-0.481 0.621-0.886 1.669-0.631 2.422-1.475 3.6-0.26 0.38-0.552 0.461-0.964 0.682-0.383 2.788 0.883 4.346 0.879 4.336 1.068-0.609 1.639-0.861 2.751-0.825 0.417 0.025 0.636 0.201 1.048 0.174 0.385-0.025 0.582-0.169 0.964-0.285 0.589-0.196 0.91-0.358 1.499-0.54 0.422-0.12 0.672-0.125 1.080-0.285 0.348-0.128 0.182-0.010 0.427-0.282 0.312-0.358 0.238-0.633 0.508-1.217 0.398-0.8 0.353-0.906 0.142-0.991 0.135-0.412 0.174-0.677 0.14-1.107-0.044-0.336 0.101-0.572-0.255-0.82-0.483-0.375-1.499-1.22-1.752-1.222-0.395 0.002-1.526-0.039-2.101 0.339-0.13 0.101-0.167 0.182-0.056-0.11 0.022-0.052 1.433-1.148 1.585-1.163 1.794-0.039 1.193-0.14 1.303-0.088 0.091-0.007 0.955 1.045 1.477 0.682 0.191-0.13 0.287-0.245 0.368-0.452-0.071-0.147-0.388-0.368-0.68-0.537-0.422-0.282-0.464-0.564-0.881-0.655-0.513-0.125-1.065-0.049-1.387-0.11-0.125-0.015-1.256 0.317-1.956 0.68-0.66 0.351 0.893-0.631 1.276-1.136 1.136-0.339 0.81-0.353 1.36-0.479 0.501-0.101 0.476-0.071 0.82-0.172 0.351-0.096 0.648-0.577 0.312-0.849-0.206-0.152-0.827 0.081-1.44 0.086-0.28 0.020-1.396 0.533-1.649 0.677-0.633 0.329-1.099 0.8-1.472 1.048-0.523 0.38 0.584-0.967 1.050-1.529z';
221
+ break;
222
+
223
+ case 'mute':
224
+ svg[0] = '0 0 20 20';
225
+ svg[1] = 'M7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714zM18.75 12.093v1.657h-1.657l-2.093-2.093-2.093 2.093h-1.657v-1.657l2.093-2.093-2.093-2.093v-1.657h1.657l2.093 2.093 2.093-2.093h1.657v1.657l-2.093 2.093z';
226
+ break;
227
+
228
+ case 'volume-mute':
229
+ svg[0] = '0 0 20 20';
230
+ svg[1] = 'M10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
231
+ break;
232
+
233
+ case 'volume-medium':
234
+ svg[0] = '0 0 20 20';
235
+ svg[1] = 'M14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
236
+ break;
237
+
238
+ case 'volume-loud':
239
+ svg[0] = '0 0 21 20';
240
+ svg[1] = 'M17.384 18.009c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.712-1.712 2.654-3.988 2.654-6.408s-0.943-4.696-2.654-6.408c-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.066 2.066 3.204 4.813 3.204 7.734s-1.138 5.668-3.204 7.734c-0.183 0.183-0.423 0.275-0.663 0.275zM14.053 16.241c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 2.559-2.559 2.559-6.722 0-9.281-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c1.594 1.594 2.471 3.712 2.471 5.966s-0.878 4.373-2.471 5.966c-0.183 0.183-0.423 0.275-0.663 0.275zM10.723 14.473c-0.24 0-0.48-0.092-0.663-0.275-0.366-0.366-0.366-0.96 0-1.326 1.584-1.584 1.584-4.161 0-5.745-0.366-0.366-0.366-0.96 0-1.326s0.96-0.366 1.326 0c2.315 2.315 2.315 6.082 0 8.397-0.183 0.183-0.423 0.275-0.663 0.275zM7.839 1.536c0.501-0.501 0.911-0.331 0.911 0.378v16.172c0 0.709-0.41 0.879-0.911 0.378l-4.714-4.713h-3.125v-7.5h3.125l4.714-4.714z';
241
+ break;
242
+
243
+ case 'chapters':
244
+ svg[0] = '0 0 20 20';
245
+ svg[1] = 'M5 2.5v17.5l6.25-6.25 6.25 6.25v-17.5zM15 0h-12.5v17.5l1.25-1.25v-15h11.25z';
246
+ break;
247
+
248
+ case 'transcript':
249
+ svg[0] = '0 0 20 20';
250
+ svg[1] = 'M0 19.107v-17.857q0-0.446 0.313-0.759t0.759-0.313h8.929v6.071q0 0.446 0.313 0.759t0.759 0.313h6.071v11.786q0 0.446-0.313 0.759t-0.759 0.312h-15q-0.446 0-0.759-0.313t-0.313-0.759zM4.286 15.536q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 12.679q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM4.286 9.821q0 0.156 0.1 0.257t0.257 0.1h7.857q0.156 0 0.257-0.1t0.1-0.257v-0.714q0-0.156-0.1-0.257t-0.257-0.1h-7.857q-0.156 0-0.257 0.1t-0.1 0.257v0.714zM11.429 5.893v-5.268q0.246 0.156 0.402 0.313l4.554 4.554q0.156 0.156 0.313 0.402h-5.268z';
251
+ break;
252
+
253
+ case 'preferences':
254
+ svg[0] = '0 0 20 20';
255
+ svg[1] = 'M18.238 11.919c-1.049-1.817-0.418-4.147 1.409-5.205l-1.965-3.404c-0.562 0.329-1.214 0.518-1.911 0.518-2.1 0-3.803-1.714-3.803-3.828h-3.931c0.005 0.653-0.158 1.314-0.507 1.919-1.049 1.818-3.382 2.436-5.212 1.382l-1.965 3.404c0.566 0.322 1.056 0.793 1.404 1.396 1.048 1.815 0.42 4.139-1.401 5.2l1.965 3.404c0.56-0.326 1.209-0.513 1.902-0.513 2.094 0 3.792 1.703 3.803 3.808h3.931c-0.002-0.646 0.162-1.3 0.507-1.899 1.048-1.815 3.375-2.433 5.203-1.387l1.965-3.404c-0.562-0.322-1.049-0.791-1.395-1.391zM10 14.049c-2.236 0-4.050-1.813-4.050-4.049s1.813-4.049 4.050-4.049 4.049 1.813 4.049 4.049c-0 2.237-1.813 4.049-4.049 4.049z';
256
+ break;
257
+
258
+ case 'close':
259
+ svg[0] = '0 0 16 20';
260
+ svg[1] = 'M1.228 14.933q0-0.446 0.312-0.759l3.281-3.281-3.281-3.281q-0.313-0.313-0.313-0.759t0.313-0.759l1.518-1.518q0.313-0.313 0.759-0.313t0.759 0.313l3.281 3.281 3.281-3.281q0.313-0.313 0.759-0.313t0.759 0.313l1.518 1.518q0.313 0.313 0.313 0.759t-0.313 0.759l-3.281 3.281 3.281 3.281q0.313 0.313 0.313 0.759t-0.313 0.759l-1.518 1.518q-0.313 0.313-0.759 0.313t-0.759-0.313l-3.281-3.281-3.281 3.281q-0.313 0.313-0.759 0.313t-0.759-0.313l-1.518-1.518q-0.313-0.313-0.313-0.759z';
261
+ break;
262
+
263
+ case 'fullscreen-expand':
264
+ svg[0] = '0 0 20 20';
265
+ svg[1] = 'M0 18.036v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502zM8.717 8.393q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257z';
266
+ break;
267
+
268
+ case 'fullscreen-collapse':
269
+ svg[0] = '0 0 20 20';
270
+ svg[1] = 'M0.145 16.964q0-0.145 0.112-0.257l3.705-3.705-1.607-1.607q-0.212-0.212-0.212-0.502t0.212-0.502 0.502-0.212h5q0.29 0 0.502 0.212t0.212 0.502v5q0 0.29-0.212 0.502t-0.502 0.212-0.502-0.212l-1.607-1.607-3.705 3.705q-0.112 0.112-0.257 0.112t-0.257-0.112l-1.272-1.272q-0.112-0.112-0.112-0.257zM8.571 9.464v-5q0-0.29 0.212-0.502t0.502-0.212 0.502 0.212l1.607 1.607 3.705-3.705q0.112-0.112 0.257-0.112t0.257 0.112l1.272 1.272q0.112 0.112 0.112 0.257t-0.112 0.257l-3.705 3.705 1.607 1.607q0.212 0.212 0.212 0.502t-0.212 0.502-0.502 0.212h-5q-0.29 0-0.502-0.212t-0.212-0.502z';
271
+ break;
272
+
273
+ case 'help':
274
+ svg[0] = '0 0 11 20';
275
+ svg[1] = 'M0.577 6.317q-0.028-0.167 0.061-0.313 1.786-2.969 5.179-2.969 0.893 0 1.797 0.346t1.629 0.926 1.183 1.423 0.458 1.769q0 0.603-0.173 1.127t-0.391 0.854-0.614 0.664-0.642 0.485-0.681 0.396q-0.458 0.257-0.765 0.725t-0.307 0.748q0 0.19-0.134 0.363t-0.313 0.173h-2.679q-0.167 0-0.285-0.206t-0.117-0.419v-0.502q0-0.926 0.725-1.747t1.596-1.211q0.658-0.301 0.938-0.625t0.279-0.848q0-0.469-0.519-0.826t-1.2-0.357q-0.725 0-1.205 0.324-0.391 0.279-1.194 1.283-0.145 0.179-0.346 0.179-0.134 0-0.279-0.089l-1.83-1.395q-0.145-0.112-0.173-0.279zM3.786 16.875v-2.679q0-0.179 0.134-0.313t0.313-0.134h2.679q0.179 0 0.313 0.134t0.134 0.313v2.679q0 0.179-0.134 0.313t-0.313 0.134h-2.679q-0.179 0-0.313-0.134t-0.134-0.313z';
276
+ break;
277
+ }
278
+
279
+ return svg;
280
+ };
281
+
282
+ // Initialize player based on data on page.
283
+ // This sets some variables, but does not modify anything. Safe to call multiple times.
284
+ // Can call again after updating this.media so long as new media element has the same ID.
285
+ AblePlayer.prototype.reinitialize = function () {
286
+
287
+ var deferred, promise, thisObj, errorMsg, srcFile;
288
+
289
+ deferred = new $.Deferred();
290
+ promise = deferred.promise();
291
+ thisObj = this;
292
+
293
+ // if F12 Developer Tools aren't open in IE (through 9, no longer a problen in IE10)
294
+ // console.log causes an error - can't use debug without a console to log messages to
295
+ if (! window.console) {
296
+ this.debug = false;
297
+ }
298
+
299
+ this.startedPlaying = false;
300
+ // TODO: Move this setting to cookie.
301
+ this.autoScrollTranscript = true;
302
+ //this.autoScrollTranscript = this.getCookie(autoScrollTranscript); // (doesn't work)
303
+
304
+ // Bootstrap from this.media possibly being an ID or other selector.
305
+ this.$media = $(this.media).first();
306
+ this.media = this.$media[0];
307
+
308
+ // Set media type to 'audio' or 'video'; this determines some of the behavior of player creation.
309
+ if (this.$media.is('audio')) {
310
+ this.mediaType = 'audio';
311
+ }
312
+ else if (this.$media.is('video')) {
313
+ this.mediaType = 'video';
314
+ }
315
+ else {
316
+ // Able Player was initialized with some element other than <video> or <audio>
317
+ this.provideFallback();
318
+ deferred.fail();
319
+ return promise;
320
+ }
321
+
322
+ this.$sources = this.$media.find('source');
323
+
324
+ this.player = this.getPlayer();
325
+ if (!this.player) {
326
+ // an error was generated in getPlayer()
327
+ this.provideFallback();
328
+ }
329
+ this.setIconType();
330
+ this.setDimensions();
331
+
332
+ deferred.resolve();
333
+ return promise;
334
+ };
335
+
336
+ AblePlayer.prototype.setDimensions = function() {
337
+ // if media element includes width and height attributes,
338
+ // use these to set the max-width and max-height of the player
339
+ if (this.$media.attr('width') && this.$media.attr('height')) {
340
+ this.playerMaxWidth = parseInt(this.$media.attr('width'), 10);
341
+ this.playerMaxHeight = parseInt(this.$media.attr('height'), 10);
342
+ }
343
+ else if (this.$media.attr('width')) {
344
+ // media element includes a width attribute, but not height
345
+ this.playerMaxWidth = parseInt(this.$media.attr('width'), 10);
346
+ }
347
+ else {
348
+ // set width to width of #player
349
+ // don't set height though; YouTube will automatically set that to match width
350
+ this.playerMaxWidth = this.$media.parent().width();
351
+ this.playerMaxHeight = this.getMatchingHeight(this.playerMaxWidth);
352
+ }
353
+ // override width and height attributes with in-line CSS to make video responsive
354
+ this.$media.css({
355
+ 'width': '100%',
356
+ 'height': 'auto'
357
+ });
358
+ };
359
+
360
+ AblePlayer.prototype.getMatchingHeight = function(width) {
361
+
362
+ // returns likely height for a video, given width
363
+ // These calculations assume 16:9 aspect ratio (the YouTube standard)
364
+ // Videos recorded in other resolutions will be sized to fit, with black bars on each side
365
+ // This function is only called if the <video> element does not have width and height attributes
366
+
367
+ var widths, heights, closestWidth, closestIndex, closestHeight, height;
368
+
369
+ widths = [ 3840, 2560, 1920, 1280, 854, 640, 426 ];
370
+ heights = [ 2160, 1440, 1080, 720, 480, 360, 240 ];
371
+ closestWidth = null;
372
+ closestIndex = null;
373
+
374
+ $.each(widths, function(index){
375
+ if (closestWidth == null || Math.abs(this - width) < Math.abs(closestWidth - width)) {
376
+ closestWidth = this;
377
+ closestIndex = index;
378
+ }
379
+ });
380
+ closestHeight = heights[closestIndex];
381
+ this.aspectRatio = closestWidth / closestHeight;
382
+ height = Math.round(width / this.aspectRatio);
383
+ return height;
384
+ };
385
+
386
+ AblePlayer.prototype.setIconType = function() {
387
+
388
+ // returns either "svg", "font" or "image" (in descending order of preference)
389
+ // Test for support of each type. If not supported, test the next type.
390
+ // last resort is image icons
391
+
392
+ var $tempButton, $testButton, controllerFont;
393
+
394
+ if (this.forceIconType) {
395
+ // use value specified in data-icon-type
396
+ return false;
397
+ }
398
+
399
+ // test for SVG support
400
+ // Test this method widely; failed as expected on IE8 and below
401
+ // https://stackoverflow.com/a/27568129/744281
402
+ if (!!(document.createElementNS && document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect)) {
403
+ // browser supports SVG
404
+ this.iconType = 'svg';
405
+ }
406
+ else {
407
+ // browser does NOT support SVG
408
+ // test whether browser can support icon fonts, and whether user has overriding the default style sheet
409
+ // which could cause problems with proper display of the icon fonts
410
+ if (window.getComputedStyle) {
411
+
412
+ // webkit doesn't return calculated styles unless element has been added to the DOM
413
+ // and is visible (note: visibly clipped is considered "visible")
414
+ // use playpauseButton for font-family test if it exists; otherwise must create a new temp button
415
+ if ($('span.icon-play').length) {
416
+ $testButton = $('span.icon-play');
417
+ }
418
+ else {
419
+ $tempButton = $('<span>',{
420
+ 'class': 'icon-play able-clipped'
421
+ });
422
+ $('body').append($tempButton);
423
+ $testButton = $tempButton;
424
+ }
425
+
426
+ // the following retrieves the computed value of font-family
427
+ // tested in Firefox 45.x with "Allow pages to choose their own fonts" unchecked - works!
428
+ // tested in Chrome 49.x with Font Changer plugin - works!
429
+ // tested in IE with user-defined style sheet enables - works!
430
+ // It does NOT account for users who have "ignore font styles on web pages" checked in IE
431
+ // There is no known way to check for that ???
432
+ controllerFont = window.getComputedStyle($testButton.get(0), null).getPropertyValue('font-family');
433
+ if (typeof controllerFont !== 'undefined') {
434
+ if (controllerFont.indexOf('able') !== -1) {
435
+ this.iconType = 'font';
436
+ }
437
+ else {
438
+ this.iconType = 'image';
439
+ }
440
+ }
441
+ else {
442
+ // couldn't get computed font-family; use images to be safe
443
+ this.iconType = 'image';
444
+ }
445
+ }
446
+ else { // window.getComputedStyle is not supported (IE 8 and earlier)
447
+ // No known way to detect computed font
448
+ // The following retrieves the value from the style sheet, not the computed font
449
+ // controllerFont = $tempButton.get(0).currentStyle.fontFamily;
450
+ // It will therefore return "able", even if the user is overriding that with a custom style sheet
451
+ // To be safe, use images
452
+ this.iconType = 'image';
453
+ }
454
+ if (this.debug) {
455
+ console.log('Using ' + this.iconType + 's for player controls');
456
+ }
457
+ if (typeof $tempButton !== 'undefined') {
458
+ $tempButton.remove();
459
+ }
460
+ }
461
+ };
462
+
463
+ // Perform one-time setup for this instance of player; called after player is first initialized.
464
+ AblePlayer.prototype.setupInstance = function () {
465
+
466
+ var deferred = new $.Deferred();
467
+ var promise = deferred.promise();
468
+
469
+ if (this.$media.attr('id')) {
470
+ this.mediaId = this.$media.attr('id');
471
+ }
472
+ else {
473
+ // Ensure the base media element always has an ID.
474
+ this.mediaId = "ableMediaId_" + this.ableIndex;
475
+ this.$media.attr('id', this.mediaId);
476
+ }
477
+ deferred.resolve();
478
+ return promise;
479
+ };
480
+
481
+ AblePlayer.prototype.setupInstancePlaylist = function() {
482
+
483
+ // find a matching playlist and set this.hasPlaylist
484
+ // if there is one, also set this.$playlist, this.playlistIndex, & this.playlistEmbed
485
+ var thisObj = this;
486
+
487
+ this.hasPlaylist = false; // will change to true if a matching playlist is found
488
+
489
+ $('.able-playlist').each(function() {
490
+ if ($(this).data('player') === thisObj.mediaId) {
491
+ // this is the playlist for the current player
492
+ thisObj.hasPlaylist = true;
493
+ // If using an embedded player, we'll replace $playlist with the clone later.
494
+ thisObj.$playlist = $(this).find('li');
495
+
496
+ // check to see if list item has YouTube as its source
497
+ // if it does, inject a thumbnail from YouTube
498
+ var $youTubeVideos = $(this).find('li[data-youtube-id]');
499
+ $youTubeVideos.each(function() {
500
+ var youTubeId = $(this).attr('data-youtube-id');
501
+ var youTubePoster = thisObj.getYouTubePosterUrl(youTubeId,'120');
502
+ var $youTubeImg = $('<img>',{
503
+ 'src': youTubePoster,
504
+ 'alt': ''
505
+ });
506
+ $(this).find('button').prepend($youTubeImg);
507
+ });
508
+
509
+ // add accessibility to the list markup
510
+ $(this).find('li span').attr('aria-hidden','true');
511
+ thisObj.playlistIndex = 0;
512
+ var dataEmbedded = $(this).data('embedded');
513
+ if (typeof dataEmbedded !== 'undefined' && dataEmbedded !== false) {
514
+ // embed playlist within player
515
+ thisObj.playlistEmbed = true;
516
+ }
517
+ else {
518
+ thisObj.playlistEmbed = false;
519
+ }
520
+ }
521
+ });
522
+
523
+ if (this.hasPlaylist && this.loop) {
524
+ // browser will loop the current track in the playlist, rather than the playlist
525
+ // therefore, need to remove loop attribute from media element
526
+ // but keep this.loop as true and handle the playlist looping ourselves
527
+ this.media.removeAttribute('loop');
528
+ }
529
+ if (this.hasPlaylist && this.playlistEmbed) {
530
+ // Copy the playlist out of the dom, so we can reinject when we build the player.
531
+ var parent = this.$playlist.parent();
532
+ this.$playlistDom = parent.clone();
533
+ parent.remove();
534
+ }
535
+ if (this.hasPlaylist && this.$sources.length === 0) {
536
+ // no source elements were provided. Construct them from the first playlist item
537
+ this.cuePlaylistItem(0);
538
+ // redefine this.$sources now that media contains one or more <source> elements
539
+ this.$sources = this.$media.find('source');
540
+ }
541
+
542
+ };
543
+
544
+ AblePlayer.prototype.recreatePlayer = function () {
545
+
546
+ // Creates the appropriate player for the current source.
547
+ var thisObj, prefsGroups, i;
548
+ thisObj = this;
549
+
550
+ // TODO: Ensure when recreating player that we carry over the mediaId
551
+ if (!this.player) {
552
+ console.log("Can't create player; no appropriate player type detected.");
553
+ return;
554
+ }
555
+ if (!this.playerCreated) {
556
+ // only call these functions once
557
+ this.loadCurrentPreferences();
558
+ this.injectPlayerCode();
559
+ }
560
+
561
+ // call all remaining functions each time a new media instance is loaded
562
+
563
+ this.initSignLanguage();
564
+
565
+ // thisObj.initializing = true;
566
+ this.initPlayer().then(function() { // initPlayer success
567
+ // thisObj.initializing = false;
568
+
569
+ thisObj.setupTracks().then(function() {
570
+
571
+ thisObj.setupAltCaptions().then(function() {
572
+
573
+ thisObj.setupTranscript().then(function() {
574
+
575
+ if (thisObj.Volume) {
576
+ thisObj.setMute(false);
577
+ }
578
+ thisObj.setFullscreen(false);
579
+ thisObj.setVolume(thisObj.defaultVolume);
580
+
581
+ if (thisObj.transcriptType) {
582
+ thisObj.addTranscriptAreaEvents();
583
+ thisObj.updateTranscript();
584
+ }
585
+ if (thisObj.mediaType === 'video') {
586
+ thisObj.initDescription();
587
+ }
588
+ if (thisObj.captions.length) {
589
+ thisObj.initDefaultCaption();
590
+ }
591
+
592
+ // setMediaAttributes() sets textTrack.mode to 'disabled' for all tracks
593
+ // This tells browsers to ignore the text tracks so Able Player can handle them
594
+ // However, timing is critical as browsers - especially Safari - tend to ignore this request
595
+ // unless it's sent late in the intialization process.
596
+ // If browsers ignore the request, the result is redundant captions
597
+ thisObj.setMediaAttributes();
598
+ thisObj.addControls();
599
+ thisObj.addEventListeners();
600
+
601
+ // inject each of the hidden forms that will be accessed from the Preferences popup menu
602
+ prefsGroups = thisObj.getPreferencesGroups();
603
+ for (i = 0; i < prefsGroups.length; i++) {
604
+ thisObj.injectPrefsForm(prefsGroups[i]);
605
+ }
606
+ thisObj.setupPopups();
607
+ thisObj.updateCaption();
608
+ thisObj.injectVTS();
609
+ if (thisObj.chaptersDivLocation) {
610
+ thisObj.populateChaptersDiv();
611
+ }
612
+ thisObj.showSearchResults();
613
+
614
+ // Go ahead and load media, without user requesting it
615
+ // Normally, we wait until user clicks play, rather than unnecessarily consume their bandwidth
616
+ // Exceptions are if the video is intended to autostart or if running on iOS (a workaround for iOS issues)
617
+ // TODO: Confirm that this is still necessary with iOS (this would added early, & I don't remember what the issues were)
618
+ if (thisObj.player === 'html5' &&
619
+ (thisObj.isIOS() || thisObj.startTime > 0 || thisObj.autoplay || thisObj.okToPlay)) {
620
+ thisObj.$media[0].load();
621
+ }
622
+ // refreshControls is called twice building/initializing the player
623
+ // this is the second. Best to pause a bit before executing, to be sure all prior steps are complete
624
+ setTimeout(function() {
625
+ thisObj.refreshControls('init');
626
+ },100);
627
+ },
628
+ function() { // initPlayer fail
629
+ thisObj.provideFallback();
630
+ });
631
+ });
632
+ });
633
+ });
634
+ };
635
+
636
+ AblePlayer.prototype.initPlayer = function () {
637
+
638
+ var thisObj = this;
639
+ var playerPromise;
640
+
641
+ // First run player specific initialization.
642
+ if (this.player === 'html5') {
643
+ playerPromise = this.initHtml5Player();
644
+ }
645
+ else if (this.player === 'youtube') {
646
+ playerPromise = this.initYouTubePlayer();
647
+ }
648
+ else if (this.player === 'vimeo') {
649
+ playerPromise = this.initVimeoPlayer();
650
+ }
651
+
652
+ // After player specific initialization is done, run remaining general initialization.
653
+ var deferred = new $.Deferred();
654
+ var promise = deferred.promise();
655
+ playerPromise.done(
656
+ function () { // done/resolved
657
+ if (thisObj.useFixedSeekInterval === false) {
658
+ thisObj.setSeekInterval();
659
+ }
660
+ deferred.resolve();
661
+ }
662
+ ).fail(function () { // failed
663
+ deferred.reject();
664
+ }
665
+ );
666
+
667
+ return promise;
668
+ };
669
+
670
+ AblePlayer.prototype.setSeekInterval = function () {
671
+
672
+ // this function is only called if this.useFixedSeekInterval is false
673
+ // if this.useChapterTimes, this is called as each new chapter is loaded
674
+ // otherwise, it's called once, as the player is initialized
675
+ var thisObj, duration;
676
+ thisObj = this;
677
+ this.seekInterval = this.defaultSeekInterval;
678
+
679
+ if (this.useChapterTimes) {
680
+ duration = this.chapterDuration;
681
+ }
682
+ else {
683
+ duration = this.duration;
684
+ }
685
+ if (typeof duration === 'undefined' || duration < 1) {
686
+ // no duration; just use default for now but keep trying until duration is available
687
+ this.seekIntervalCalculated = false;
688
+ return;
689
+ }
690
+ else {
691
+ if (duration <= 20) {
692
+ this.seekInterval = 5; // 4 steps max
693
+ }
694
+ else if (duration <= 30) {
695
+ this.seekInterval = 6; // 5 steps max
696
+ }
697
+ else if (duration <= 40) {
698
+ this.seekInterval = 8; // 5 steps max
699
+ }
700
+ else if (duration <= 100) {
701
+ this.seekInterval = 10; // 10 steps max
702
+ }
703
+ else {
704
+ // never more than 10 steps from start to end
705
+ this.seekInterval = (duration / 10);
706
+ }
707
+ this.seekIntervalCalculated = true;
708
+ }
709
+ };
710
+
711
+ AblePlayer.prototype.initDefaultCaption = function () {
712
+
713
+ var captions, i;
714
+
715
+ captions = this.captions;
716
+
717
+ if (captions.length > 0) {
718
+ for (i=0; i<captions.length; i++) {
719
+ if (captions[i].def === true) {
720
+ this.captionLang = captions[i].language;
721
+ this.selectedCaptions = captions[i];
722
+ }
723
+ }
724
+ if (typeof this.captionLang === 'undefined') {
725
+ // No caption track was flagged as default
726
+ // find and use a caption language that matches the player language
727
+ for (i=0; i<captions.length; i++) {
728
+ if (captions[i].language === this.lang) {
729
+ this.captionLang = captions[i].language;
730
+ this.selectedCaptions = captions[i];
731
+ }
732
+ }
733
+ }
734
+ if (typeof this.captionLang === 'undefined') {
735
+ // Still no matching caption track
736
+ // just use the first track
737
+ this.captionLang = captions[0].language;
738
+ this.selectedCaptions = captions[0];
739
+ }
740
+ if (typeof this.captionLang !== 'undefined') {
741
+ // reset transcript selected <option> to this.captionLang
742
+ if (this.$transcriptLanguageSelect) {
743
+ this.$transcriptLanguageSelect.find('option[lang=' + this.captionLang + ']').prop('selected',true);
744
+ }
745
+ // sync all other tracks to this same languge
746
+ this.syncTrackLanguages('init',this.captionLang);
747
+ }
748
+ }
749
+ };
750
+
751
+ AblePlayer.prototype.initHtml5Player = function () {
752
+ // Nothing special to do!
753
+ var deferred = new $.Deferred();
754
+ var promise = deferred.promise();
755
+ deferred.resolve();
756
+ return promise;
757
+ };
758
+
759
+ // Sets media/track/source attributes; is called whenever player is recreated since $media may have changed.
760
+ AblePlayer.prototype.setMediaAttributes = function () {
761
+ // Firefox puts videos in tab order; remove.
762
+ this.$media.attr('tabindex', -1);
763
+
764
+ // Keep native player from displaying captions/subtitles by setting textTrack.mode='disabled'
765
+ // https://dev.w3.org/html5/spec-author-view/video.html#text-track-mode
766
+ // This *should* work but historically hasn't been supported in all browsers
767
+ // Workaround for non-supporting browsers is to remove default attribute
768
+ // We're doing that too in track.js > setupCaptions()
769
+ var textTracks = this.$media.get(0).textTracks;
770
+ if (textTracks) {
771
+ var i = 0;
772
+ while (i < textTracks.length) {
773
+ textTracks[i].mode = 'disabled';
774
+ i += 1;
775
+ }
776
+ }
777
+ };
778
+
779
+ AblePlayer.prototype.getPlayer = function() {
780
+
781
+ // Determine which player to use, if any
782
+ // return 'html5', 'youtube', 'vimeo', or null
783
+
784
+ var i, sourceType, $newItem;
785
+ if (this.youTubeId) {
786
+ if (this.mediaType !== 'video') {
787
+ // attempting to play a YouTube video using an element other than <video>
788
+ return null;
789
+ }
790
+ else {
791
+ return 'youtube';
792
+ }
793
+ }
794
+ else if (this.vimeoId) {
795
+ if (this.mediaType !== 'video') {
796
+ // attempting to play a Vimeo video using an element other than <video>
797
+ return null;
798
+ }
799
+ else {
800
+ return 'vimeo';
801
+ }
802
+
803
+ }
804
+ else if (this.testFallback ||
805
+ ((this.isUserAgent('msie 7') || this.isUserAgent('msie 8') || this.isUserAgent('msie 9')) && this.mediaType === 'video') ||
806
+ (this.isIOS() && (this.isIOS(4) || this.isIOS(5) || this.isIOS(6)))
807
+ ) {
808
+ // the user wants to test the fallback player, or
809
+ // the user is using an older version of IE or IOS,
810
+ // both of which had buggy implementation of HTML5 video
811
+ return null;
812
+ }
813
+ else if (this.media.canPlayType) {
814
+ return 'html5';
815
+ }
816
+ else {
817
+ // Browser does not support the available media file
818
+ return null;
819
+ }
820
+ };
914
821
 
915
822
  })(jQuery);