wai-website-theme 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +52 -0
  4. data/_data/lang.json +730 -0
  5. data/_data/techniques.yml +180 -0
  6. data/_data/wcag.yml +125 -0
  7. data/_includes/.DS_Store +0 -0
  8. data/_includes/body-class.html +1 -0
  9. data/_includes/box.html +10 -0
  10. data/_includes/excol.html +13 -0
  11. data/_includes/footer.html +40 -0
  12. data/_includes/head.html +23 -0
  13. data/_includes/header.html +59 -0
  14. data/_includes/icon.html +6 -0
  15. data/_includes/img.html +17 -0
  16. data/_includes/multilang-list-policy-links.html +29 -0
  17. data/_includes/multilang-list.html +35 -0
  18. data/_includes/multilang-policy-title.html +5 -0
  19. data/_includes/multilang-title-full.html +1 -0
  20. data/_includes/multilang-title.html +1 -0
  21. data/_includes/navlist.html +22 -0
  22. data/_includes/notes.html +2 -0
  23. data/_includes/prevnext.html +34 -0
  24. data/_includes/resources.html +19 -0
  25. data/_includes/sidenav.html +65 -0
  26. data/_includes/sidenote.html +14 -0
  27. data/_includes/toc.html +10 -0
  28. data/_includes/video-player.html +99 -0
  29. data/_layouts/default.html +26 -0
  30. data/_layouts/home.html +14 -0
  31. data/_layouts/news.html +21 -0
  32. data/_layouts/none.html +1 -0
  33. data/_layouts/policy.html +72 -0
  34. data/_layouts/sidenav.html +27 -0
  35. data/_layouts/sidenavsidebar.html +22 -0
  36. data/assets/ableplayer/.gitattributes +14 -0
  37. data/assets/ableplayer/.gitignore +7 -0
  38. data/assets/ableplayer/Gruntfile.js +105 -0
  39. data/assets/ableplayer/LICENSE +26 -0
  40. data/assets/ableplayer/README.md +656 -0
  41. data/assets/ableplayer/build/ableplayer.dist.js +12157 -0
  42. data/assets/ableplayer/build/ableplayer.js +12157 -0
  43. data/assets/ableplayer/build/ableplayer.min.css +2 -0
  44. data/assets/ableplayer/build/ableplayer.min.js +8 -0
  45. data/assets/ableplayer/button-icons/able-icons.svg +116 -0
  46. data/assets/ableplayer/button-icons/black/captions.png +0 -0
  47. data/assets/ableplayer/button-icons/black/chapters.png +0 -0
  48. data/assets/ableplayer/button-icons/black/close.png +0 -0
  49. data/assets/ableplayer/button-icons/black/descriptions.png +0 -0
  50. data/assets/ableplayer/button-icons/black/ellipsis.png +0 -0
  51. data/assets/ableplayer/button-icons/black/faster.png +0 -0
  52. data/assets/ableplayer/button-icons/black/forward.png +0 -0
  53. data/assets/ableplayer/button-icons/black/fullscreen-collapse.png +0 -0
  54. data/assets/ableplayer/button-icons/black/fullscreen-expand.png +0 -0
  55. data/assets/ableplayer/button-icons/black/help.png +0 -0
  56. data/assets/ableplayer/button-icons/black/next.png +0 -0
  57. data/assets/ableplayer/button-icons/black/pause.png +0 -0
  58. data/assets/ableplayer/button-icons/black/pipe.png +0 -0
  59. data/assets/ableplayer/button-icons/black/play.png +0 -0
  60. data/assets/ableplayer/button-icons/black/preferences.png +0 -0
  61. data/assets/ableplayer/button-icons/black/previous.png +0 -0
  62. data/assets/ableplayer/button-icons/black/rabbit.png +0 -0
  63. data/assets/ableplayer/button-icons/black/restart.png +0 -0
  64. data/assets/ableplayer/button-icons/black/rewind.png +0 -0
  65. data/assets/ableplayer/button-icons/black/sign.png +0 -0
  66. data/assets/ableplayer/button-icons/black/slower.png +0 -0
  67. data/assets/ableplayer/button-icons/black/stop.png +0 -0
  68. data/assets/ableplayer/button-icons/black/transcript.png +0 -0
  69. data/assets/ableplayer/button-icons/black/turtle.png +0 -0
  70. data/assets/ableplayer/button-icons/black/volume-loud.png +0 -0
  71. data/assets/ableplayer/button-icons/black/volume-medium.png +0 -0
  72. data/assets/ableplayer/button-icons/black/volume-mute.png +0 -0
  73. data/assets/ableplayer/button-icons/black/volume-soft.png +0 -0
  74. data/assets/ableplayer/button-icons/fonts/able.eot +0 -0
  75. data/assets/ableplayer/button-icons/fonts/able.svg +40 -0
  76. data/assets/ableplayer/button-icons/fonts/able.ttf +0 -0
  77. data/assets/ableplayer/button-icons/fonts/able.woff +0 -0
  78. data/assets/ableplayer/button-icons/white/captions.png +0 -0
  79. data/assets/ableplayer/button-icons/white/chapters.png +0 -0
  80. data/assets/ableplayer/button-icons/white/close.png +0 -0
  81. data/assets/ableplayer/button-icons/white/descriptions.png +0 -0
  82. data/assets/ableplayer/button-icons/white/ellipsis.png +0 -0
  83. data/assets/ableplayer/button-icons/white/faster.png +0 -0
  84. data/assets/ableplayer/button-icons/white/forward.png +0 -0
  85. data/assets/ableplayer/button-icons/white/fullscreen-collapse.png +0 -0
  86. data/assets/ableplayer/button-icons/white/fullscreen-expand.png +0 -0
  87. data/assets/ableplayer/button-icons/white/help.png +0 -0
  88. data/assets/ableplayer/button-icons/white/next.png +0 -0
  89. data/assets/ableplayer/button-icons/white/pause.png +0 -0
  90. data/assets/ableplayer/button-icons/white/pipe.png +0 -0
  91. data/assets/ableplayer/button-icons/white/play.png +0 -0
  92. data/assets/ableplayer/button-icons/white/preferences.png +0 -0
  93. data/assets/ableplayer/button-icons/white/previous.png +0 -0
  94. data/assets/ableplayer/button-icons/white/rabbit.png +0 -0
  95. data/assets/ableplayer/button-icons/white/restart.png +0 -0
  96. data/assets/ableplayer/button-icons/white/rewind.png +0 -0
  97. data/assets/ableplayer/button-icons/white/sign.png +0 -0
  98. data/assets/ableplayer/button-icons/white/slower.png +0 -0
  99. data/assets/ableplayer/button-icons/white/stop.png +0 -0
  100. data/assets/ableplayer/button-icons/white/transcript.png +0 -0
  101. data/assets/ableplayer/button-icons/white/turtle.png +0 -0
  102. data/assets/ableplayer/button-icons/white/volume-loud.png +0 -0
  103. data/assets/ableplayer/button-icons/white/volume-medium.png +0 -0
  104. data/assets/ableplayer/button-icons/white/volume-mute.png +0 -0
  105. data/assets/ableplayer/button-icons/white/volume-soft.png +0 -0
  106. data/assets/ableplayer/images/wingrip.png +0 -0
  107. data/assets/ableplayer/package.json +22 -0
  108. data/assets/ableplayer/scripts/JQuery.doWhen.js +113 -0
  109. data/assets/ableplayer/scripts/ableplayer-base.js +440 -0
  110. data/assets/ableplayer/scripts/browser.js +162 -0
  111. data/assets/ableplayer/scripts/buildplayer.js +1609 -0
  112. data/assets/ableplayer/scripts/caption.js +385 -0
  113. data/assets/ableplayer/scripts/chapters.js +242 -0
  114. data/assets/ableplayer/scripts/control.js +1514 -0
  115. data/assets/ableplayer/scripts/description.js +283 -0
  116. data/assets/ableplayer/scripts/dialog.js +147 -0
  117. data/assets/ableplayer/scripts/dragdrop.js +766 -0
  118. data/assets/ableplayer/scripts/event.js +595 -0
  119. data/assets/ableplayer/scripts/initialize.js +725 -0
  120. data/assets/ableplayer/scripts/langs.js +750 -0
  121. data/assets/ableplayer/scripts/metadata.js +134 -0
  122. data/assets/ableplayer/scripts/misc.js +72 -0
  123. data/assets/ableplayer/scripts/preference.js +909 -0
  124. data/assets/ableplayer/scripts/search.js +171 -0
  125. data/assets/ableplayer/scripts/sign.js +92 -0
  126. data/assets/ableplayer/scripts/slider.js +454 -0
  127. data/assets/ableplayer/scripts/track.js +296 -0
  128. data/assets/ableplayer/scripts/transcript.js +590 -0
  129. data/assets/ableplayer/scripts/translation.js +66 -0
  130. data/assets/ableplayer/scripts/volume.js +383 -0
  131. data/assets/ableplayer/scripts/webvtt.js +765 -0
  132. data/assets/ableplayer/scripts/youtube.js +471 -0
  133. data/assets/ableplayer/styles/ableplayer.css +1241 -0
  134. data/assets/ableplayer/thirdparty/js.cookie.js +145 -0
  135. data/assets/ableplayer/thirdparty/modernizr.custom.js +4 -0
  136. data/assets/ableplayer/translations/ca.js +1 -0
  137. data/assets/ableplayer/translations/de.js +1 -0
  138. data/assets/ableplayer/translations/en.js +305 -0
  139. data/assets/ableplayer/translations/es.js +305 -0
  140. data/assets/ableplayer/translations/fr.js +305 -0
  141. data/assets/ableplayer/translations/it.js +303 -0
  142. data/assets/ableplayer/translations/ja.js +305 -0
  143. data/assets/ableplayer/translations/nl.js +305 -0
  144. data/assets/css/style.css +4360 -0
  145. data/assets/css/style.css.map +1 -0
  146. data/assets/fonts/anonymouspro-bold.woff +0 -0
  147. data/assets/fonts/anonymouspro-bold.woff2 +0 -0
  148. data/assets/fonts/anonymouspro-bolditalic.woff +0 -0
  149. data/assets/fonts/anonymouspro-bolditalic.woff2 +0 -0
  150. data/assets/fonts/anonymouspro-italic.woff +0 -0
  151. data/assets/fonts/anonymouspro-italic.woff2 +0 -0
  152. data/assets/fonts/anonymouspro-regular.woff +0 -0
  153. data/assets/fonts/anonymouspro-regular.woff2 +0 -0
  154. data/assets/fonts/notosans-bold.woff +0 -0
  155. data/assets/fonts/notosans-bold.woff2 +0 -0
  156. data/assets/fonts/notosans-bolditalic.woff +0 -0
  157. data/assets/fonts/notosans-bolditalic.woff2 +0 -0
  158. data/assets/fonts/notosans-italic.woff +0 -0
  159. data/assets/fonts/notosans-italic.woff2 +0 -0
  160. data/assets/fonts/notosans-regular.woff +0 -0
  161. data/assets/fonts/notosans-regular.woff2 +0 -0
  162. data/assets/images/.DS_Store +0 -0
  163. data/assets/images/Shape.svg +10 -0
  164. data/assets/images/icon-related-content.svg +14 -0
  165. data/assets/images/icons.svg +126 -0
  166. data/assets/images/teaser-image@1x.jpg +0 -0
  167. data/assets/images/teaser-image@2x.jpg +0 -0
  168. data/assets/images/w3c.sketch +0 -0
  169. data/assets/images/w3c.svg +10 -0
  170. data/assets/scripts/jquery.min.js +4 -0
  171. data/assets/scripts/main.js +208 -0
  172. data/assets/scripts/svg4everybody.js +1 -0
  173. metadata +257 -0
