Skip to content

Commit f47847e

Browse files
author
Terrill
committed
Update draggable/resizable UI & extend to transcript window
1 parent 75cf133 commit f47847e

14 files changed

Lines changed: 3449 additions & 1121 deletions

File tree

‎build/ableplayer.dist.js‎

Lines changed: 1092 additions & 336 deletions
Large diffs are not rendered by default.

‎build/ableplayer.js‎

Lines changed: 1092 additions & 336 deletions
Large diffs are not rendered by default.

‎build/ableplayer.min.css‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎build/ableplayer.min.js‎

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎images/wingrip.png‎

259 Bytes
Loading

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ableplayer",
3-
"version": "2.3.40",
3+
"version": "2.3.41",
44
"description": "fully accessible HTML5 media player",
55
"homepage": "http://ableplayer.github.io/ableplayer",
66
"bugs": "https://github.com/ableplayer/ableplayer/issues",

‎scripts/buildplayer.js‎

Lines changed: 165 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@
1717
var thisObj, vidcapContainer, prefsGroups, i;
1818
thisObj = this;
1919

20-
// create $mediaContainer and $ableDiv and wrap them around the media element
20+
// create three wrappers and wrap them around the media element. From inner to outer:
21+
// $mediaContainer - contains the original media element
22+
// $ableDiv - contains the media player and all its objects (e.g., captions, controls, descriptions)
23+
// $ableWrapper - contains additional widgets (e.g., transcript window, sign window)
2124
this.$mediaContainer = this.$media.wrap('<div class="able-media-container"></div>').parent();
2225
this.$ableDiv = this.$mediaContainer.wrap('<div class="able"></div>').parent();
26+
this.$ableWrapper = this.$ableDiv.wrap('<div class="able-wrapper"></div>').parent();
2327
// width and height of this.$mediaContainer are not updated when switching to full screen
2428
// However, I don't think they're needed at all. Commented out on 4/12/15, but
2529
// preserved here just in case there are unanticipated problems...
@@ -154,12 +158,16 @@
154158
};
155159

