wai-website-theme 1.3.1 → 1.4
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.
- checksums.yaml +4 -4
- data/_includes/different.html +2 -1
- data/_includes/external.html +2 -1
- data/_includes/header.html +2 -1
- data/_includes/menuitem.html +6 -2
- data/_includes/peoplelist.html +21 -0
- data/_includes/prevnext-navigation.html +56 -0
- data/_includes/{prevnext.html → prevnext-order.html} +9 -0
- data/_includes/translation-note-msg.html +5 -3
- data/_includes/video-player.html +2 -2
- data/_layouts/default.html +8 -1
- data/_layouts/news.html +7 -1
- data/_layouts/policy.html +7 -1
- data/_layouts/sidenav.html +8 -1
- data/_layouts/sidenavsidebar.html +8 -1
- data/assets/ableplayer/Gruntfile.js +2 -1
- data/assets/ableplayer/README.md +158 -85
- data/assets/ableplayer/build/ableplayer.dist.js +15445 -13823
- data/assets/ableplayer/build/ableplayer.js +15445 -13823
- data/assets/ableplayer/build/ableplayer.min.css +1 -2
- data/assets/ableplayer/build/ableplayer.min.js +3 -10
- data/assets/ableplayer/package-lock.json +944 -346
- data/assets/ableplayer/package.json +8 -8
- data/assets/ableplayer/scripts/ableplayer-base.js +515 -524
- data/assets/ableplayer/scripts/browser.js +158 -158
- data/assets/ableplayer/scripts/buildplayer.js +1750 -1682
- data/assets/ableplayer/scripts/caption.js +424 -401
- data/assets/ableplayer/scripts/chapters.js +259 -259
- data/assets/ableplayer/scripts/control.js +1831 -1594
- data/assets/ableplayer/scripts/description.js +333 -256
- data/assets/ableplayer/scripts/dialog.js +145 -145
- data/assets/ableplayer/scripts/dragdrop.js +746 -749
- data/assets/ableplayer/scripts/event.js +875 -696
- data/assets/ableplayer/scripts/initialize.js +819 -912
- data/assets/ableplayer/scripts/langs.js +979 -743
- data/assets/ableplayer/scripts/metadata.js +124 -124
- data/assets/ableplayer/scripts/misc.js +170 -137
- data/assets/ableplayer/scripts/preference.js +904 -904
- data/assets/ableplayer/scripts/search.js +172 -172
- data/assets/ableplayer/scripts/sign.js +82 -78
- data/assets/ableplayer/scripts/slider.js +449 -448
- data/assets/ableplayer/scripts/track.js +409 -309
- data/assets/ableplayer/scripts/transcript.js +684 -595
- data/assets/ableplayer/scripts/translation.js +63 -67
- data/assets/ableplayer/scripts/ttml2webvtt.js +85 -85
- data/assets/ableplayer/scripts/vimeo.js +448 -0
- data/assets/ableplayer/scripts/volume.js +395 -380
- data/assets/ableplayer/scripts/vts.js +1077 -1077
- data/assets/ableplayer/scripts/webvtt.js +766 -763
- data/assets/ableplayer/scripts/youtube.js +695 -478
- data/assets/ableplayer/styles/ableplayer.css +54 -46
- data/assets/ableplayer/translations/nl.js +54 -54
- data/assets/ableplayer/translations/pt-br.js +311 -0
- data/assets/ableplayer/translations/tr.js +311 -0
- data/assets/ableplayer/translations/zh-tw.js +1 -1
- data/assets/css/style.css +1 -1
- data/assets/css/style.css.map +1 -1
- data/assets/images/icons.svg +5 -5
- data/assets/scripts/main.js +7 -0
- data/assets/search/tipuesearch.js +3 -3
- metadata +8 -3
|
@@ -4,1090 +4,1090 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
(function ($) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
7
|
+
AblePlayer.prototype.injectVTS = function() {
|
|
8
|
+
|
|
9
|
+
// To add a transcript sorter to a web page:
|
|
10
|
+
// Add <div id="able-vts"></div> to the web page
|
|
11
|
+
|
|
12
|
+
// Define all variables
|
|
13
|
+
var thisObj, tracks, $heading;
|
|
14
|
+
var $instructions, $p1, $p2, $ul, $li1, $li2, $li3;
|
|
15
|
+
var $fieldset, $legend, i, $radioDiv, radioId, $label, $radio;
|
|
16
|
+
var $saveButton, $savedTable;
|
|
17
|
+
|
|
18
|
+
thisObj = this;
|
|
19
|
+
|
|
20
|
+
if ($('#able-vts').length) {
|
|
21
|
+
// Page includes a container for a VTS instance
|
|
22
|
+
|
|
23
|
+
// Are they qualifying tracks?
|
|
24
|
+
if (this.vtsTracks.length) {
|
|
25
|
+
// Yes - there are!
|
|
26
|
+
|
|
27
|
+
// Build an array of unique languages
|
|
28
|
+
this.langs = [];
|
|
29
|
+
this.getAllLangs(this.vtsTracks);
|
|
30
|
+
|
|
31
|
+
// Set the default VTS language
|
|
32
|
+
this.vtsLang = this.lang;
|
|
33
|
+
|
|
34
|
+
// Inject a heading
|
|
35
|
+
$heading = $('<h2>').text('Video Transcript Sorter'); // TODO: Localize; intelligently assign proper heading level
|
|
36
|
+
$('#able-vts').append($heading);
|
|
37
|
+
|
|
38
|
+
// Inject an empty div for writing messages
|
|
39
|
+
this.$vtsAlert = $('<div>',{
|
|
40
|
+
'id': 'able-vts-alert',
|
|
41
|
+
'aria-live': 'polite',
|
|
42
|
+
'aria-atomic': 'true'
|
|
43
|
+
})
|
|
44
|
+
$('#able-vts').append(this.$vtsAlert);
|
|
45
|
+
|
|
46
|
+
// Inject instructions (TODO: Localize)
|
|
47
|
+
$instructions = $('<div>',{
|
|
48
|
+
'id': 'able-vts-instructions'
|
|
49
|
+
});
|
|
50
|
+
$p1 = $('<p>').text('Use the Video Transcript Sorter to perform any of the following tasks:');
|
|
51
|
+
$ul = $('<ul>');
|
|
52
|
+
$li1 = $('<li>').text('Reorder chapters, descriptions, captions, and/or subtitles so they appear in the proper sequence in Able Player\'s auto-generated transcript.');
|
|
53
|
+
$li2 = $('<li>').text('Modify content or start/end times (all are directly editable within the table).');
|
|
54
|
+
$li3 = $('<li>').text('Insert new content, such as chapters or descriptions.');
|
|
55
|
+
$p2 = $('<p>').text('When finished editing, click the "Save Changes" button. This will auto-generate new content for all relevant timed text files (chapters, descriptions, captions, and/or subtitles), which can be copied and pasted into separate WebVTT files for use by Able Player.');
|
|
56
|
+
$ul.append($li1,$li2,$li3);
|
|
57
|
+
$instructions.append($p1,$ul,$p2);
|
|
58
|
+
$('#able-vts').append($instructions);
|
|
59
|
+
|
|
60
|
+
// Inject a fieldset with radio buttons for each language
|
|
61
|
+
$fieldset = $('<fieldset>');
|
|
62
|
+
$legend = $('<legend>').text('Select a language'); // TODO: Localize this
|
|
63
|
+
$fieldset.append($legend)
|
|
64
|
+
for (i in this.langs) {
|
|
65
|
+
radioId = 'vts-lang-radio-' + this.langs[i];
|
|
66
|
+
$radioDiv = $('<div>',{
|
|
67
|
+
// uncomment the following if label is native name
|
|
68
|
+
// 'lang': this.langs[i]
|
|
69
|
+
});
|
|
70
|
+
$radio = $('<input>', {
|
|
71
|
+
'type': 'radio',
|
|
72
|
+
'name': 'vts-lang',
|
|
73
|
+
'id': radioId,
|
|
74
|
+
'value': this.langs[i]
|
|
75
|
+
}).on('click',function() {
|
|
76
|
+
thisObj.vtsLang = $(this).val();
|
|
77
|
+
thisObj.showVtsAlert('Loading ' + thisObj.getLanguageName(thisObj.vtsLang) + ' tracks');
|
|
78
|
+
thisObj.injectVtsTable('update',thisObj.vtsLang);
|
|
79
|
+
});
|
|
80
|
+
if (this.langs[i] == this.lang) {
|
|
81
|
+
// this is the default language.
|
|
82
|
+
$radio.prop('checked',true);
|
|
83
|
+
}
|
|
84
|
+
$label = $('<label>', {
|
|
85
|
+
'for': radioId
|
|
86
|
+
// Two options for label:
|
|
87
|
+
// getLanguageNativeName() - returns native name; if using this be sure to add lang attr to <div> (see above)
|
|
88
|
+
// getLanguageName() - returns name in English; doesn't require lang attr on <label>
|
|
89
|
+
}).text(this.getLanguageName(this.langs[i]));
|
|
90
|
+
$radioDiv.append($radio,$label);
|
|
91
|
+
$fieldset.append($radioDiv);
|
|
92
|
+
}
|
|
93
|
+
$('#able-vts').append($fieldset);
|
|
94
|
+
|
|
95
|
+
// Inject a 'Save Changes' button
|
|
96
|
+
$saveButton = $('<button>',{
|
|
97
|
+
'type': 'button',
|
|
98
|
+
'id': 'able-vts-save',
|
|
99
|
+
'value': 'save'
|
|
100
|
+
}).text('Save Changes'); // TODO: Localize this
|
|
101
|
+
$('#able-vts').append($saveButton);
|
|
102
|
+
|
|
103
|
+
// Inject a table with one row for each cue in the default language
|
|
104
|
+
this.injectVtsTable('add',this.vtsLang);
|
|
105
|
+
|
|
106
|
+
// TODO: Add drag/drop functionality for mousers
|
|
107
|
+
|
|
108
|
+
// Add event listeners for contenteditable cells
|
|
109
|
+
var kindOptions, beforeEditing, editedCell, editedContent, i, closestKind;
|
|
110
|
+
kindOptions = ['captions','chapters','descriptions','subtitles'];
|
|
111
|
+
$('td[contenteditable="true"]').on('focus',function() {
|
|
112
|
+
beforeEditing = $(this).text();
|
|
113
|
+
}).on('blur',function() {
|
|
114
|
+
if (beforeEditing != $(this).text()) {
|
|
115
|
+
editedCell = $(this).index();
|
|
116
|
+
editedContent = $(this).text();
|
|
117
|
+
if (editedCell === 1) {
|
|
118
|
+
// do some simple spelling auto-correct
|
|
119
|
+
if ($.inArray(editedContent,kindOptions) === -1) {
|
|
120
|
+
// whatever user typed is not a valid kind
|
|
121
|
+
// assume they correctly typed the first character
|
|
122
|
+
if (editedContent.substr(0,1) === 's') {
|
|
123
|
+
$(this).text('subtitles');
|
|
124
|
+
}
|
|
125
|
+
else if (editedContent.substr(0,1) === 'd') {
|
|
126
|
+
$(this).text('descriptions');
|
|
127
|
+
}
|
|
128
|
+
else if (editedContent.substr(0,2) === 'ch') {
|
|
129
|
+
$(this).text('chapters');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// whatever else they types, assume 'captions'
|
|
133
|
+
$(this).text('captions');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (editedCell === 2 || editedCell === 3) {
|
|
138
|
+
// start or end time
|
|
139
|
+
// ensure proper formatting (with 3 decimal places)
|
|
140
|
+
$(this).text(thisObj.formatTimestamp(editedContent));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}).on('keydown',function(e) {
|
|
144
|
+
// don't allow keystrokes to trigger Able Player (or other) functions
|
|
145
|
+
// while user is editing
|
|
146
|
+
e.stopPropagation();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// handle click on the Save button
|
|
150
|
+
|
|
151
|
+
// handle click on the Save button
|
|
152
|
+
$('#able-vts-save').on('click',function(e) {
|
|
153
|
+
e.stopPropagation();
|
|
154
|
+
if ($(this).attr('value') == 'save') {
|
|
155
|
+
// replace table with WebVTT output in textarea fields (for copying/pasting)
|
|
156
|
+
$(this).attr('value','cancel').text('Return to Editor'); // TODO: Localize this
|
|
157
|
+
$savedTable = $('#able-vts table');
|
|
158
|
+
$('#able-vts-instructions').hide();
|
|
159
|
+
$('#able-vts > fieldset').hide();
|
|
160
|
+
$('#able-vts table').remove();
|
|
161
|
+
$('#able-vts-icon-credit').remove();
|
|
162
|
+
thisObj.parseVtsOutput($savedTable);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// cancel saving, and restore the table using edited content
|
|
166
|
+
$(this).attr('value','save').text('Save Changes'); // TODO: Localize this
|
|
167
|
+
$('#able-vts-output').remove();
|
|
168
|
+
$('#able-vts-instructions').show();
|
|
169
|
+
$('#able-vts > fieldset').show();
|
|
170
|
+
$('#able-vts').append($savedTable);
|
|
171
|
+
$('#able-vts').append(thisObj.getIconCredit());
|
|
172
|
+
thisObj.showVtsAlert('Cancelling saving. Any edits you made have been restored in the VTS table.'); // TODO: Localize this
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
AblePlayer.prototype.setupVtsTracks = function(kind, lang, label, src, contents) {
|
|
180
|
+
|
|
181
|
+
// Called from tracks.js
|
|
182
|
+
|
|
183
|
+
var srcFile, vtsCues;
|
|
184
|
+
|
|
185
|
+
srcFile = this.getFilenameFromPath(src);
|
|
186
|
+
vtsCues = this.parseVtsTracks(contents);
|
|
187
|
+
|
|
188
|
+
this.vtsTracks.push({
|
|
189
|
+
'kind': kind,
|
|
190
|
+
'language': lang,
|
|
191
|
+
'label': label,
|
|
192
|
+
'srcFile': srcFile,
|
|
193
|
+
'cues': vtsCues
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
AblePlayer.prototype.getFilenameFromPath = function(path) {
|
|
198
|
+
|
|
199
|
+
var lastSlash;
|
|
200
|
+
|
|
201
|
+
lastSlash = path.lastIndexOf('/');
|
|
202
|
+
if (lastSlash === -1) {
|
|
203
|
+
// there are no slashes in path.
|
|
204
|
+
return path;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return path.substr(lastSlash+1);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
AblePlayer.prototype.getFilenameFromTracks = function(kind,lang) {
|
|
212
|
+
|
|
213
|
+
for (var i=0; i<this.vtsTracks.length; i++) {
|
|
214
|
+
if (this.vtsTracks[i].kind === kind && this.vtsTracks[i].language === lang) {
|
|
215
|
+
// this is a matching track
|
|
216
|
+
// srcFile has already been converted to filename from path before saving to vtsTracks
|
|
217
|
+
return this.vtsTracks[i].srcFile;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// no matching track found
|
|
221
|
+
return false;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
AblePlayer.prototype.parseVtsTracks = function(contents) {
|
|
225
|
+
|
|
226
|
+
var rows, timeParts, cues, i, j, thisRow, nextRow, content, blankRow;
|
|
227
|
+
rows = contents.split("\n");
|
|
228
|
+
cues = [];
|
|
229
|
+
i = 0;
|
|
230
|
+
while (i < rows.length) {
|
|
231
|
+
thisRow = rows[i];
|
|
232
|
+
if (thisRow.indexOf(' --> ') !== -1) {
|
|
233
|
+
// this is probably a time row
|
|
234
|
+
timeParts = thisRow.trim().split(' ');
|
|
235
|
+
if (this.isValidTimestamp(timeParts[0]) && this.isValidTimestamp(timeParts[2])) {
|
|
236
|
+
// both timestamps are valid. This is definitely a time row
|
|
237
|
+
content = '';
|
|
238
|
+
j = i+1;
|
|
239
|
+
blankRow = false;
|
|
240
|
+
while (j < rows.length && !blankRow) {
|
|
241
|
+
nextRow = rows[j].trim();
|
|
242
|
+
if (nextRow.length > 0) {
|
|
243
|
+
if (content.length > 0) {
|
|
244
|
+
// add back the EOL between rows of content
|
|
245
|
+
content += "\n" + nextRow;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
// this is the first row of content. No need for an EOL
|
|
249
|
+
content += nextRow;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
blankRow = true;
|
|
254
|
+
}
|
|
255
|
+
j++;
|
|
256
|
+
}
|
|
257
|
+
cues.push({
|
|
258
|
+
'start': timeParts[0],
|
|
259
|
+
'end': timeParts[2],
|
|
260
|
+
'content': content
|
|
261
|
+
});
|
|
262
|
+
i = j; //skip ahead
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
i++;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return cues;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
AblePlayer.prototype.isValidTimestamp = function(timestamp) {
|
|
273
|
+
|
|
274
|
+
// return true if timestamp contains only numbers or expected punctuation
|
|
275
|
+
if (/^[0-9:,.]*$/.test(timestamp)) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
AblePlayer.prototype.formatTimestamp = function(timestamp) {
|
|
284
|
+
|
|
285
|
+
// timestamp is a string in the form "HH:MM:SS.xxx"
|
|
286
|
+
// Take some simple steps to ensure edited timestamp values still adhere to expected format
|
|
287
|
+
|
|
288
|
+
var firstPart, lastPart;
|
|
289
|
+
|
|
290
|
+
var firstPart = timestamp.substr(0,timestamp.lastIndexOf('.')+1);
|
|
291
|
+
var lastPart = timestamp.substr(timestamp.lastIndexOf('.')+1);
|
|
292
|
+
|
|
293
|
+
// TODO: Be sure each component within firstPart has only exactly two digits
|
|
294
|
+
// Probably can't justify doing this automatically
|
|
295
|
+
// If users enters '5' for minutes, that could be either '05' or '50'
|
|
296
|
+
// This should trigger an error and prompt the user to correct the value before proceeding
|
|
297
|
+
|
|
298
|
+
// Be sure lastPart has exactly three digits
|
|
299
|
+
if (lastPart.length > 3) {
|
|
300
|
+
// chop off any extra digits
|
|
301
|
+
lastPart = lastPart.substr(0,3);
|
|
302
|
+
}
|
|
303
|
+
else if (lastPart.length < 3) {
|
|
304
|
+
// add trailing zeros
|
|
305
|
+
while (lastPart.length < 3) {
|
|
306
|
+
lastPart += '0';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return firstPart + lastPart;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
AblePlayer.prototype.injectVtsTable = function(action,lang) {
|
|
314
|
+
|
|
315
|
+
// action is either 'add' (for a new table) or 'update' (if user has selected a new lang)
|
|
316
|
+
|
|
317
|
+
var $table, headers, i, $tr, $th, $td, rows, rowNum, rowId;
|
|
318
|
+
|
|
319
|
+
if (action === 'update') {
|
|
320
|
+
// remove existing table
|
|
321
|
+
$('#able-vts table').remove();
|
|
322
|
+
$('#able-vts-icon-credit').remove();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
$table = $('<table>',{
|
|
326
|
+
'lang': lang
|
|
327
|
+
});
|
|
328
|
+
$tr = $('<tr>',{
|
|
329
|
+
'lang': 'en' // TEMP, until header row is localized
|
|
330
|
+
});
|
|
331
|
+
headers = ['Row #','Kind','Start','End','Content','Actions']; // TODO: Localize this
|
|
332
|
+
for (i=0; i < headers.length; i++) {
|
|
333
|
+
$th = $('<th>', {
|
|
334
|
+
'scope': 'col'
|
|
335
|
+
}).text(headers[i]);
|
|
336
|
+
if (headers[i] === 'Actions') {
|
|
337
|
+
$th.addClass('actions');
|
|
338
|
+
}
|
|
339
|
+
$tr.append($th);
|
|
340
|
+
}
|
|
341
|
+
$table.append($tr);
|
|
342
|
+
|
|
343
|
+
// Get all rows (sorted by start time), and inject them into table
|
|
344
|
+
rows = this.getAllRows(lang);
|
|
345
|
+
for (i=0; i < rows.length; i++) {
|
|
346
|
+
rowNum = i + 1;
|
|
347
|
+
rowId = 'able-vts-row-' + rowNum;
|
|
348
|
+
$tr = $('<tr>',{
|
|
349
|
+
'id': rowId,
|
|
350
|
+
'class': 'kind-' + rows[i].kind
|
|
351
|
+
});
|
|
352
|
+
// Row #
|
|
353
|
+
$td = $('<td>').text(rowNum);
|
|
354
|
+
$tr.append($td);
|
|
355
|
+
|
|
356
|
+
// Kind
|
|
357
|
+
$td = $('<td>',{
|
|
358
|
+
'contenteditable': 'true'
|
|
359
|
+
}).text(rows[i].kind);
|
|
360
|
+
$tr.append($td);
|
|
361
|
+
|
|
362
|
+
// Start
|
|
363
|
+
$td = $('<td>',{
|
|
364
|
+
'contenteditable': 'true'
|
|
365
|
+
}).text(rows[i].start);
|
|
366
|
+
$tr.append($td);
|
|
367
|
+
|
|
368
|
+
// End
|
|
369
|
+
$td = $('<td>',{
|
|
370
|
+
'contenteditable': 'true'
|
|
371
|
+
}).text(rows[i].end);
|
|
372
|
+
$tr.append($td);
|
|
373
|
+
|
|
374
|
+
// Content
|
|
375
|
+
$td = $('<td>',{
|
|
376
|
+
'contenteditable': 'true'
|
|
377
|
+
}).text(rows[i].content); // TODO: Preserve tags
|
|
378
|
+
$tr.append($td);
|
|
379
|
+
|
|
380
|
+
// Actions
|
|
381
|
+
$td = this.addVtsActionButtons(rowNum,rows.length);
|
|
382
|
+
$tr.append($td);
|
|
383
|
+
|
|
384
|
+
$table.append($tr);
|
|
385
|
+
}
|
|
386
|
+
$('#able-vts').append($table);
|
|
387
|
+
|
|
388
|
+
// Add credit for action button SVG icons
|
|
389
|
+
$('#able-vts').append(this.getIconCredit());
|
|
390
|
+
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
AblePlayer.prototype.addVtsActionButtons = function(rowNum,numRows) {
|
|
394
|
+
|
|
395
|
+
// rowNum is the number of the current table row (starting with 1)
|
|
396
|
+
// numRows is the total number of rows (excluding the header row)
|
|
397
|
+
// TODO: Position buttons so they're vertically aligned, even if missing an Up or Down button
|
|
398
|
+
var thisObj, $td, buttons, i, button, $button, $svg, $g, pathString, pathString2, $path, $path2;
|
|
399
|
+
thisObj = this;
|
|
400
|
+
$td = $('<td>');
|
|
401
|
+
buttons = ['up','down','insert','delete'];
|
|
402
|
+
|
|
403
|
+
for (i=0; i < buttons.length; i++) {
|
|
404
|
+
button = buttons[i];
|
|
405
|
+
if (button === 'up') {
|
|
406
|
+
if (rowNum > 1) {
|
|
407
|
+
$button = $('<button>',{
|
|
408
|
+
'id': 'able-vts-button-up-' + rowNum,
|
|
409
|
+
'title': 'Move up',
|
|
410
|
+
'aria-label': 'Move Row ' + rowNum + ' up'
|
|
411
|
+
}).on('click', function(el) {
|
|
412
|
+
thisObj.onClickVtsActionButton(el.currentTarget);
|
|
413
|
+
});
|
|
414
|
+
$svg = $('<svg>',{
|
|
415
|
+
'focusable': 'false',
|
|
416
|
+
'aria-hidden': 'true',
|
|
417
|
+
'x': '0px',
|
|
418
|
+
'y': '0px',
|
|
419
|
+
'width': '254.296px',
|
|
420
|
+
'height': '254.296px',
|
|
421
|
+
'viewBox': '0 0 254.296 254.296',
|
|
422
|
+
'style': 'enable-background:new 0 0 254.296 254.296'
|
|
423
|
+
});
|
|
424
|
+
pathString = 'M249.628,176.101L138.421,52.88c-6.198-6.929-16.241-6.929-22.407,0l-0.381,0.636L4.648,176.101'
|
|
425
|
+
+ 'c-6.198,6.897-6.198,18.052,0,24.981l0.191,0.159c2.892,3.305,6.865,5.371,11.346,5.371h221.937c4.577,0,8.613-2.161,11.41-5.594'
|
|
426
|
+
+ 'l0.064,0.064C255.857,194.153,255.857,182.998,249.628,176.101z';
|
|
427
|
+
$path = $('<path>',{
|
|
428
|
+
'd': pathString
|
|
429
|
+
});
|
|
430
|
+
$g = $('<g>').append($path);
|
|
431
|
+
$svg.append($g);
|
|
432
|
+
$button.append($svg);
|
|
433
|
+
// Refresh button in the DOM in order for browser to process & display the SVG
|
|
434
|
+
$button.html($button.html());
|
|
435
|
+
$td.append($button);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else if (button === 'down') {
|
|
439
|
+
if (rowNum < numRows) {
|
|
440
|
+
$button = $('<button>',{
|
|
441
|
+
'id': 'able-vts-button-down-' + rowNum,
|
|
442
|
+
'title': 'Move down',
|
|
443
|
+
'aria-label': 'Move Row ' + rowNum + ' down'
|
|
444
|
+
}).on('click', function(el) {
|
|
445
|
+
thisObj.onClickVtsActionButton(el.currentTarget);
|
|
446
|
+
});
|
|
447
|
+
$svg = $('<svg>',{
|
|
448
|
+
'focusable': 'false',
|
|
449
|
+
'aria-hidden': 'true',
|
|
450
|
+
'x': '0px',
|
|
451
|
+
'y': '0px',
|
|
452
|
+
'width': '292.362px',
|
|
453
|
+
'height': '292.362px',
|
|
454
|
+
'viewBox': '0 0 292.362 292.362',
|
|
455
|
+
'style': 'enable-background:new 0 0 292.362 292.362'
|
|
456
|
+
});
|
|
457
|
+
pathString = 'M286.935,69.377c-3.614-3.617-7.898-5.424-12.848-5.424H18.274c-4.952,0-9.233,1.807-12.85,5.424'
|
|
458
|
+
+ 'C1.807,72.998,0,77.279,0,82.228c0,4.948,1.807,9.229,5.424,12.847l127.907,127.907c3.621,3.617,7.902,5.428,12.85,5.428'
|
|
459
|
+
+ 's9.233-1.811,12.847-5.428L286.935,95.074c3.613-3.617,5.427-7.898,5.427-12.847C292.362,77.279,290.548,72.998,286.935,69.377z';
|
|
460
|
+
$path = $('<path>',{
|
|
461
|
+
'd': pathString
|
|
462
|
+
});
|
|
463
|
+
$g = $('<g>').append($path);
|
|
464
|
+
$svg.append($g);
|
|
465
|
+
$button.append($svg);
|
|
466
|
+
// Refresh button in the DOM in order for browser to process & display the SVG
|
|
467
|
+
$button.html($button.html());
|
|
468
|
+
$td.append($button);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
else if (button === 'insert') {
|
|
472
|
+
// Add Insert button to all rows
|
|
473
|
+
$button = $('<button>',{
|
|
474
|
+
'id': 'able-vts-button-insert-' + rowNum,
|
|
475
|
+
'title': 'Insert row below',
|
|
476
|
+
'aria-label': 'Insert row before Row ' + rowNum
|
|
477
|
+
}).on('click', function(el) {
|
|
478
|
+
thisObj.onClickVtsActionButton(el.currentTarget);
|
|
479
|
+
});
|
|
480
|
+
$svg = $('<svg>',{
|
|
481
|
+
'focusable': 'false',
|
|
482
|
+
'aria-hidden': 'true',
|
|
483
|
+
'x': '0px',
|
|
484
|
+
'y': '0px',
|
|
485
|
+
'width': '401.994px',
|
|
486
|
+
'height': '401.994px',
|
|
487
|
+
'viewBox': '0 0 401.994 401.994',
|
|
488
|
+
'style': 'enable-background:new 0 0 401.994 401.994'
|
|
489
|
+
});
|
|
490
|
+
pathString = 'M394,154.175c-5.331-5.33-11.806-7.994-19.417-7.994H255.811V27.406c0-7.611-2.666-14.084-7.994-19.414'
|
|
491
|
+
+ 'C242.488,2.666,236.02,0,228.398,0h-54.812c-7.612,0-14.084,2.663-19.414,7.993c-5.33,5.33-7.994,11.803-7.994,19.414v118.775'
|
|
492
|
+
+ 'H27.407c-7.611,0-14.084,2.664-19.414,7.994S0,165.973,0,173.589v54.819c0,7.618,2.662,14.086,7.992,19.411'
|
|
493
|
+
+ 'c5.33,5.332,11.803,7.994,19.414,7.994h118.771V374.59c0,7.611,2.664,14.089,7.994,19.417c5.33,5.325,11.802,7.987,19.414,7.987'
|
|
494
|
+
+ 'h54.816c7.617,0,14.086-2.662,19.417-7.987c5.332-5.331,7.994-11.806,7.994-19.417V255.813h118.77'
|
|
495
|
+
+ 'c7.618,0,14.089-2.662,19.417-7.994c5.329-5.325,7.994-11.793,7.994-19.411v-54.819C401.991,165.973,399.332,159.502,394,154.175z';
|
|
496
|
+
$path = $('<path>',{
|
|
497
|
+
'd': pathString
|
|
498
|
+
});
|
|
499
|
+
$g = $('<g>').append($path);
|
|
500
|
+
$svg.append($g);
|
|
501
|
+
$button.append($svg);
|
|
502
|
+
// Refresh button in the DOM in order for browser to process & display the SVG
|
|
503
|
+
$button.html($button.html());
|
|
504
|
+
$td.append($button);
|
|
505
|
+
}
|
|
506
|
+
else if (button === 'delete') {
|
|
507
|
+
// Add Delete button to all rows
|
|
508
|
+
$button = $('<button>',{
|
|
509
|
+
'id': 'able-vts-button-delete-' + rowNum,
|
|
510
|
+
'title': 'Delete row ',
|
|
511
|
+
'aria-label': 'Delete Row ' + rowNum
|
|
512
|
+
}).on('click', function(el) {
|
|
513
|
+
thisObj.onClickVtsActionButton(el.currentTarget);
|
|
514
|
+
});
|
|
515
|
+
$svg = $('<svg>',{
|
|
516
|
+
'focusable': 'false',
|
|
517
|
+
'aria-hidden': 'true',
|
|
518
|
+
'x': '0px',
|
|
519
|
+
'y': '0px',
|
|
520
|
+
'width': '508.52px',
|
|
521
|
+
'height': '508.52px',
|
|
522
|
+
'viewBox': '0 0 508.52 508.52',
|
|
523
|
+
'style': 'enable-background:new 0 0 508.52 508.52'
|
|
524
|
+
});
|
|
525
|
+
pathString = 'M397.281,31.782h-63.565C333.716,14.239,319.478,0,301.934,0h-95.347'
|
|
526
526
|
+ 'c-17.544,0-31.782,14.239-31.782,31.782h-63.565c-17.544,0-31.782,14.239-31.782,31.782h349.607'
|
|
527
527
|
+ 'C429.063,46.021,414.825,31.782,397.281,31.782z';
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
528
|
+
$path = $('<path>',{
|
|
529
|
+
'd': pathString
|
|
530
|
+
});
|
|
531
|
+
pathString2 = 'M79.456,476.737c0,17.544,14.239,31.782,31.782,31.782h286.042'
|
|
532
532
|
+ 'c17.544,0,31.782-14.239,31.782-31.782V95.347H79.456V476.737z M333.716,174.804c0-8.772,7.151-15.891,15.891-15.891'
|
|
533
533
|
+ 'c8.74,0,15.891,7.119,15.891,15.891v254.26c0,8.74-7.151,15.891-15.891,15.891c-8.74,0-15.891-7.151-15.891-15.891V174.804z'
|
|
534
534
|
+ 'M238.369,174.804c0-8.772,7.119-15.891,15.891-15.891c8.74,0,15.891,7.119,15.891,15.891v254.26'
|
|
535
535
|
+ 'c0,8.74-7.151,15.891-15.891,15.891c-8.772,0-15.891-7.151-15.891-15.891V174.804z M143.021,174.804'
|
|
536
536
|
+ 'c0-8.772,7.119-15.891,15.891-15.891c8.772,0,15.891,7.119,15.891,15.891v254.26c0,8.74-7.119,15.891-15.891,15.891'
|
|
537
537
|
+ 'c-8.772,0-15.891-7.151-15.891-15.891V174.804z';
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
538
|
+
$path2 = $('<path>',{
|
|
539
|
+
'd': pathString2
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
$g = $('<g>').append($path,$path2);
|
|
543
|
+
$svg.append($g);
|
|
544
|
+
$button.append($svg);
|
|
545
|
+
// Refresh button in the DOM in order for browser to process & display the SVG
|
|
546
|
+
$button.html($button.html());
|
|
547
|
+
$td.append($button);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return $td;
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
AblePlayer.prototype.updateVtsActionButtons = function($buttons,nextRowNum) {
|
|
554
|
+
|
|
555
|
+
// TODO: Add some filters to this function to add or delete 'Up' and 'Down' buttons
|
|
556
|
+
// if row is moved to/from the first/last rows
|
|
557
|
+
var i, $thisButton, id, label, newId, newLabel;
|
|
558
|
+
for (i=0; i < $buttons.length; i++) {
|
|
559
|
+
$thisButton = $buttons.eq(i);
|
|
560
|
+
id = $thisButton.attr('id');
|
|
561
|
+
label = $thisButton.attr('aria-label');
|
|
562
|
+
// replace the integer (id) within each of the above strings
|
|
563
|
+
newId = id.replace(/[0-9]+/g, nextRowNum);
|
|
564
|
+
newLabel = label.replace(/[0-9]+/g, nextRowNum);
|
|
565
|
+
$thisButton.attr('id',newId);
|
|
566
|
+
$thisButton.attr('aria-label',newLabel);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
AblePlayer.prototype.getIconCredit = function() {
|
|
571
|
+
|
|
572
|
+
var credit;
|
|
573
|
+
credit = '<div id="able-vts-icon-credit">'
|
|
574
|
+
+ 'Action buttons made by <a href="https://www.flaticon.com/authors/elegant-themes">Elegant Themes</a> '
|
|
575
|
+
+ 'from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> '
|
|
576
|
+
+ 'are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" '
|
|
577
|
+
+ 'target="_blank">CC 3.0 BY</a>'
|
|
578
|
+
+ '</div>';
|
|
579
|
+
return credit;
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
AblePlayer.prototype.getAllLangs = function(tracks) {
|
|
583
|
+
|
|
584
|
+
// update this.langs with any unique languages found in tracks
|
|
585
|
+
var i;
|
|
586
|
+
for (i in tracks) {
|
|
587
|
+
if (tracks[i].hasOwnProperty('language')) {
|
|
588
|
+
if ($.inArray(tracks[i].language,this.langs) === -1) {
|
|
589
|
+
// this language is not already in the langs array. Add it.
|
|
590
|
+
this.langs[this.langs.length] = tracks[i].language;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
AblePlayer.prototype.getAllRows = function(lang) {
|
|
597
|
+
|
|
598
|
+
// returns an array of data to be displayed in VTS table
|
|
599
|
+
// includes all cues for tracks of any type with matching lang
|
|
600
|
+
// cues are sorted by start time
|
|
601
|
+
var i, track, c, cues;
|
|
602
|
+
cues = [];
|
|
603
|
+
for (i=0; i < this.vtsTracks.length; i++) {
|
|
604
|
+
track = this.vtsTracks[i];
|
|
605
|
+
if (track.language == lang) {
|
|
606
|
+
// this track matches the language. Add its cues to array
|
|
607
|
+
for (c in track.cues) {
|
|
608
|
+
cues.push({
|
|
609
|
+
'kind': track.kind,
|
|
610
|
+
'lang': lang,
|
|
611
|
+
'id': track.cues[c].id,
|
|
612
|
+
'start': track.cues[c].start,
|
|
613
|
+
'end': track.cues[c].end,
|
|
614
|
+
'content': track.cues[c].content
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
// Now sort cues by start time
|
|
620
|
+
cues.sort(function(a,b) {
|
|
621
|
+
return a.start > b.start ? 1 : -1;
|
|
622
|
+
});
|
|
623
|
+
return cues;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
AblePlayer.prototype.onClickVtsActionButton = function(el) {
|
|
628
|
+
|
|
629
|
+
// handle click on up, down, insert, or delete button
|
|
630
|
+
var idParts, action, rowNum;
|
|
631
|
+
idParts = $(el).attr('id').split('-');
|
|
632
|
+
action = idParts[3];
|
|
633
|
+
rowNum = idParts[4];
|
|
634
|
+
if (action == 'up') {
|
|
635
|
+
// move the row up
|
|
636
|
+
this.moveRow(rowNum,'up');
|
|
637
|
+
}
|
|
638
|
+
else if (action == 'down') {
|
|
639
|
+
// move the row down
|
|
640
|
+
this.moveRow(rowNum,'down');
|
|
641
|
+
}
|
|
642
|
+
else if (action == 'insert') {
|
|
643
|
+
// insert a row below
|
|
644
|
+
this.insertRow(rowNum);
|
|
645
|
+
}
|
|
646
|
+
else if (action == 'delete') {
|
|
647
|
+
// delete the row
|
|
648
|
+
this.deleteRow(rowNum);
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
|
|
652
|
+
AblePlayer.prototype.insertRow = function(rowNum) {
|
|
653
|
+
|
|
654
|
+
// Insert empty row below rowNum
|
|
655
|
+
var $table, $rows, numRows, newRowNum, newRowId, newTimes, $tr, $td;
|
|
656
|
+
var $select, options, i, $option, newKind, newClass, $parentRow;
|
|
657
|
+
var i, nextRowNum, $buttons;
|
|
658
|
+
|
|
659
|
+
$table = $('#able-vts table');
|
|
660
|
+
$rows = $table.find('tr');
|
|
661
|
+
|
|
662
|
+
numRows = $rows.length - 1; // exclude header row
|
|
663
|
+
|
|
664
|
+
newRowNum = parseInt(rowNum) + 1;
|
|
665
|
+
newRowId = 'able-vts-row-' + newRowNum;
|
|
666
|
+
|
|
667
|
+
// Create an empty row
|
|
668
|
+
$tr = $('<tr>',{
|
|
669
|
+
'id': newRowId
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
// Row #
|
|
673
|
+
$td = $('<td>').text(newRowNum);
|
|
674
|
+
$tr.append($td);
|
|
675
|
+
|
|
676
|
+
// Kind (add a select field for chosing a kind)
|
|
677
|
+
newKind = null;
|
|
678
|
+
$select = $('<select>',{
|
|
679
|
+
'id': 'able-vts-kind-' + newRowNum,
|
|
680
|
+
'aria-label': 'What kind of track is this?',
|
|
681
|
+
'placeholder': 'Select a kind'
|
|
682
|
+
}).on('change',function() {
|
|
683
|
+
newKind = $(this).val();
|
|
684
|
+
newClass = 'kind-' + newKind;
|
|
685
|
+
$parentRow = $(this).closest('tr');
|
|
686
|
+
// replace the select field with the chosen value as text
|
|
687
|
+
$(this).parent().text(newKind);
|
|
688
|
+
// add a class to the parent row
|
|
689
|
+
$parentRow.addClass(newClass);
|
|
690
|
+
});
|
|
691
|
+
options = ['','captions','chapters','descriptions','subtitles'];
|
|
692
|
+
for (i=0; i<options.length; i++) {
|
|
693
|
+
$option = $('<option>',{
|
|
694
|
+
'value': options[i]
|
|
695
|
+
}).text(options[i]);
|
|
696
|
+
$select.append($option);
|
|
697
|
+
}
|
|
698
|
+
$td = $('<td>').append($select);
|
|
699
|
+
$tr.append($td);
|
|
700
|
+
|
|
701
|
+
// Start
|
|
702
|
+
$td = $('<td>',{
|
|
703
|
+
'contenteditable': 'true'
|
|
704
|
+
}); // TODO; Intelligently assign a new start time (see getAdjustedTimes())
|
|
705
|
+
$tr.append($td);
|
|
706
|
+
|
|
707
|
+
// End
|
|
708
|
+
$td = $('<td>',{
|
|
709
|
+
'contenteditable': 'true'
|
|
710
|
+
}); // TODO; Intelligently assign a new end time (see getAdjustedTimes())
|
|
711
|
+
$tr.append($td);
|
|
712
|
+
|
|
713
|
+
// Content
|
|
714
|
+
$td = $('<td>',{
|
|
715
|
+
'contenteditable': 'true'
|
|
716
|
+
});
|
|
717
|
+
$tr.append($td);
|
|
718
|
+
|
|
719
|
+
// Actions
|
|
720
|
+
$td = this.addVtsActionButtons(newRowNum,numRows);
|
|
721
|
+
$tr.append($td);
|
|
722
|
+
|
|
723
|
+
// Now insert the new row
|
|
724
|
+
$table.find('tr').eq(rowNum).after($tr);
|
|
725
|
+
|
|
726
|
+
// Update row.id, Row # cell, & action items for all rows after the inserted one
|
|
727
|
+
for (i=newRowNum; i <= numRows; i++) {
|
|
728
|
+
nextRowNum = i + 1;
|
|
729
|
+
$rows.eq(i).attr('id','able-vts-row-' + nextRowNum); // increment tr id
|
|
730
|
+
$rows.eq(i).find('td').eq(0).text(nextRowNum); // increment Row # as expressed in first td
|
|
731
|
+
$buttons = $rows.eq(i).find('button');
|
|
732
|
+
this.updateVtsActionButtons($buttons,nextRowNum);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Auto-adjust times
|
|
736
|
+
this.adjustTimes(newRowNum);
|
|
737
|
+
|
|
738
|
+
// Announce the insertion
|
|
739
|
+
this.showVtsAlert('A new row ' + newRowNum + ' has been inserted'); // TODO: Localize this
|
|
740
|
+
|
|
741
|
+
// Place focus in new select field
|
|
742
|
+
$select.focus();
|
|
743
|
+
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
AblePlayer.prototype.deleteRow = function(rowNum) {
|
|
747
|
+
|
|
748
|
+
var $table, $rows, numRows, i, nextRowNum, $buttons;
|
|
749
|
+
|
|
750
|
+
$table = $('#able-vts table');
|
|
751
|
+
$table[0].deleteRow(rowNum);
|
|
752
|
+
$rows = $table.find('tr'); // this does not include the deleted row
|
|
753
|
+
numRows = $rows.length - 1; // exclude header row
|
|
754
|
+
|
|
755
|
+
// Update row.id, Row # cell, & action buttons for all rows after the deleted one
|
|
756
|
+
for (i=rowNum; i <= numRows; i++) {
|
|
757
|
+
nextRowNum = i;
|
|
758
|
+
$rows.eq(i).attr('id','able-vts-row-' + nextRowNum); // increment tr id
|
|
759
|
+
$rows.eq(i).find('td').eq(0).text(nextRowNum); // increment Row # as expressed in first td
|
|
760
|
+
$buttons = $rows.eq(i).find('button');
|
|
761
|
+
this.updateVtsActionButtons($buttons,nextRowNum);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Announce the deletion
|
|
765
|
+
this.showVtsAlert('Row ' + rowNum + ' has been deleted'); // TODO: Localize this
|
|
766
|
+
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
AblePlayer.prototype.moveRow = function(rowNum,direction) {
|
|
770
|
+
|
|
771
|
+
// swap two rows
|
|
772
|
+
var $rows, $thisRow, otherRowNum, $otherRow, newTimes, msg;
|
|
773
|
+
|
|
774
|
+
$rows = $('#able-vts table').find('tr');
|
|
775
|
+
$thisRow = $('#able-vts table').find('tr').eq(rowNum);
|
|
776
|
+
if (direction == 'up') {
|
|
777
|
+
otherRowNum = parseInt(rowNum) - 1;
|
|
778
|
+
$otherRow = $('#able-vts table').find('tr').eq(otherRowNum);
|
|
779
|
+
$otherRow.before($thisRow);
|
|
780
|
+
}
|
|
781
|
+
else if (direction == 'down') {
|
|
782
|
+
otherRowNum = parseInt(rowNum) + 1;
|
|
783
|
+
$otherRow = $('#able-vts table').find('tr').eq(otherRowNum);
|
|
784
|
+
$otherRow.after($thisRow);
|
|
785
|
+
}
|
|
786
|
+
// Update row.id, Row # cell, & action buttons for the two swapped rows
|
|
787
|
+
$thisRow.attr('id','able-vts-row-' + otherRowNum);
|
|
788
|
+
$thisRow.find('td').eq(0).text(otherRowNum);
|
|
789
|
+
this.updateVtsActionButtons($thisRow.find('button'),otherRowNum);
|
|
790
|
+
$otherRow.attr('id','able-vts-row-' + rowNum);
|
|
791
|
+
$otherRow.find('td').eq(0).text(rowNum);
|
|
792
|
+
this.updateVtsActionButtons($otherRow.find('button'),rowNum);
|
|
793
|
+
|
|
794
|
+
// auto-adjust times
|
|
795
|
+
this.adjustTimes(otherRowNum);
|
|
796
|
+
|
|
797
|
+
// Announce the move (TODO: Localize this)
|
|
798
|
+
msg = 'Row ' + rowNum + ' has been moved ' + direction;
|
|
799
|
+
msg += ' and is now Row ' + otherRowNum;
|
|
800
|
+
this.showVtsAlert(msg);
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
AblePlayer.prototype.adjustTimes = function(rowNum) {
|
|
804
|
+
|
|
805
|
+
// Adjusts start and end times of the current, previous, and next rows in VTS table
|
|
806
|
+
// after a move or insert
|
|
807
|
+
// NOTE: Fully automating this process would be extraordinarily complicated
|
|
808
|
+
// The goal here is simply to make subtle tweaks to ensure rows appear
|
|
809
|
+
// in the new order within the Able Player transcript
|
|
810
|
+
// Additional tweaking will likely be required by the user
|
|
811
|
+
|
|
812
|
+
// HISTORY: Originally set minDuration to 2 seconds for captions and .500 for descriptions
|
|
813
|
+
// However, this can results in significant changes to existing caption timing,
|
|
814
|
+
// with not-so-positive results.
|
|
815
|
+
// As of 3.1.15, setting minDuration to .001 for all track kinds
|
|
816
|
+
// Users will have to make further adjustments manually if needed
|
|
817
|
+
|
|
818
|
+
// TODO: Add WebVTT validation on save, since tweaking times is risky
|
|
819
|
+
|
|
820
|
+
var minDuration, $rows, prevRowNum, nextRowNum, $row, $prevRow, $nextRow,
|
|
821
|
+
kind, prevKind, nextKind,
|
|
822
|
+
start, prevStart, nextStart,
|
|
823
|
+
end, prevEnd, nextEnd;
|
|
824
|
+
|
|
825
|
+
// Define minimum duration (in seconds) for each kind of track
|
|
826
|
+
minDuration = [];
|
|
827
|
+
minDuration['captions'] = .001;
|
|
828
|
+
minDuration['descriptions'] = .001;
|
|
829
|
+
minDuration['chapters'] = .001;
|
|
830
|
+
|
|
831
|
+
// refresh rows object
|
|
832
|
+
$rows = $('#able-vts table').find('tr');
|
|
833
|
+
|
|
834
|
+
// Get kind, start, and end from current row
|
|
835
|
+
$row = $rows.eq(rowNum);
|
|
836
|
+
if ($row.is('[class^="kind-"]')) {
|
|
837
|
+
// row has a class that starts with "kind-"
|
|
838
|
+
// Extract kind from the class name
|
|
839
|
+
kind = this.getKindFromClass($row.attr('class'));
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
// Kind has not been assigned (e.g., newly inserted row)
|
|
843
|
+
// Set as captions row by default
|
|
844
|
+
kind = 'captions';
|
|
845
|
+
}
|
|
846
|
+
start = this.getSecondsFromColonTime($row.find('td').eq(2).text());
|
|
847
|
+
end = this.getSecondsFromColonTime($row.find('td').eq(3).text());
|
|
848
|
+
|
|
849
|
+
// Get kind, start, and end from previous row
|
|
850
|
+
if (rowNum > 1) {
|
|
851
|
+
// this is not the first row. Include the previous row
|
|
852
|
+
prevRowNum = rowNum - 1;
|
|
853
|
+
$prevRow = $rows.eq(prevRowNum);
|
|
854
|
+
if ($prevRow.is('[class^="kind-"]')) {
|
|
855
|
+
// row has a class that starts with "kind-"
|
|
856
|
+
// Extract kind from the class name
|
|
857
|
+
prevKind = this.getKindFromClass($prevRow.attr('class'));
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
// Kind has not been assigned (e.g., newly inserted row)
|
|
861
|
+
prevKind = null;
|
|
862
|
+
}
|
|
863
|
+
prevStart = this.getSecondsFromColonTime($prevRow.find('td').eq(2).text());
|
|
864
|
+
prevEnd = this.getSecondsFromColonTime($prevRow.find('td').eq(3).text());
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
// this is the first row
|
|
868
|
+
prevRowNum = null;
|
|
869
|
+
$prevRow = null;
|
|
870
|
+
prevKind = null;
|
|
871
|
+
prevStart = null;
|
|
872
|
+
prevEnd = null;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Get kind, start, and end from next row
|
|
876
|
+
if (rowNum < ($rows.length - 1)) {
|
|
877
|
+
// this is not the last row. Include the next row
|
|
878
|
+
nextRowNum = rowNum + 1;
|
|
879
|
+
$nextRow = $rows.eq(nextRowNum);
|
|
880
|
+
if ($nextRow.is('[class^="kind-"]')) {
|
|
881
|
+
// row has a class that starts with "kind-"
|
|
882
|
+
// Extract kind from the class name
|
|
883
|
+
nextKind = this.getKindFromClass($nextRow.attr('class'));
|
|
884
|
+
}
|
|
885
|
+
else {
|
|
886
|
+
// Kind has not been assigned (e.g., newly inserted row)
|
|
887
|
+
nextKind = null;
|
|
888
|
+
}
|
|
889
|
+
nextStart = this.getSecondsFromColonTime($nextRow.find('td').eq(2).text());
|
|
890
|
+
nextEnd = this.getSecondsFromColonTime($nextRow.find('td').eq(3).text());
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
// this is the last row
|
|
894
|
+
nextRowNum = null;
|
|
895
|
+
$nextRow = null;
|
|
896
|
+
nextKind = null;
|
|
897
|
+
nextStart = null;
|
|
898
|
+
nextEnd = null;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
if (isNaN(start)) {
|
|
902
|
+
if (prevKind == null) {
|
|
903
|
+
// The previous row was probably inserted, and user has not yet selected a kind
|
|
904
|
+
// automatically set it to captions
|
|
905
|
+
prevKind = 'captions';
|
|
906
|
+
$prevRow.attr('class','kind-captions');
|
|
907
|
+
$prevRow.find('td').eq(1).html('captions');
|
|
908
|
+
}
|
|
909
|
+
// Current row has no start time (i.e., it's an inserted row)
|
|
910
|
+
if (prevKind === 'captions') {
|
|
911
|
+
// start the new row immediately after the captions end
|
|
912
|
+
start = (parseFloat(prevEnd) + .001).toFixed(3);
|
|
913
|
+
if (nextStart) {
|
|
914
|
+
// end the new row immediately before the next row starts
|
|
915
|
+
end = (parseFloat(nextStart) - .001).toFixed(3);
|
|
916
|
+
}
|
|
917
|
+
else {
|
|
918
|
+
// this is the last row. Use minDuration to calculate end time.
|
|
919
|
+
end = (parseFloat(start) + minDuration[kind]).toFixed(3);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
else if (prevKind === 'chapters') {
|
|
923
|
+
// start the new row immediately after the chapter start (not end)
|
|
924
|
+
start = (parseFloat(prevStart) + .001).toFixed(3);
|
|
925
|
+
if (nextStart) {
|
|
926
|
+
// end the new row immediately before the next row starts
|
|
927
|
+
end = (parseFloat(nextStart) - .001).toFixed(3);
|
|
928
|
+
}
|
|
929
|
+
else {
|
|
930
|
+
// this is the last row. Use minDuration to calculate end time.
|
|
931
|
+
end = (parseFloat(start) + minDurartion[kind]).toFixed(3);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
else if (prevKind === 'descriptions') {
|
|
935
|
+
// start the new row minDuration['descriptions'] after the description starts
|
|
936
|
+
// this will theoretically allow at least a small cushion for the description to be read
|
|
937
|
+
start = (parseFloat(prevStart) + minDuration['descriptions']).toFixed(3);
|
|
938
|
+
end = (parseFloat(start) + minDuration['descriptions']).toFixed(3);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
// current row has a start time (i.e., an existing row has been moved))
|
|
943
|
+
if (prevStart) {
|
|
944
|
+
// this is not the first row.
|
|
945
|
+
if (prevStart < start) {
|
|
946
|
+
if (start < nextStart) {
|
|
947
|
+
// No change is necessary
|
|
948
|
+
}
|
|
949
|
+
else {
|
|
950
|
+
// nextStart needs to be incremented
|
|
951
|
+
nextStart = (parseFloat(start) + minDuration[kind]).toFixed(3);
|
|
952
|
+
nextEnd = (parseFloat(nextStart) + minDuration[nextKind]).toFixed(3);
|
|
953
|
+
// TODO: Ensure nextEnd does not exceed the following start (nextNextStart)
|
|
954
|
+
// Or... maybe this is getting too complicated and should be left up to the user
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
// start needs to be incremented
|
|
959
|
+
start = (parseFloat(prevStart) + minDuration[prevKind]).toFixed(3);
|
|
960
|
+
end = (parseFloat(start) + minDuration[kind]).toFixed(3);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
// this is the first row
|
|
965
|
+
if (start < nextStart) {
|
|
966
|
+
// No change is necessary
|
|
967
|
+
}
|
|
968
|
+
else {
|
|
969
|
+
// nextStart needs to be incremented
|
|
970
|
+
nextStart = (parseFloat(start) + minDuration[kind]).toFixed(3);
|
|
971
|
+
nextEnd = (parseFloat(nextStart) + minDuration[nextKind]).toFixed(3);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// check to be sure there is sufficient duration between new start & end times
|
|
977
|
+
if (end - start < minDuration[kind]) {
|
|
978
|
+
// duration is too short. Change end time
|
|
979
|
+
end = (parseFloat(start) + minDuration[kind]).toFixed(3);
|
|
980
|
+
if (nextStart) {
|
|
981
|
+
// this is not the last row
|
|
982
|
+
// increase start time of next row
|
|
983
|
+
nextStart = (parseFloat(end) + .001).toFixed(3);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Update all affected start/end times
|
|
988
|
+
$row.find('td').eq(2).text(this.formatSecondsAsColonTime(start,true));
|
|
989
|
+
$row.find('td').eq(3).text(this.formatSecondsAsColonTime(end,true));
|
|
990
|
+
if ($prevRow) {
|
|
991
|
+
$prevRow.find('td').eq(2).text(this.formatSecondsAsColonTime(prevStart,true));
|
|
992
|
+
$prevRow.find('td').eq(3).text(this.formatSecondsAsColonTime(prevEnd,true));
|
|
993
|
+
}
|
|
994
|
+
if ($nextRow) {
|
|
995
|
+
$nextRow.find('td').eq(2).text(this.formatSecondsAsColonTime(nextStart,true));
|
|
996
|
+
$nextRow.find('td').eq(3).text(this.formatSecondsAsColonTime(nextEnd,true));
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
AblePlayer.prototype.getKindFromClass = function(myclass) {
|
|
1001
|
+
|
|
1002
|
+
// This function is called when a class with prefix "kind-" is found in the class attribute
|
|
1003
|
+
// TODO: Rewrite this using regular expressions
|
|
1004
|
+
var kindStart, kindEnd, kindLength, kind;
|
|
1005
|
+
|
|
1006
|
+
kindStart = myclass.indexOf('kind-')+5;
|
|
1007
|
+
kindEnd = myclass.indexOf(' ',kindStart);
|
|
1008
|
+
if (kindEnd == -1) {
|
|
1009
|
+
// no spaces found, "kind-" must be the only myclass
|
|
1010
|
+
kindLength = myclass.length - kindStart;
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
kindLength = kindEnd - kindStart;
|
|
1014
|
+
}
|
|
1015
|
+
kind = myclass.substr(kindStart,kindLength);
|
|
1016
|
+
return kind;
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
AblePlayer.prototype.showVtsAlert = function(message) {
|
|
1020
|
+
|
|
1021
|
+
// this is distinct from greater Able Player showAlert()
|
|
1022
|
+
// because it's positioning needs are unique
|
|
1023
|
+
// For now, alertDiv is fixed at top left of screen
|
|
1024
|
+
// but could ultimately be modified to appear near the point of action in the VTS table
|
|
1025
|
+
this.$vtsAlert.text(message).show().delay(3000).fadeOut('slow');
|
|
1026
|
+
};
|
|
1027
|
+
|
|
1028
|
+
AblePlayer.prototype.parseVtsOutput = function($table) {
|
|
1029
|
+
|
|
1030
|
+
// parse table into arrays, then into WebVTT content, for each kind
|
|
1031
|
+
// Display the WebVTT content in textarea fields for users to copy and paste
|
|
1032
|
+
var lang, i, kinds, kind, vtt, $rows, start, end, content, $output;
|
|
1033
|
+
|
|
1034
|
+
lang = $table.attr('lang');
|
|
1035
|
+
kinds = ['captions','chapters','descriptions','subtitles'];
|
|
1036
|
+
vtt = {};
|
|
1037
|
+
for (i=0; i < kinds.length; i++) {
|
|
1038
|
+
kind = kinds[i];
|
|
1039
|
+
vtt[kind] = 'WEBVTT' + "\n\n";
|
|
1040
|
+
}
|
|
1041
|
+
$rows = $table.find('tr');
|
|
1042
|
+
if ($rows.length > 0) {
|
|
1043
|
+
for (i=0; i < $rows.length; i++) {
|
|
1044
|
+
kind = $rows.eq(i).find('td').eq(1).text();
|
|
1045
|
+
if ($.inArray(kind,kinds) !== -1) {
|
|
1046
|
+
start = $rows.eq(i).find('td').eq(2).text();
|
|
1047
|
+
end = $rows.eq(i).find('td').eq(3).text();
|
|
1048
|
+
content = $rows.eq(i).find('td').eq(4).text();
|
|
1049
|
+
if (start !== undefined && end !== undefined) {
|
|
1050
|
+
vtt[kind] += start + ' --> ' + end + "\n";
|
|
1051
|
+
if (content !== 'undefined') {
|
|
1052
|
+
vtt[kind] += content;
|
|
1053
|
+
}
|
|
1054
|
+
vtt[kind] += "\n\n";
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
$output = $('<div>',{
|
|
1060
|
+
'id': 'able-vts-output'
|
|
1061
|
+
})
|
|
1062
|
+
$('#able-vts').append($output);
|
|
1063
|
+
for (i=0; i < kinds.length; i++) {
|
|
1064
|
+
kind = kinds[i];
|
|
1065
|
+
if (vtt[kind].length > 8) {
|
|
1066
|
+
// some content has been added
|
|
1067
|
+
this.showWebVttOutput(kind,vtt[kind],lang)
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
AblePlayer.prototype.showWebVttOutput = function(kind,vttString,lang) {
|
|
1073
|
+
|
|
1074
|
+
var $heading, filename, $p, pText, $textarea;
|
|
1075
|
+
|
|
1076
|
+
$heading = $('<h3>').text(kind.charAt(0).toUpperCase() + kind.slice(1));
|
|
1077
|
+
filename = this.getFilenameFromTracks(kind,lang);
|
|
1078
|
+
pText = 'If you made changes, copy/paste the following content ';
|
|
1079
|
+
if (filename) {
|
|
1080
|
+
pText += 'to replace the original content of your ' + this.getLanguageName(lang) + ' ';
|
|
1081
|
+
pText += '<em>' + kind + '</em> WebVTT file (<strong>' + filename + '</strong>).';
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
pText += 'into a new ' + this.getLanguageName(lang) + ' <em>' + kind + '</em> WebVTT file.';
|
|
1085
|
+
}
|
|
1086
|
+
$p = $('<p>',{
|
|
1087
|
+
'class': 'able-vts-output-instructions'
|
|
1088
|
+
}).html(pText);
|
|
1089
|
+
$textarea = $('<textarea>').text(vttString);
|
|
1090
|
+
$('#able-vts-output').append($heading,$p,$textarea);
|
|
1091
|
+
};
|
|
1092
1092
|
|
|
1093
1093
|
})(jQuery);
|