@@ -0,0 +1,595 @@
1
+ (function ($) {
2
+ // Media events
3
+ AblePlayer.prototype.onMediaUpdateTime = function () {
4
+
5
+ var currentTime = this.getElapsed();
6
+ if (this.swappingSrc && (typeof this.swapTime !== 'undefined')) {
7
+ if (this.swapTime === currentTime) {
8
+ // described version been swapped and media has scrubbed to time of previous version
9
+ if (this.playing) {
10
+ // resume playback
11
+ this.playMedia();
12
+ // reset vars
13
+ this.swappingSrc = false;
14
+ this.swapTime = null;
15
+ }
16
+ }
17
+ }
18
+ else if (this.startedPlaying) {
19
+ // do all the usual time-sync stuff during playback
20
+ if (this.prefHighlight === 1) {
21
+ this.highlightTranscript(currentTime);
22
+ }
23
+ this.updateCaption();
24
+ this.showDescription(currentTime);
25
+ this.updateChapter(currentTime);
26
+ this.updateMeta();
27
+ this.refreshControls();
28
+ }
29
+ };
30
+
31
+ AblePlayer.prototype.onMediaPause = function () {
32
+ // do something
33
+ };
34
+
35
+ AblePlayer.prototype.onMediaComplete = function () {
36
+ // if there's a playlist, advance to next item and start playing
37
+ if (this.hasPlaylist) {
38
+ if (this.playlistIndex === (this.$playlist.length - 1)) {
39
+ // this is the last track in the playlist
40
+ if (this.loop) {
41
+ this.playlistIndex = 0;
42
+ this.swapSource(0);
43
+ }
44
+ }
45
+ else {
46
+ // this is not the last track. Play the next one.
47
+ this.playlistIndex++;
48
+ this.swapSource(this.playlistIndex)
49
+ }
50
+ }
51
+ this.refreshControls();
52
+ };
53
+
54
+ AblePlayer.prototype.onMediaNewSourceLoad = function () {
55
+
56
+ if (this.swappingSrc === true) {
57
+ // new source file has just been loaded
58
+ if (this.swapTime > 0) {
59
+ // this.swappingSrc will be set to false after seek is complete
60
+ // see onMediaUpdateTime()
61
+ this.seekTo(this.swapTime);
62
+ }
63
+ else {
64
+ if (this.playing) {
65
+ // should be able to resume playback
66
+ if (this.player === 'jw') {
67
+ var player = this.jwPlayer;
68
+ // Seems to be a bug in JW player, where this doesn't work when fired immediately.
69
+ // Thus have to use a setTimeout
70
+ setTimeout(function () {
71
+ player.play(true);
72
+ }, 500);
73
+ }
74
+ else {
75
+ this.playMedia();
76
+ }
77
+ }
78
+ this.swappingSrc = false; // swapping is finished
79
+ this.refreshControls();
80
+ }
81
+ }
82
+ };
83
+
84
+ // End Media events
85
+
86
+ AblePlayer.prototype.onWindowResize = function () {
87
+
88
+ if (this.isFullscreen()) {
89
+
90
+ var newWidth, newHeight;
91
+
92
+ newWidth = $(window).width();
93
+
94
+ // haven't isolated why, but some browsers return an innerHeight that's 20px too tall in fullscreen mode
95
+ // Test results:
96
+ // Browsers that require a 20px adjustment: Firefox, IE11 (Trident), Edge
97
+ if (this.isUserAgent('Firefox') || this.isUserAgent('Trident') || this.isUserAgent('Edge')) {
98
+ newHeight = window.innerHeight - this.$playerDiv.outerHeight() - 20;
99
+ }
100
+ else if (window.outerHeight >= window.innerHeight) {
101
+ // Browsers that do NOT require adjustment: Chrome, Safari, Opera, MSIE 10
102
+ newHeight = window.innerHeight - this.$playerDiv.outerHeight();
103
+ }
104
+ else {
105
+ // Observed in Safari 9.0.1 on Mac OS X: outerHeight is actually less than innerHeight
106
+ // Maybe a bug, or maybe window.outerHeight is already adjusted for controller height(?)
107
+ // No longer observed in Safari 9.0.2
108
+ newHeight = window.outerHeight;
109
+ }
110
+ if (!this.$descDiv.is(':hidden')) {
111
+ newHeight -= this.$descDiv.height();
112
+ }
113
+ this.positionCaptions('overlay');
114
+ }
115
+ else { // not fullscreen
116
+ if (this.restoringAfterFullScreen) {
117
+ newWidth = this.preFullScreenWidth;
118
+ newHeight = this.preFullScreenHeight;
119
+ }
120
+ else {
121
+ // not restoring after full screen
122
+ newWidth = this.$ableWrapper.width();
123
+ if (typeof this.aspectRatio !== 'undefined') {
124
+ newHeight = Math.round(newWidth / this.aspectRatio);
125
+ }
126
+ else {
127
+ // not likely, since this.aspectRatio is defined during intialization
128
+ // however, this is a fallback scenario just in case
129
+ newHeight = this.$ableWrapper.height();
130
+ }
131
+ this.positionCaptions(); // reset with this.prefCaptionsPosition
132
+ }
133
+ }
134
+ this.resizePlayer(newWidth, newHeight);
135
+ };
136
+
137
+ AblePlayer.prototype.addSeekbarListeners = function () {
138
+ var thisObj = this;
139
+
140
+ // Handle seek bar events.
141
+ this.seekBar.bodyDiv.on('startTracking', function (event) {
142
+ thisObj.pausedBeforeTracking = thisObj.isPaused();
143
+ thisObj.pauseMedia();
144
+ }).on('tracking', function (event, position) {
145
+ // Scrub transcript, captions, and metadata.
146
+ thisObj.highlightTranscript(position);
147
+ thisObj.updateCaption(position);
148
+ thisObj.showDescription(position);
149
+ thisObj.updateChapter(thisObj.convertChapterTimeToVideoTime(position));
150
+ thisObj.updateMeta(position);
151
+ thisObj.refreshControls();
152
+ }).on('stopTracking', function (event, position) {
153
+ if (thisObj.useChapterTimes) {
154
+ thisObj.seekTo(thisObj.convertChapterTimeToVideoTime(position));
155
+ }
156
+ else {
157
+ thisObj.seekTo(position);
158
+ }
159
+ if (!thisObj.pausedBeforeTracking) {
160
+ setTimeout(function () {
161
+ thisObj.playMedia();
162
+ }, 200);
163
+ }
164
+ });
165
+ };
166
+
167
+ AblePlayer.prototype.onClickPlayerButton = function (el) {
168
+ // TODO: This is super-fragile since we need to know the length of the class name to split off; update this to other way of dispatching?
169
+ var whichButton = $(el).attr('class').split(' ')[0].substr(20);
170
+ if (whichButton === 'play') {
171
+ this.handlePlay();
172
+ }
173
+ else if (whichButton === 'restart') {
174
+ this.handleRestart();
175
+ }
176
+ else if (whichButton === 'rewind') {
177
+ this.handleRewind();
178
+ }
179
+ else if (whichButton === 'forward') {
180
+ this.handleFastForward();
181
+ }
182
+ else if (whichButton === 'mute') {
183
+ this.handleMute();
184
+ }
185
+ else if (whichButton === 'volume') {
186
+ this.handleVolume();
187
+ }
188
+ else if (whichButton === 'faster') {
189
+ this.handleRateIncrease();
190
+ }
191
+ else if (whichButton === 'slower') {
192
+ this.handleRateDecrease();
193
+ }
194
+ else if (whichButton === 'captions') {
195
+ this.handleCaptionToggle();
196
+ }
197
+ else if (whichButton === 'chapters') {
198
+ this.handleChapters();
199
+ }
200
+ else if (whichButton === 'descriptions') {
201
+ this.handleDescriptionToggle();
202
+ }
203
+ else if (whichButton === 'sign') {
204
+ this.handleSignToggle();
205
+ }
206
+ else if (whichButton === 'preferences') {
207
+ this.handlePrefsClick();
208
+ }
209
+ else if (whichButton === 'help') {
210
+ this.handleHelpClick();
211
+ }
212
+ else if (whichButton === 'transcript') {
213
+ this.handleTranscriptToggle();
214
+ }
215
+ else if (whichButton === 'fullscreen') {
216
+ this.handleFullscreenToggle();
217
+ }
218
+ };
219
+
220
+ AblePlayer.prototype.okToHandleKeyPress = function () {
221
+
222
+ // returns true unless user's focus is on a UI element
223
+ // that is likely to need supported keystrokes, including space
224
+ var activeElement = $(document.activeElement).prop('tagName');
225
+ if (activeElement === 'INPUT') {
226
+ return false;
227
+ }
228
+ else {
229
+ return true;
230
+ }
231
+ }
232
+
233
+ AblePlayer.prototype.onPlayerKeyPress = function (e) {
234
+ // handle keystrokes (using DHTML Style Guide recommended key combinations)
235
+ // http://dev.aol.com/dhtml_style_guide/#mediaplayer
236
+ // Modifier keys Alt + Ctrl are on by default, but can be changed within Preferences
237
+ // NOTE #1: Style guide only supports Play/Pause, Stop, Mute, Captions, & Volume Up & Down
238
+ // The rest are reasonable best choices
239
+ // NOTE #2: If there are multiple players on a single page, keystroke handlers
240
+ // are only bound to the FIRST player
241
+ if (!this.okToHandleKeyPress()) {
242
+ return false;
243
+ }
244
+ // Convert to lower case.
245
+ var which = e.which;
246
+
247
+ if (which >= 65 && which <= 90) {
248
+ which += 32;
249
+ }
250
+ if (which === 27) {
251
+ this.closePopups();
252
+ }
253
+ else if (which === 32) { // spacebar = play/pause
254
+ if (!($('.able-controller button').is(':focus'))) {
255
+ // only toggle play if a button does not have focus
256
+ // if a button has focus, space should activate that button
257
+ this.handlePlay();
258
+ }
259
+ }
260
+ else if (which === 112) { // p = play/pause
261
+ if (this.usingModifierKeys(e)) {
262
+ this.handlePlay();
263
+ }
264
+ }
265
+ else if (which === 115) { // s = stop (now restart)
266
+ if (this.usingModifierKeys(e)) {
267
+ this.handleRestart();
268
+ }
269
+ }
270
+ else if (which === 109) { // m = mute
271
+ if (this.usingModifierKeys(e)) {
272
+ this.handleMute();
273
+ }
274
+ }
275
+ else if (which === 118) { // v = volume
276
+ if (this.usingModifierKeys(e)) {
277
+ this.handleVolume();
278
+ }
279
+ }
280
+ else if (which >= 49 && which <= 57) { // set volume 1-9
281
+ if (this.usingModifierKeys(e)) {
282
+ this.handleVolume(which);
283
+ }
284
+ }
285
+ else if (which === 99) { // c = caption toggle
286
+ if (this.usingModifierKeys(e)) {
287
+ this.handleCaptionToggle();
288
+ }
289
+ }
290
+ else if (which === 100) { // d = description
291
+ if (this.usingModifierKeys(e)) {
292
+ this.handleDescriptionToggle();
293
+ }
294
+ }
295
+ else if (which === 102) { // f = forward
296
+ if (this.usingModifierKeys(e)) {
297
+ this.handleFastForward();
298
+ }
299
+ }
300
+ else if (which === 114) { // r = rewind
301
+ if (this.usingModifierKeys(e)) {
302
+ this.handleRewind();
303
+ }
304
+ }
305
+ else if (which === 101) { // e = preferences
306
+ if (this.usingModifierKeys(e)) {
307
+ this.handlePrefsClick();
308
+ }
309
+ }
310
+ else if (which === 13) { // Enter
311
+ var thisElement = $(document.activeElement);
312
+ if (thisElement.prop('tagName') === 'SPAN') {
313
+ // register a click on this SPAN
314
+ // if it's a transcript span the transcript span click handler will take over
315
+ thisElement.click();
316
+ }
317
+ else if (thisElement.prop('tagName') === 'LI') {
318
+ thisElement.click();
319
+ }
320
+ }
321
+ };
322
+
323
+ AblePlayer.prototype.addHtml5MediaListeners = function () {
324
+
325
+ var thisObj = this;
326
+
327
+ // NOTE: iOS does not support autoplay,
328
+ // and no events are triggered until media begins to play
329
+ this.$media
330
+ .on('emptied',function() {
331
+ // do something
332
+ })
333
+ .on('loadedmetadata',function() {
334
+ thisObj.onMediaNewSourceLoad();
335
+ })
336
+ .on('canplay',function() {
337
+ // previously handled seeking to startTime here
338
+ // but it's probably safer to wait for canplaythrough
339
+ // so we know player can seek ahead to anything
340
+ })
341
+ .on('canplaythrough',function() {
342
+ if (!thisObj.startedPlaying) {
343
+ if (thisObj.startTime) {
344
+ if (thisObj.seeking) {
345
+ // a seek has already been initiated
346
+ // since canplaythrough has been triggered, the seek is complete
347
+ thisObj.seeking = false;
348
+ if (thisObj.autoplay) {
349
+ thisObj.playMedia();
350
+ }
351
+ }
352
+ else {
353
+ // haven't started seeking yet
354
+ thisObj.seekTo(thisObj.startTime);
355
+ }
356
+ }
357
+ else if (thisObj.defaultChapter && typeof thisObj.selectedChapters !== 'undefined') {
358
+ thisObj.seekToChapter(thisObj.defaultChapter);
359
+ }
360
+ else {
361
+ // there is now startTime, therefore no seeking required
362
+ if (thisObj.autoplay) {
363
+ thisObj.playMedia();
364
+ }
365
+ }
366
+ }
367
+ else {
368
+ // already started playing
369
+ }
370
+ })
371
+ .on('playing',function() {
372
+ thisObj.playing = true;
373
+ thisObj.refreshControls();
374
+ })
375
+ .on('ended',function() {
376
+ thisObj.onMediaComplete();
377
+ })
378
+ .on('progress', function() {
379
+ thisObj.refreshControls();
380
+ })
381
+ .on('waiting',function() {
382
+ thisObj.refreshControls();
383
+ })
384
+ .on('durationchange',function() {
385
+ // Display new duration.
386
+ thisObj.refreshControls();
387
+ })
388
+ .on('timeupdate',function() {
389
+ thisObj.onMediaUpdateTime();
390
+ })
391
+ .on('play',function() {
392
+ if (thisObj.debug) {
393
+ console.log('media play event');
394
+ }
395
+ })
396
+ .on('pause',function() {
397
+ thisObj.onMediaPause();
398
+ })
399
+ .on('ratechange',function() {
400
+ // do something
401
+ })
402
+ .on('volumechange',function() {
403
+ thisObj.volume = thisObj.getVolume();
404
+ if (thisObj.debug) {
405
+ console.log('media volume change to ' + thisObj.volume + ' (' + thisObj.volumeButton + ')');
406
+ }
407
+ })
408
+ .on('error',function() {
409
+ if (thisObj.debug) {
410
+ switch (thisObj.media.error.code) {
411
+ case 1:
412
+ console.log('HTML5 Media Error: MEDIA_ERR_ABORTED');
413
+ break;
414
+ case 2:
415
+ console.log('HTML5 Media Error: MEDIA_ERR_NETWORK ');
416
+ break;
417
+ case 3:
418
+ console.log('HTML5 Media Error: MEDIA_ERR_DECODE ');
419
+ break;
420
+ case 4:
421
+ console.log('HTML5 Media Error: MEDIA_ERR_SRC_NOT_SUPPORTED ');
422
+ break;
423
+ }
424
+ }
425
+ });
426
+ };
427
+
428
+ AblePlayer.prototype.addJwMediaListeners = function () {
429
+ var thisObj = this;
430
+ // add listeners for JW Player events
431
+ this.jwPlayer
432
+ .onTime(function() {
433
+ thisObj.onMediaUpdateTime();
434
+ })
435
+ .onComplete(function() {
436
+ thisObj.onMediaComplete();
437
+ })
438
+ .onReady(function() {
439
+ if (thisObj.debug) {
440
+ console.log('JW Player onReady event fired');
441
+ }
442
+ // remove JW Player from tab order.
443
+ // We don't want users tabbing into the Flash object and getting trapped
444
+ $('#' + thisObj.jwId).removeAttr('tabindex');
445
+
446
+ // JW Player was initialized with no explicit width or height; get them now
447
+ thisObj.$fallbackWrapper = $('#' + thisObj.mediaId + '_fallback_wrapper');
448
+ thisObj.fallbackDefaultWidth = thisObj.$fallbackWrapper.width();
449
+ thisObj.fallbackDefaultHeight = thisObj.$fallbackWrapper.height();
450
+ thisObj.fallbackRatio = thisObj.fallbackDefaultWidth / thisObj.fallbackDefaultHeight;
451
+
452
+ if (thisObj.startTime > 0 && !thisObj.startedPlaying) {
453
+ thisObj.seekTo(thisObj.startTime);
454
+ thisObj.startedPlaying = true;
455
+ }
456
+ thisObj.refreshControls();
457
+ })
458
+ .onSeek(function(event) {
459
+ // this is called when user scrubs ahead or back,
460
+ // after the target offset is reached
461
+ if (thisObj.debug) {
462
+ console.log('Seeking to ' + event.position + '; target: ' + event.offset);
463
+ }
464
+
465
+ if (thisObj.jwSeekPause) {
466
+ // media was temporarily paused
467
+ thisObj.jwSeekPause = false;
468
+ thisObj.playMedia();
469
+ }
470
+
471
+ setTimeout(function () {
472
+ thisObj.refreshControls();
473
+ }, 300);
474
+ })
475
+ .onPlay(function() {
476
+ if (thisObj.debug) {
477
+ console.log('JW Player onPlay event fired');
478
+ }
479
+ thisObj.refreshControls();
480
+ })
481
+ .onPause(function() {
482
+ thisObj.onMediaPause();
483
+ })
484
+ .onBuffer(function() {
485
+ if (thisObj.debug) {
486
+ console.log('JW Player onBuffer event fired');
487
+ }
488
+ thisObj.refreshControls();
489
+ })
490
+ .onBufferChange(function() {
491
+ thisObj.refreshControls();
492
+ })
493
+ .onIdle(function(e) {
494
+ if (thisObj.debug) {
495
+ console.log('JW Player onIdle event fired');
496
+ }
497
+ thisObj.refreshControls();
498
+ })
499
+ .onMeta(function() {
500
+ if (thisObj.debug) {
501
+ console.log('JW Player onMeta event fired');
502
+ }
503
+ })
504
+ .onPlaylist(function() {
505
+ if (thisObj.debug) {
506
+ console.log('JW Player onPlaylist event fired');
507
+ }
508
+
509
+ // Playlist change includes new media source.
510
+ thisObj.onMediaNewSourceLoad();
511
+ });
512
+ };
513
+
514
+ AblePlayer.prototype.addEventListeners = function () {
515
+ var thisObj, whichButton, thisElement;
516
+
517
+ // Save the current object context in thisObj for use with inner functions.
518
+ thisObj = this;
519
+
520
+ // Appropriately resize media player for full screen.
521
+ $(window).resize(function () {
522
+ thisObj.onWindowResize();
523
+ });
524
+
525
+ // Refresh player if it changes from hidden to visible
526
+ // There is no event triggered by a change in visibility
527
+ // but MutationObserver works in most browsers:
528
+ // http://caniuse.com/#feat=mutationobserver
529
+ var target = this.$ableDiv[0];
530
+ var observer = new MutationObserver(function(mutations) {
531
+ mutations.forEach(function(mutation) {
532
+ if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
533
+ // the player's style attribute has changed. Check to see if it's visible
534
+ if (thisObj.$ableDiv.is(':visible')) {
535
+ thisObj.refreshControls();
536
+ }
537
+ }
538
+ });
539
+ });
540
+ var config = { attributes: true, childList: true, characterData: true };
541
+ observer.observe(target, config);
542
+
543
+ this.addSeekbarListeners();
544
+
545
+ // handle clicks on player buttons
546
+ this.$controllerDiv.find('button').on('click',function(){
547
+ thisObj.onClickPlayerButton(this);
548
+ });
549
+
550
+ // handle local keydown events if this isn't the only player on the page;
551
+ // otherwise these are dispatched by global handler (see ableplayer-base,js)
552
+ this.$ableDiv.keydown(function (e) {
553
+ if (AblePlayer.nextIndex > 1) {
554
+ thisObj.onPlayerKeyPress(e);
555
+ }
556
+ });
557
+
558
+ // transcript is not a child of this.$ableDiv
559
+ // therefore, must be added separately
560
+ if (this.$transcriptArea) {
561
+ this.$transcriptArea.keydown(function (e) {
562
+ if (AblePlayer.nextIndex > 1) {
563
+ thisObj.onPlayerKeyPress(e);
564
+ }
565
+ });
566
+ }
567
+
568
+ // handle clicks on playlist items
569
+ if (this.$playlist) {
570
+ this.$playlist.click(function() {
571
+ thisObj.playlistIndex = $(this).index();
572
+ thisObj.swapSource(thisObj.playlistIndex);
573
+ });
574
+ }
575
+
576
+ // Also play/pause when clicking on the media.
577
+ this.$media.click(function () {
578
+ thisObj.handlePlay();
579
+ });
580
+
581
+ // add listeners for media events
582
+ if (this.player === 'html5') {
583
+ this.addHtml5MediaListeners();
584
+ }
585
+ else if (this.player === 'jw') {
586
+ this.addJwMediaListeners();
587
+ }
588
+ else if (this.player === 'youtube') {
589
+ // Youtube doesn't give us time update events, so we just periodically generate them ourselves
590
+ setInterval(function () {
591
+ thisObj.onMediaUpdateTime();
592
+ }, 300);
593
+ }
594
+ };
595
+ })(jQuery);