156160
AblePlayer.prototype.injectTranscriptArea = function() {
161+
162+
var thisObj = this;
163+
157164
this.$transcriptArea = $('<div>', {
158-
'class': 'able-transcript-area'
165+
'class': 'able-transcript-area',
166+
'tabindex': '-1'
159167
});
160168

161169
this.$transcriptToolbar = $('<div>', {
162-
'class': 'able-transcript-toolbar'
170+
'class': 'able-window-toolbar'
163171
});
164172

165173
this.$transcriptDiv = $('<div>', {
@@ -179,23 +187,30 @@
179187
this.$transcriptLanguageSelect.append(this.$unknownTranscriptOption);
180188
this.$transcriptLanguageSelect.prop('disabled', true);
181189

182-
var floatRight = $('<div style="float: right;">');
183-
this.$transcriptLanguageSelectContainer = floatRight;
190+
var languageSelectWrapper = $('<div class="transcript-language-select-wrapper">');
191+
this.$transcriptLanguageSelectContainer = languageSelectWrapper;
184192

185-
floatRight.append($('<label for="transcript-language-select">' + this.tt.language + ': </label>'), this.$transcriptLanguageSelect);
186-
this.$transcriptToolbar.append(floatRight);
193+
languageSelectWrapper.append($('<label for="transcript-language-select">' + this.tt.language + ': </label>'), this.$transcriptLanguageSelect);
194+
this.$transcriptToolbar.append(languageSelectWrapper);
187195

188196
this.$transcriptArea.append(this.$transcriptToolbar, this.$transcriptDiv);
189197

190-
// If client has provided separate transcript location, put it there instead.
198+
// If client has provided separate transcript location, put it there.
199+
// Otherwise append it to the body
191200
if (this.transcriptDivLocation) {
192201
$('#' + this.transcriptDivLocation).append(this.$transcriptArea);
193202
}
194-
else if (this.$ableColumnRight) {
195-
this.$ableColumnRight.prepend(this.$transcriptArea);
196-
}
197203
else {
198-
this.splitPlayerIntoColumns('transcript');
204+
this.$ableWrapper.append(this.$transcriptArea);
205+
}
206+
207+
// make it draggable (popup only; NOT external transcript)
208+
if (!this.transcriptDivLocation) {
209+
this.initDragDrop('transcript');
210+
if (this.prefTranscript === 1) {
211+
// transcript is on. Go ahead and position it
212+
this.positionDraggableWindow('transcript',this.getDefaultWidth('transcript'));
213+
}
199214
}
200215

201216
// If client has provided separate transcript location, override user's preference for hiding transcript
@@ -204,6 +219,19 @@
204219
}
205220
};
206221

222+
AblePlayer.prototype.getDefaultWidth = function(which) {
223+
224+
// return default width of resizable elements
225+
// these values are somewhat arbitrary, but seem to result in good usability
226+
// if users disagree, they can resize (and resposition) them
227+
if (which === 'transcript') {
228+
return 450;
229+
}
230+
else if (which === 'sign') {
231+
return 400;
232+
}
233+
};
234+
207235
AblePlayer.prototype.populateChaptersDiv = function() {
208236

209237
var thisObj, headingLevel, headingType, headingId, $chaptersHeading,
@@ -294,41 +322,129 @@
294322
this.$chaptersDiv.append($chaptersNav);
295323
};
296324

297-
AblePlayer.prototype.splitPlayerIntoColumns = function (feature) {
298-
// feature is either 'transcript' or 'sign'
299-
// if present, player is split into two column, with this feature in the right column
300-
this.$ableColumnLeft = this.$ableDiv.wrap('<div class="able-column-left">').parent();
301-
this.$ableColumnLeft.width(this.playerWidth);
302-
if (feature === 'transcript') {
303-
this.$transcriptArea.insertAfter(this.$ableColumnLeft);
304-
this.$ableColumnRight = this.$transcriptArea.wrap('<div class="able-column-right">').parent();
325+
AblePlayer.prototype.positionDraggableWindow = function (which, width) {
326+
327+
// which is either 'transcript' or 'sign'
328+
329+
var cookie, cookiePos, $window, dragged, windowPos, currentWindowPos, firstTime;
330+
cookie = this.getCookie();
331+
if (which === 'transcript') {
332+
$window = this.$transcriptArea;
333+
if (typeof cookie.transcript !== 'undefined') {
334+
cookiePos = cookie.transcript;
335+
}
336+
}
337+
else if (which === 'sign') {
338+
$window = this.$signWindow;
339+
if (typeof cookie.transcript !== 'undefined') {
340+
cookiePos = cookie.sign;
341+
}
342+
}
343+
if (typeof cookiePos !== 'undefined' && !($.isEmptyObject(cookiePos))) {
344+
// position window using stored values from cookie
345+
$window.css({
346+
'position': cookiePos['position'],
347+
'width': cookiePos['width'],
348+
'z-index': cookiePos['zindex']
349+
});
350+
if (cookiePos['position'] === 'absolute') {
351+
$window.css({
352+
'top': cookiePos['top'],
353+
'left': cookiePos['left']
354+
});
355+
}
356+
// since cookie is not page-specific, z-index needs may vary across different pages
357+
this.updateZIndex(which);
305358
}
306-
else if (feature == 'sign') {
307-
this.$signArea.insertAfter(this.$ableColumnLeft);
308-
this.$ableColumnRight = this.$signArea.wrap('<div class="able-column-right">').parent();
359+
else {
360+
// position window using default values
361+
windowPos = this.getOptimumPosition(which, width);
362+
if (typeof width === 'undefined') {
363+
width = this.getDefaultWidth(which);
364+
}
365+
$window.css({
366+
'position': windowPos[0],
367+
'width': width,
368+
'z-index': windowPos[1]
369+
});
370+
if (windowPos[0] === 'absolute') {
371+
$window.css({
372+
'top': windowPos[2] + 'px',
373+
'left': windowPos[3] + 'px',
374+
});
375+
}
309376
}
310-
this.$ableColumnRight.width(this.playerWidth);
311377
};
312378

313-
AblePlayer.prototype.injectPoster = function ($element) {
314-
315-
// get poster attribute from media element and append that as an img to $element
316-
// currently only applies to YouTube and fallback
317-
var poster;
318-
319-
if (this.$media.attr('poster')) {
320-
poster = this.$media.attr('poster');
321-
this.$posterImg = $('<img>',{
322-
'class': 'able-poster',
323-
'src' : poster,
324-
'alt' : "",
325-
'role': "presentation",
326-
'width': this.playerWidth,
327-
'height': this.playerHeight
328-
});
329-
$element.append(this.$posterImg);
379+
AblePlayer.prototype.getOptimumPosition = function (targetWindow, targetWidth) {
380+
381+
// returns optimum position for targetWindow, as an array with the following structure:
382+
// 0 - CSS position ('absolute' or 'relative')
383+
// 1 - zindex
384+
// 2 - top
385+
// 3 - left
386+
// targetWindow is either 'transcript' or 'sign'
387+
// if there is room to the right of the player, position element there
388+
// else if there is room the left of the player, position element there
389+
// else position element beneath player
390+
391+
var gap, position, ableWidth, ableHeight, ableOffset, ableTop, ableLeft,
392+
windowWidth, otherWindowWidth, zIndex;
393+
394+
if (typeof targetWidth === 'undefined') {
395+
targetWidth = this.getDefaultWidth(targetWindow);
330396
}
331-
}
397+
398+
gap = 5; // number of pixels to preserve between Able Player objects
399+
400+
position = []; // position, top, left
401+
402+
ableWidth = this.$ableDiv.width();
403+
ableHeight = this.$ableDiv.height();
404+
ableOffset = this.$ableDiv.offset();
405+
ableTop = ableOffset.top;
406+
ableLeft = ableOffset.left;
407+
windowWidth = $(window).width();
408+
otherWindowWidth = 0; // width of other visiable draggable windows will be added to this
409+
410+
// get optimum zIndex for this window
411+
zIndex = this.getHighestZIndex(targetWindow);
412+
413+
if (targetWindow === 'transcript') {
414+
if (typeof this.$signWindow !== 'undefined') {
415+
if (this.$signWindow.is(':visible')) {
416+
otherWindowWidth = this.$signWindow.width() + gap;
417+
}
418+
}
419+
}
420+
else if (targetWindow === 'sign') {
421+
if (typeof this.$transcriptArea !== 'undefined') {
422+
if (this.$transcriptArea.is(':visible')) {
423+
otherWindowWidth = this.$transcriptArea.width() + gap;
424+
}
425+
}
426+
}
427+
if (targetWidth < (windowWidth - (ableLeft + ableWidth + gap + otherWindowWidth))) {
428+
// there's room to the left of $ableDiv
429+
position[0] = 'absolute';
430+
position[1] = zIndex;
431+
position[2] = 0;
432+
position[3] = ableWidth + otherWindowWidth + gap;
433+
}
434+
else if (targetWidth + gap < ableLeft) {
435+
// there's room to the right of $ableDiv
436+
position[0] = 'absolute';
437+
position[1] = zIndex;
438+
position[2] = 0;
439+
position[3] = ableLeft - targetWidth - gap;
440+
}
441+
else {
442+
// position element below $ableDiv
443+
position[0] = 'relative';
444+
// no need to define z-index, top, or left
445+
}
446+
return position;
447+
};
332448

333449
AblePlayer.prototype.injectAlert = function () {
334450

@@ -421,14 +537,15 @@
421537
// Create popup div and append to player
422538
// 'which' parameter is either 'captions', 'chapters', 'prefs', or 'X-window' (e.g., "sign-window")
423539
AblePlayer.prototype.createPopup = function (which) {
540+
424541
var thisObj, $popup, $thisButton, $thisListItem, $prevButton, $nextButton,
425542
selectedTrackIndex, selectedTrack;
426543
thisObj = this;
427544
$popup = $('<div>',{
428545
'id': this.mediaId + '-' + which + '-menu',
429546
'class': 'able-popup'
430547
});
431-
if (which == 'chapters' || which == 'prefs') {
548+
if (which === 'chapters' || which === 'prefs' || which === 'sign-window' || which === 'transcript-window') {
432549
$popup.addClass('able-popup-no-radio');
433550
}
434551
$popup.on('keydown',function (e) {
@@ -844,8 +961,6 @@
844961
}
845962

846963
controlLayout['br'].push('preferences');
847-
// Help button eliminated in v2.3.4 - help text combined into Preferences dialog
848-
// controlLayout['br'].push('help');
849964

850965
// TODO: JW currently has a bug with fullscreen, anything that can be done about this?
851966
if (this.mediaType === 'video' && this.allowFullScreen && this.player !== 'jw') {
@@ -1091,6 +1206,10 @@
10911206
}
10921207
else if (control === 'sign') {
10931208
this.$signButton = newButton;
1209+
// gray out sign button if sign language window is not active
1210+
if (!(this.$signWindow.is(':visible'))) {
1211+
this.$signButton.addClass('buttonOff');
1212+
}
10941213
}
10951214
else if (control === 'descriptions') {
10961215
this.$descButton = newButton;
@@ -1130,20 +1249,7 @@
11301249
}
11311250

11321251
if (this.mediaType === 'video') {
1133-
// As of v 2.3.4, no longer adding width and height on this.$vidCapContainer
1134-
// CAN'T constrain the height if this.prefCaptionsPosition === 'below'
1135-
// because the caption div below the video needs to be able to expand as needed
1136-
// Checked the new setting in Firefox, Chrome, & IE and it seems to work w/o width & height
1137-
/*
1138-
// set width and height of div.able-vidcap-container
1139-
vidcapStyles = {
1140-
'width': this.playerWidth+'px',
1141-
'height': this.playerHeight+'px'
1142-
}
1143-
if (this.$vidcapContainer) {
1144-
this.$vidcapContainer.css(vidcapStyles);
1145-
}
1146-
*/
1252+
11471253
if (this.$captionDiv) {
11481254
// set width of the captions container
11491255
this.$captionDiv.css('width',this.playerWidth+'px');

0 commit comments

Comments
 (0)