wai-website-theme 1.3.1 → 1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/different.html +2 -1
  3. data/_includes/external.html +2 -1
  4. data/_includes/header.html +2 -1
  5. data/_includes/menuitem.html +6 -2
  6. data/_includes/peoplelist.html +21 -0
  7. data/_includes/prevnext-navigation.html +56 -0
  8. data/_includes/{prevnext.html → prevnext-order.html} +9 -0
  9. data/_includes/translation-note-msg.html +5 -3
  10. data/_includes/video-player.html +2 -2
  11. data/_layouts/default.html +8 -1
  12. data/_layouts/news.html +7 -1
  13. data/_layouts/policy.html +7 -1
  14. data/_layouts/sidenav.html +8 -1
  15. data/_layouts/sidenavsidebar.html +8 -1
  16. data/assets/ableplayer/Gruntfile.js +2 -1
  17. data/assets/ableplayer/README.md +158 -85
  18. data/assets/ableplayer/build/ableplayer.dist.js +15445 -13823
  19. data/assets/ableplayer/build/ableplayer.js +15445 -13823
  20. data/assets/ableplayer/build/ableplayer.min.css +1 -2
  21. data/assets/ableplayer/build/ableplayer.min.js +3 -10
  22. data/assets/ableplayer/package-lock.json +944 -346
  23. data/assets/ableplayer/package.json +8 -8
  24. data/assets/ableplayer/scripts/ableplayer-base.js +515 -524
  25. data/assets/ableplayer/scripts/browser.js +158 -158
  26. data/assets/ableplayer/scripts/buildplayer.js +1750 -1682
  27. data/assets/ableplayer/scripts/caption.js +424 -401
  28. data/assets/ableplayer/scripts/chapters.js +259 -259
  29. data/assets/ableplayer/scripts/control.js +1831 -1594
  30. data/assets/ableplayer/scripts/description.js +333 -256
  31. data/assets/ableplayer/scripts/dialog.js +145 -145
  32. data/assets/ableplayer/scripts/dragdrop.js +746 -749
  33. data/assets/ableplayer/scripts/event.js +875 -696
  34. data/assets/ableplayer/scripts/initialize.js +819 -912
  35. data/assets/ableplayer/scripts/langs.js +979 -743
  36. data/assets/ableplayer/scripts/metadata.js +124 -124
  37. data/assets/ableplayer/scripts/misc.js +170 -137
  38. data/assets/ableplayer/scripts/preference.js +904 -904
  39. data/assets/ableplayer/scripts/search.js +172 -172
  40. data/assets/ableplayer/scripts/sign.js +82 -78
  41. data/assets/ableplayer/scripts/slider.js +449 -448
  42. data/assets/ableplayer/scripts/track.js +409 -309
  43. data/assets/ableplayer/scripts/transcript.js +684 -595
  44. data/assets/ableplayer/scripts/translation.js +63 -67
  45. data/assets/ableplayer/scripts/ttml2webvtt.js +85 -85
  46. data/assets/ableplayer/scripts/vimeo.js +448 -0
  47. data/assets/ableplayer/scripts/volume.js +395 -380
  48. data/assets/ableplayer/scripts/vts.js +1077 -1077
  49. data/assets/ableplayer/scripts/webvtt.js +766 -763
  50. data/assets/ableplayer/scripts/youtube.js +695 -478
  51. data/assets/ableplayer/styles/ableplayer.css +54 -46
  52. data/assets/ableplayer/translations/nl.js +54 -54
  53. data/assets/ableplayer/translations/pt-br.js +311 -0
  54. data/assets/ableplayer/translations/tr.js +311 -0
  55. data/assets/ableplayer/translations/zh-tw.js +1 -1
  56. data/assets/css/style.css +1 -1
  57. data/assets/css/style.css.map +1 -1
  58. data/assets/images/icons.svg +5 -5
  59. data/assets/scripts/main.js +7 -0
  60. data/assets/search/tipuesearch.js +3 -3
  61. metadata +8 -3
@@ -1,147 +1,147 @@
1
1
  (function ($) {
2
- var focusableElementsSelector = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
3
-
4
- // Based on the incredible accessible modal dialog.
5
- window.AccessibleDialog = function(modalDiv, $returnElement, dialogRole, title, $descDiv, closeButtonLabel, width, fullscreen, escapeHook) {
6
-
7
- this.title = title;
8
- this.closeButtonLabel = closeButtonLabel;
9
- this.focusedElementBeforeModal = $returnElement;
10
- this.escapeHook = escapeHook;
11
- this.baseId = $(modalDiv).attr('id') || Math.floor(Math.random() * 1000000000).toString();
12
- var thisObj = this;
13
- var modal = modalDiv;
14
- this.modal = modal;
15
- modal.css({
16
- 'width': width || '50%',
17
- 'top': (fullscreen ? '0' : '5%')
18
- });
19
- modal.addClass('able-modal-dialog');
20
-
21
- if (!fullscreen) {
22
- var closeButton = $('<button>',{
23
- 'class': 'modalCloseButton',
24
- 'title': thisObj.closeButtonLabel,
25
- 'aria-label': thisObj.closeButtonLabel
26
- }).text('X');
27
- closeButton.keydown(function (e) {
28
- // Space key down
29
- if (e.which === 32) {
30
- thisObj.hide();
31
- }
32
- }).click(function () {
33
- thisObj.hide();
34
- });
35
-
36
- var titleH1 = $('<h1></h1>');
37
- titleH1.attr('id', 'modalTitle-' + this.baseId);
38
- titleH1.css('text-align', 'center');
39
- titleH1.text(title);
40
-
41
- $descDiv.attr('id', 'modalDesc-' + this.baseId);
42
-
43
- modal.attr({
44
- 'aria-labelledby': 'modalTitle-' + this.baseId,
45
- 'aria-describedby': 'modalDesc-' + this.baseId
46
- });
47
- modal.prepend(titleH1);
48
- modal.prepend(closeButton);
49
- }
50
-
51
- modal.attr({
52
- 'aria-hidden': 'true',
53
- 'role': dialogRole
54
- });
55
-
56
- modal.keydown(function (e) {
57
- // Escape
58
- if (e.which === 27) {
59
- if (thisObj.escapeHook) {
60
- thisObj.escapeHook(e, this);
61
- }
62
- else {
63
- thisObj.hide();
64
- e.preventDefault();
65
- }
66
- }
67
- // Tab
68
- else if (e.which === 9) {
69
- // Manually loop tab navigation inside the modal.
70
- var parts = modal.find('*');
71
- var focusable = parts.filter(focusableElementsSelector).filter(':visible');
72
-
73
- if (focusable.length === 0) {
74
- return;
75
- }
76
-
77
- var focused = $(':focus');
78
- var currentIndex = focusable.index(focused);
79
- if (e.shiftKey) {
80
- // If backwards from first element, go to last.
81
- if (currentIndex === 0) {
82
- focusable.get(focusable.length - 1).focus();
83
- e.preventDefault();
84
- }
85
- }
86
- else {
87
- if (currentIndex === focusable.length - 1) {
88
- focusable.get(0).focus();
89
- e.preventDefault();
90
- }
91
- }
92
- }
93
- e.stopPropagation();
94
- });
95
-
96
- $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
97
- };
98
-
99
- AccessibleDialog.prototype.show = function () {
100
- if (!this.overlay) {
101
- // Generate overlay.
102
- var overlay = $('<div></div>').attr({
103
- 'class': 'able-modal-overlay',
104
- 'tabindex': '-1'
105
- });
106
- this.overlay = overlay;
107
- $('body').append(overlay);
108
-
109
- // Keep from moving focus out of dialog when clicking outside of it.
110
- overlay.on('mousedown.accessibleModal', function (e) {
111
- e.preventDefault();
112
- });
113
- }
114
-
115
- $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'true');
116
-
117
- this.overlay.css('display', 'block');
118
- this.modal.css('display', 'block');
119
- this.modal.attr({
120
- 'aria-hidden': 'false',
121
- 'tabindex': '-1'
122
- });
123
-
124
- var focusable = this.modal.find("*").filter(focusableElementsSelector).filter(':visible');
125
- if (focusable.length === 0) {
126
- this.focusedElementBeforeModal.blur();
127
- }
128
- var thisObj = this;
129
- setTimeout(function () {
130
- // originally set focus on the first focusable element
131
- // thisObj.modal.find('button.modalCloseButton').first().focus();
132
- // but setting focus on dialog seems to provide more reliable access to ALL content within
133
- thisObj.modal.focus();
134
- }, 300);
135
- };
136
-
137
- AccessibleDialog.prototype.hide = function () {
138
- if (this.overlay) {
139
- this.overlay.css('display', 'none');
140
- }
141
- this.modal.css('display', 'none');
142
- this.modal.attr('aria-hidden', 'true');
143
- $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
144
-
145
- this.focusedElementBeforeModal.focus();
146
- };
2
+ var focusableElementsSelector = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]";
3
+
4
+ // Based on the incredible accessible modal dialog.
5
+ window.AccessibleDialog = function(modalDiv, $returnElement, dialogRole, title, $descDiv, closeButtonLabel, width, fullscreen, escapeHook) {
6
+
7
+ this.title = title;
8
+ this.closeButtonLabel = closeButtonLabel;
9
+ this.focusedElementBeforeModal = $returnElement;
10
+ this.escapeHook = escapeHook;
11
+ this.baseId = $(modalDiv).attr('id') || Math.floor(Math.random() * 1000000000).toString();
12
+ var thisObj = this;
13
+ var modal = modalDiv;
14
+ this.modal = modal;
15
+ modal.css({
16
+ 'width': width || '50%',
17
+ 'top': (fullscreen ? '0' : '5%')
18
+ });
19
+ modal.addClass('able-modal-dialog');
20
+
21
+ if (!fullscreen) {
22
+ var closeButton = $('<button>',{
23
+ 'class': 'modalCloseButton',
24
+ 'title': thisObj.closeButtonLabel,
25
+ 'aria-label': thisObj.closeButtonLabel
26
+ }).text('X');
27
+ closeButton.keydown(function (e) {
28
+ // Space key down
29
+ if (e.which === 32) {
30
+ thisObj.hide();
31
+ }
32
+ }).click(function () {
33
+ thisObj.hide();
34
+ });
35
+
36
+ var titleH1 = $('<h1></h1>');
37
+ titleH1.attr('id', 'modalTitle-' + this.baseId);
38
+ titleH1.css('text-align', 'center');
39
+ titleH1.text(title);
40
+
41
+ $descDiv.attr('id', 'modalDesc-' + this.baseId);
42
+
43
+ modal.attr({
44
+ 'aria-labelledby': 'modalTitle-' + this.baseId,
45
+ 'aria-describedby': 'modalDesc-' + this.baseId
46
+ });
47
+ modal.prepend(titleH1);
48
+ modal.prepend(closeButton);
49
+ }
50
+
51
+ modal.attr({
52
+ 'aria-hidden': 'true',
53
+ 'role': dialogRole
54
+ });
55
+
56
+ modal.keydown(function (e) {
57
+ // Escape
58
+ if (e.which === 27) {
59
+ if (thisObj.escapeHook) {
60
+ thisObj.escapeHook(e, this);
61
+ }
62
+ else {
63
+ thisObj.hide();
64
+ e.preventDefault();
65
+ }
66
+ }
67
+ // Tab
68
+ else if (e.which === 9) {
69
+ // Manually loop tab navigation inside the modal.
70
+ var parts = modal.find('*');
71
+ var focusable = parts.filter(focusableElementsSelector).filter(':visible');
72
+
73
+ if (focusable.length === 0) {
74
+ return;
75
+ }
76
+
77
+ var focused = $(':focus');
78
+ var currentIndex = focusable.index(focused);
79
+ if (e.shiftKey) {
80
+ // If backwards from first element, go to last.
81
+ if (currentIndex === 0) {
82
+ focusable.get(focusable.length - 1).focus();
83
+ e.preventDefault();
84
+ }
85
+ }
86
+ else {
87
+ if (currentIndex === focusable.length - 1) {
88
+ focusable.get(0).focus();
89
+ e.preventDefault();
90
+ }
91
+ }
92
+ }
93
+ e.stopPropagation();
94
+ });
95
+
96
+ $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
97
+ };
98
+
99
+ AccessibleDialog.prototype.show = function () {
100
+ if (!this.overlay) {
101
+ // Generate overlay.
102
+ var overlay = $('<div></div>').attr({
103
+ 'class': 'able-modal-overlay',
104
+ 'tabindex': '-1'
105
+ });
106
+ this.overlay = overlay;
107
+ $('body').append(overlay);
108
+
109
+ // Keep from moving focus out of dialog when clicking outside of it.
110
+ overlay.on('mousedown.accessibleModal', function (e) {
111
+ e.preventDefault();
112
+ });
113
+ }
114
+
115
+ $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'true');
116
+
117
+ this.overlay.css('display', 'block');
118
+ this.modal.css('display', 'block');
119
+ this.modal.attr({
120
+ 'aria-hidden': 'false',
121
+ 'tabindex': '-1'
122
+ });
123
+
124
+ var focusable = this.modal.find("*").filter(focusableElementsSelector).filter(':visible');
125
+ if (focusable.length === 0) {
126
+ this.focusedElementBeforeModal.blur();
127
+ }
128
+ var thisObj = this;
129
+ setTimeout(function () {
130
+ // originally set focus on the first focusable element
131
+ // thisObj.modal.find('button.modalCloseButton').first().focus();
132
+ // but setting focus on dialog seems to provide more reliable access to ALL content within
133
+ thisObj.modal.focus();
134
+ }, 300);
135
+ };
136
+
137
+ AccessibleDialog.prototype.hide = function () {
138
+ if (this.overlay) {
139
+ this.overlay.css('display', 'none');
140
+ }
141
+ this.modal.css('display', 'none');
142
+ this.modal.attr('aria-hidden', 'true');
143
+ $('body > *').not('.able-modal-overlay').not('.able-modal-dialog').attr('aria-hidden', 'false');
144
+
145
+ this.focusedElementBeforeModal.focus();
146
+ };
147
147
  })(jQuery);
@@ -1,759 +1,756 @@
1
1
  (function ($) {
2
2
 
3
- AblePlayer.prototype.initDragDrop = function ( which ) {
4
-
5
- // supported values of which: 'sign', 'transcript'
6
-
7
- // NOTE: "Drag and Drop" for Able Player is a metaphor only!!!
8
- // HTML5 Drag & Drop API enables moving elements to new locations in the DOM
9
- // Thats not our purpose; we're simply changing the visible position on-screen
10
- // Therefore, the drag & drop interface was overhauled in v2.3.41 to simple
11
- // use mouse (and keyboard) events to change CSS positioning properties
12
-
13
- // There are nevertheless lessons to be learned from Drag & Drop about accessibility:
14
- // http://dev.opera.com/articles/accessible-drag-and-drop/
15
-
16
- var thisObj, $window, $toolbar, windowName, $resizeHandle, resizeZIndex;
17
-
18
- thisObj = this;
19
-
20
- if (which === 'transcript') {
21
- $window = this.$transcriptArea;
22
- windowName = 'transcript-window';
23
- $toolbar = this.$transcriptToolbar;
24
- }
25
- else if (which === 'sign') {
26
- $window = this.$signWindow;
27
- windowName = 'sign-window';
28
- $toolbar = this.$signToolbar;
29
- }
30
-
31
- // add class to trigger change in cursor on hover
32
- $toolbar.addClass('able-draggable');
33
-
34
- // add resize handle selector to bottom right corner
35
- $resizeHandle = $('<div>',{
36
- 'class': 'able-resizable'
37
- });
38
- // assign z-index that's slightly higher than parent window
39
- resizeZIndex = parseInt($window.css('z-index')) + 100;
40
- $resizeHandle.css('z-index',resizeZIndex);
41
- $window.append($resizeHandle);
42
-
43
- // add event listener to toolbar to start and end drag
44
- // other event listeners will be added when drag starts
45
- $toolbar.on('mousedown', function(e) {
46
- e.stopPropagation();
47
- if (!thisObj.windowMenuClickRegistered) {
48
- thisObj.windowMenuClickRegistered = true;
49
- thisObj.startMouseX = e.pageX;
50
- thisObj.startMouseY = e.pageY;
51
- thisObj.dragDevice = 'mouse';
52
- thisObj.startDrag(which, $window);
53
- }
54
- return false;
55
- });
56
- $toolbar.on('mouseup', function(e) {
57
- e.stopPropagation();
58
- if (thisObj.dragging && thisObj.dragDevice === 'mouse') {
59
- thisObj.endDrag(which);
60
- }
61
- return false;
62
- });
63
-
64
- // add event listeners for resizing
65
- $resizeHandle.on('mousedown', function(e) {
66
-
67
- e.stopPropagation();
68
- if (!thisObj.windowMenuClickRegistered) {
69
- thisObj.windowMenuClickRegistered = true;
70
- thisObj.startMouseX = e.pageX;
71
- thisObj.startMouseY = e.pageY;
72
- thisObj.startResize(which, $window);
73
- return false;
74
- }
75
- });
76
-
77
- $resizeHandle.on('mouseup', function(e) {
78
- e.stopPropagation();
79
- if (thisObj.resizing) {
80
- thisObj.endResize(which);
81
- }
82
- return false;
83
- });
84
-
85
- // whenever a window is clicked, bring it to the foreground
86
- $window.on('click', function() {
87
-
88
- if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
89
- thisObj.updateZIndex(which);
90
- }
91
- thisObj.finishingDrag = false;
92
- });
93
-
94
- this.addWindowMenu(which,$window,windowName);
95
- };
96
-
97
- AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) {
98
-
99
-
100
- var thisObj, $windowAlert, menuId, $newButton, $buttonIcon, buttonImgSrc, $buttonImg,
101
- $buttonLabel, tooltipId, $tooltip, $popup,
102
- label, position, buttonHeight, buttonWidth, tooltipY, tooltipX, tooltipStyle, tooltip,
103
- $optionList, menuBaseId, options, i, $optionItem, option, menuId;
104
-
105
- thisObj = this;
106
-
107
- // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked
108
- // This will prevent the click event from also triggering a mousedown event on the toolbar
109
- // (which would unexpectedly send the window into drag mode)
110
- this.windowMenuClickRegistered = false;
111
-
112
- // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag
113
- // this will prevent the click event from being triggered
114
- this.finishingDrag = false;
115
-
116
- // create an alert div and add it to window
117
- $windowAlert = $('<div role="alert"></div>');
118
- $windowAlert.addClass('able-alert');
119
- $windowAlert.hide();
120
- $windowAlert.appendTo(this.$activeWindow);
121
- $windowAlert.css({
122
- top: $window.offset().top
123
- });
124
-
125
- // add button to draggable window which triggers a popup menu
126
- // for now, re-use preferences icon for this purpose
127
- menuId = this.mediaId + '-' + windowName + '-menu';
128
- $newButton = $('<button>',{
129
- 'type': 'button',
130
- 'tabindex': '0',
131
- 'aria-label': this.tt.windowButtonLabel,
132
- 'aria-haspopup': 'true',
133
- 'aria-controls': menuId,
134
- 'class': 'able-button-handler-preferences'
135
- });
136
- if (this.iconType === 'font') {
137
- $buttonIcon = $('<span>',{
138
- 'class': 'icon-preferences',
139
- 'aria-hidden': 'true'
140
- });
141
- $newButton.append($buttonIcon);
142
- }
143
- else {
144
- // use image
145
- buttonImgSrc = this.rootPath + 'button-icons/' + this.toolbarIconColor + '/preferences.png';
146
- $buttonImg = $('<img>',{
147
- 'src': buttonImgSrc,
148
- 'alt': '',
149
- 'role': 'presentation'
150
- });
151
- $newButton.append($buttonImg);
152
- }
153
-
154
- // add the visibly-hidden label for screen readers that don't support aria-label on the button
155
- $buttonLabel = $('<span>',{
156
- 'class': 'able-clipped'
157
- }).text(this.tt.windowButtonLabel);
158
- $newButton.append($buttonLabel);
159
-
160
- // add a tooltip that displays aria-label on mouseenter or focus
161
- tooltipId = this.mediaId + '-' + windowName + '-tooltip';
162
- $tooltip = $('<div>',{
163
- 'class' : 'able-tooltip',
164
- 'id' : tooltipId
165
- }).hide();
166
- $newButton.on('mouseenter focus',function(e) {
167
- var label = $(this).attr('aria-label');
168
- // get position of this button
169
- var position = $(this).position();
170
- var buttonHeight = $(this).height();
171
- var buttonWidth = $(this).width();
172
- var tooltipY = position.top - buttonHeight - 5;
173
- var tooltipX = 0;
174
- var tooltipStyle = {
175
- left: '',
176
- right: tooltipX + 'px',
177
- top: tooltipY + 'px'
178
- };
179
- var tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(label).css(tooltipStyle);
180
- thisObj.showTooltip(tooltip);
181
- $(this).on('mouseleave blur',function() {
182
- AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
183
- });
184
- });
185
-
186
- // setup popup menu
187
- $popup = this.setupPopups(windowName); // 'transcript-window' or 'sign-window'
188
- // define vars and assemble all the parts
189
- if (which === 'transcript') {
190
- this.$transcriptAlert = $windowAlert;
191
- this.$transcriptPopupButton = $newButton;
192
- this.$transcriptPopup = $popup;
193
- this.$transcriptToolbar.append($windowAlert,$newButton,$tooltip,$popup);
194
- }
195
- else if (which === 'sign') {
196
- this.$signAlert = $windowAlert;
197
- this.$signPopupButton = $newButton;
198
- this.$signPopup = $popup;
199
- this.$signToolbar.append($windowAlert,$newButton,$tooltip,$popup);
200
- }
201
-
202
- // handle button click
203
- $newButton.on('click mousedown keydown',function(e) {
204
- e.stopPropagation();
205
- if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
206
- // don't set windowMenuClickRegistered yet; that happens in handler function
207
- thisObj.handleWindowButtonClick(which, e);
208
- }
209
- thisObj.finishingDrag = false;
210
- });
211
-
212
- this.addResizeDialog(which, $window);
213
- };
214
-
215
- AblePlayer.prototype.addResizeDialog = function (which, $window) {
216
-
217
- var thisObj, $windowPopup, $windowButton,
218
- widthId, heightId, startingWidth, startingHeight, aspectRatio,
219
- $resizeForm, $resizeWrapper,
220
- $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel,
221
- $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel,
222
- tempWidth, tempHeight,
223
- $saveButton, $cancelButton, newWidth, newHeight, resizeDialog;
224
-
225
- thisObj = this;
226
-
227
- if (which === 'transcript') {
228
- $windowPopup = this.$transcriptPopup;
229
- $windowButton = this.$transcriptPopupButton;
230
- }
231
- else if (which === 'sign') {
232
- $windowPopup = this.$signPopup;
233
- $windowButton = this.$signPopupButton;
234
- }
235
-
236
- widthId = this.mediaId + '-resize-' + which + '-width';
237
- heightId = this.mediaId + '-resize-' + which + '-height';
238
- startingWidth = $window.width();
239
- startingHeight = $window.height();
240
- aspectRatio = startingWidth / startingHeight;
241
-
242
- $resizeForm = $('<div></div>',{
243
- 'class' : 'able-resize-form'
244
- });
245
-
246
- // inner container for all content, will be assigned to modal div's aria-describedby
247
- $resizeWrapper = $('<div></div>');
248
-
249
- // width field
250
- $resizeWidthDiv = $('<div></div>');
251
- $resizeWidthInput = $('<input>',{
252
- 'type': 'text',
253
- 'id': widthId,
254
- 'value': startingWidth
255
- });
256
- $resizeWidthLabel = $('<label>',{
257
- 'for': widthId
258
- }).text(this.tt.width);
259
-
260
- // height field
261
- $resizeHeightDiv = $('<div></div>');
262
- $resizeHeightInput = $('<input>',{
263
- 'type': 'text',
264
- 'id': heightId,
265
- 'value': startingHeight
266
- });
267
- $resizeHeightLabel = $('<label>',{
268
- 'for': heightId
269
- }).text(this.tt.height);
270
-
271
- if (which === 'sign') {
272
- // make height a read-only field
273
- // and calculate its value based on width to preserve aspect ratio
274
- $resizeHeightInput.prop('readonly',true);
275
- $resizeWidthInput.on('input',function() {
276
- tempWidth = $(this).val();
277
- tempHeight = Math.round(tempWidth/aspectRatio, 0);
278
- $resizeHeightInput.val(tempHeight);
279
- })
280
- }
281
-
282
- // Add save and cancel buttons.
283
- $saveButton = $('<button class="modal-button">' + this.tt.save + '</button>');
284
- $cancelButton = $('<button class="modal-button">' + this.tt.cancel + '</button>');
285
- $saveButton.on('click',function () {
286
- newWidth = $('#' + widthId).val();
287
- newHeight = $('#' + heightId).val();
288
- if (newWidth !== startingWidth || newHeight !== startingHeight) {
289
- $window.css({
290
- 'width': newWidth + 'px',
291
- 'height': newHeight + 'px'
292
- });
293
- thisObj.updateCookie(which);
294
- }
295
- resizeDialog.hide();
296
- $windowPopup.hide();
297
- $windowButton.focus();
298
- });
299
- $cancelButton.on('click',function () {
300
- resizeDialog.hide();
301
- $windowPopup.hide();
302
- $windowButton.focus();
303
- });
304
-
305
- // Now assemble all the parts
306
- $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput);
307
- $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput);
308
- $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv);
309
- $resizeForm.append($resizeWrapper,'<hr>',$saveButton,$cancelButton);
310
-
311
- // must be appended to the BODY!
312
- // otherwise when aria-hidden="true" is applied to all background content
313
- // that will include an ancestor of the dialog,
314
- // which will render the dialog unreadable by screen readers
315
- $('body').append($resizeForm);
316
- resizeDialog = new AccessibleDialog($resizeForm, $windowButton, 'alert', this.tt.windowResizeHeading, $resizeWrapper, this.tt.closeButtonLabel, '20em');
317
- if (which === 'transcript') {
318
- this.transcriptResizeDialog = resizeDialog;
319
- }
320
- else if (which === 'sign') {
321
- this.signResizeDialog = resizeDialog;
322
- }
323
- };
324
-
325
- AblePlayer.prototype.handleWindowButtonClick = function (which, e) {
326
-
327
- var thisObj, $windowPopup, $windowButton, $toolbar, popupTop;
328
-
329
- thisObj = this;
330
-
331
- if (which === 'transcript') {
332
- $windowPopup = this.$transcriptPopup;
333
- $windowButton = this.$transcriptPopupButton;
334
- $toolbar = this.$transcriptToolbar;
335
- }
336
- else if (which === 'sign') {
337
- $windowPopup = this.$signPopup;
338
- $windowButton = this.$signPopupButton;
339
- $toolbar = this.$signToolbar;
340
- }
341
-
342
- if (e.type === 'keydown') {
343
- // user pressed a key
344
- if (e.which === 32 || e.which === 13) {
345
- // this was Enter or space
346
- this.windowMenuClickRegistered = true;
347
- }
348
- else if (e.which === 27) { // escape
349
- // hide the popup menu
350
- $windowPopup.hide('fast', function() {
351
- // also reset the Boolean
352
- thisObj.windowMenuClickRegistered = false;
353
- // also restore menu items to their original state
354
- $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
355
- // also return focus to window options button
356
- $windowButton.focus();
357
- });
358
- }
359
- else {
360
- return false;
361
- }
362
- }
363
- else {
364
- // this was a mouse event
365
- this.windowMenuClickRegistered = true;
366
- }
367
-
368
- if ($windowPopup.is(':visible')) {
369
- $windowPopup.hide(200,'',function() {
370
- thisObj.windowMenuClickRegistered = false; // reset
371
- });
372
- $windowPopup.find('li').removeClass('able-focus');
373
- $windowButton.attr('aria-expanded','false').focus();
374
- }
375
- else {
376
- // first, be sure window is on top
377
- this.updateZIndex(which);
378
- popupTop = $windowButton.position().top + $windowButton.outerHeight();
379
- $windowPopup.css('top', popupTop);
380
- $windowPopup.show(200,'',function() {
381
- $windowButton.attr('aria-expanded','true');
382
- $(this).find('li').first().focus().addClass('able-focus');
383
- thisObj.windowMenuClickRegistered = false; // reset
384
- });
385
- }
386
- };
387
-
388
- AblePlayer.prototype.handleMenuChoice = function (which, choice, e) {
389
-
390
- var thisObj, $window, $windowPopup, $windowButton, resizeDialog, $thisRadio;
391
-
392
- thisObj = this;
393
-
394
- if (which === 'transcript') {
395
- $window = this.$transcriptArea;
396
- $windowPopup = this.$transcriptPopup;
397
- $windowButton = this.$transcriptPopupButton;
398
- resizeDialog = this.transcriptResizeDialog;
399
- }
400
- else if (which === 'sign') {
401
- $window = this.$signWindow;
402
- $windowPopup = this.$signPopup;
403
- $windowButton = this.$signPopupButton;
404
- resizeDialog = this.signResizeDialog;
405
- }
406
-
407
- if (e.type === 'keydown') {
408
- if (e.which === 27) { // escape
409
- // hide the popup menu
410
- $windowPopup.hide('fast', function() {
411
- // also reset the Boolean
412
- thisObj.windowMenuClickRegistered = false;
413
- // also restore menu items to their original state
414
- $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
415
- // also return focus to window options button
416
- $windowButton.focus();
417
- });
418
- return false;
419
- }
420
- else {
421
- // all other keys will be handled by upstream functions
422
- return false;
423
- }
424
- }
425
-
426
- // hide the popup menu
427
- $windowPopup.hide('fast', function() {
428
- // also reset the boolean
429
- thisObj.windowMenuClickRegistered = false;
430
- // also restore menu items to their original state
431
- $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
432
- });
433
- if (choice !== 'close') {
434
- $windowButton.focus();
435
- }
436
-
437
- if (choice === 'move') {
438
- if (!this.showedAlert(which)) {
439
- this.showAlert(this.tt.windowMoveAlert,which);
440
- if (which === 'transcript') {
441
- this.showedTranscriptAlert = true;
442
- }
443
- else if (which === 'sign') {
444
- this.showedSignAlert = true;
445
- }
446
- }
447
- if (e.type === 'keydown') {
448
- this.dragDevice = 'keyboard';
449
- }
450
- else {
451
- this.dragDevice = 'mouse';
452
- }
453
- this.startDrag(which, $window);
454
- $windowPopup.hide().parent().focus();
455
- }
456
- else if (choice == 'resize') {
457
- // resize through the menu uses a form, not drag
458
- resizeDialog.show();
459
- }
460
- else if (choice == 'close') {
461
- // close window, place focus on corresponding button on controller bar
462
- if (which === 'transcript') {
463
- this.handleTranscriptToggle();
464
- }
465
- else if (which === 'sign') {
466
- this.handleSignToggle();
467
- }
468
- }
469
- };
470
-
471
- AblePlayer.prototype.startDrag = function(which, $element) {
472
- var thisObj, $windowPopup, zIndex, startPos, newX, newY;
473
- thisObj = this;
474
-
475
- this.$activeWindow = $element;
476
- this.dragging = true;
477
-
478
- if (which === 'transcript') {
479
- $windowPopup = this.$transcriptPopup;
480
- }
481
- else if (which === 'sign') {
482
- $windowPopup = this.$signPopup;
483
- }
484
-
485
- if (!this.showedAlert(which)) {
486
- this.showAlert(this.tt.windowMoveAlert,which);
487
- if (which === 'transcript') {
488
- this.showedTranscriptAlert = true;
489
- }
490
- else if (which === 'sign') {
491
- this.showedSignAlert = true;
492
- }
493
- }
494
-
495
- // if window's popup menu is open, close it
496
- if ($windowPopup.is(':visible')) {
497
- $windowPopup.hide();
498
- }
499
-
500
- // be sure this window is on top
501
- this.updateZIndex(which);
502
-
503
- // get starting position of element
504
- startPos = this.$activeWindow.position();
505
- this.dragStartX = startPos.left;
506
- this.dragStartY = startPos.top;
507
-
508
- if (typeof this.startMouseX === 'undefined') {
509
- this.dragDevice = 'keyboard';
510
- this.dragKeyX = this.dragStartX;
511
- this.dragKeyY = this.dragStartY;
512
- // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd()
513
- this.startingDrag = true;
514
- }
515
- else {
516
- this.dragDevice = 'mouse';
517
- // get offset between mouse position and top left corner of draggable element
518
- this.dragOffsetX = this.startMouseX - this.dragStartX;
519
- this.dragOffsetY = this.startMouseY - this.dragStartY;
520
- }
521
-
522
- // prepare element for dragging
523
- this.$activeWindow.addClass('able-drag').css({
524
- 'position': 'absolute',
525
- 'top': this.dragStartY + 'px',
526
- 'left': this.dragStartX + 'px'
527
- }).focus();
528
-
529
- // add device-specific event listeners
530
- if (this.dragDevice === 'mouse') {
531
- $(document).on('mousemove',function(e) {
532
- if (thisObj.dragging) {
533
- // calculate new top left based on current mouse position - offset
534
- newX = e.pageX - thisObj.dragOffsetX;
535
- newY = e.pageY - thisObj.dragOffsetY;
536
- thisObj.resetDraggedObject( newX, newY );
537
- }
538
- });
539
- }
540
- else if (this.dragDevice === 'keyboard') {
541
- this.$activeWindow.on('keydown',function(e) {
542
- if (thisObj.dragging) {
543
- thisObj.dragKeys(which, e);
544
- }
545
- });
546
- }
547
- return false;
548
- };
549
-
550
- AblePlayer.prototype.dragKeys = function(which, e) {
551
-
552
- var key, keySpeed;
553
-
554
- var thisObj = this;
555
-
556
- // stopgap to prevent firing on initial Enter or space
557
- // that selected "Move" from menu
558
- if (this.startingDrag) {
559
- this.startingDrag = false;
560
- return false;
561
- }
562
- key = e.which;
563
- keySpeed = 10; // pixels per keypress event
564
-
565
- switch (key) {
566
- case 37: // left
567
- case 63234:
568
- this.dragKeyX -= keySpeed;
569
- break;
570
- case 38: // up
571
- case 63232:
3
+ AblePlayer.prototype.initDragDrop = function ( which ) {
4
+
5
+ // supported values of which: 'sign', 'transcript'
6
+
7
+ // NOTE: "Drag and Drop" for Able Player is a metaphor only!!!
8
+ // HTML5 Drag & Drop API enables moving elements to new locations in the DOM
9
+ // Thats not our purpose; we're simply changing the visible position on-screen
10
+ // Therefore, the drag & drop interface was overhauled in v2.3.41 to simple
11
+ // use mouse (and keyboard) events to change CSS positioning properties
12
+
13
+ // There are nevertheless lessons to be learned from Drag & Drop about accessibility:
14
+ // http://dev.opera.com/articles/accessible-drag-and-drop/
15
+
16
+ var thisObj, $window, $toolbar, windowName, $resizeHandle, resizeZIndex;
17
+
18
+ thisObj = this;
19
+
20
+ if (which === 'transcript') {
21
+ $window = this.$transcriptArea;
22
+ windowName = 'transcript-window';
23
+ $toolbar = this.$transcriptToolbar;
24
+ }
25
+ else if (which === 'sign') {
26
+ $window = this.$signWindow;
27
+ windowName = 'sign-window';
28
+ $toolbar = this.$signToolbar;
29
+ }
30
+
31
+ // add class to trigger change in cursor on hover
32
+ $toolbar.addClass('able-draggable');
33
+
34
+ // add resize handle selector to bottom right corner
35
+ $resizeHandle = $('<div>',{
36
+ 'class': 'able-resizable'
37
+ });
38
+ // assign z-index that's slightly higher than parent window
39
+ resizeZIndex = parseInt($window.css('z-index')) + 100;
40
+ $resizeHandle.css('z-index',resizeZIndex);
41
+ $window.append($resizeHandle);
42
+
43
+ // add event listener to toolbar to start and end drag
44
+ // other event listeners will be added when drag starts
45
+ $toolbar.on('mousedown', function(e) {
46
+ e.stopPropagation();
47
+ if (!thisObj.windowMenuClickRegistered) {
48
+ thisObj.windowMenuClickRegistered = true;
49
+ thisObj.startMouseX = e.pageX;
50
+ thisObj.startMouseY = e.pageY;
51
+ thisObj.dragDevice = 'mouse';
52
+ thisObj.startDrag(which, $window);
53
+ }
54
+ return false;
55
+ });
56
+ $toolbar.on('mouseup', function(e) {
57
+ e.stopPropagation();
58
+ if (thisObj.dragging && thisObj.dragDevice === 'mouse') {
59
+ thisObj.endDrag(which);
60
+ }
61
+ return false;
62
+ });
63
+
64
+ // add event listeners for resizing
65
+ $resizeHandle.on('mousedown', function(e) {
66
+
67
+ e.stopPropagation();
68
+ if (!thisObj.windowMenuClickRegistered) {
69
+ thisObj.windowMenuClickRegistered = true;
70
+ thisObj.startMouseX = e.pageX;
71
+ thisObj.startMouseY = e.pageY;
72
+ thisObj.startResize(which, $window);
73
+ return false;
74
+ }
75
+ });
76
+
77
+ $resizeHandle.on('mouseup', function(e) {
78
+ e.stopPropagation();
79
+ if (thisObj.resizing) {
80
+ thisObj.endResize(which);
81
+ }
82
+ return false;
83
+ });
84
+
85
+ // whenever a window is clicked, bring it to the foreground
86
+ $window.on('click', function() {
87
+
88
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
89
+ thisObj.updateZIndex(which);
90
+ }
91
+ thisObj.finishingDrag = false;
92
+ });
93
+
94
+ this.addWindowMenu(which,$window,windowName);
95
+ };
96
+
97
+ AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) {
98
+
99
+
100
+ var thisObj, $windowAlert, menuId, $newButton, $buttonIcon, buttonImgSrc, $buttonImg,
101
+ $buttonLabel, tooltipId, $tooltip, $popup,
102
+ label, position, buttonHeight, buttonWidth, tooltipY, tooltipX, tooltipStyle, tooltip,
103
+ $optionList, menuBaseId, options, i, $optionItem, option, menuId;
104
+
105
+ thisObj = this;
106
+
107
+ // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked
108
+ // This will prevent the click event from also triggering a mousedown event on the toolbar
109
+ // (which would unexpectedly send the window into drag mode)
110
+ this.windowMenuClickRegistered = false;
111
+
112
+ // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag
113
+ // this will prevent the click event from being triggered
114
+ this.finishingDrag = false;
115
+
116
+ // create an alert div and add it to window
117
+ $windowAlert = $('<div role="alert"></div>');
118
+ $windowAlert.addClass('able-alert');
119
+ $windowAlert.hide();
120
+ $windowAlert.appendTo(this.$activeWindow);
121
+ $windowAlert.css({
122
+ top: $window.offset().top
123
+ });
124
+
125
+ // add button to draggable window which triggers a popup menu
126
+ // for now, re-use preferences icon for this purpose
127
+ menuId = this.mediaId + '-' + windowName + '-menu';
128
+ $newButton = $('<button>',{
129
+ 'type': 'button',
130
+ 'tabindex': '0',
131
+ 'aria-label': this.tt.windowButtonLabel,
132
+ 'aria-haspopup': 'true',
133
+ 'aria-controls': menuId,
134
+ 'class': 'able-button-handler-preferences'
135
+ });
136
+ if (this.iconType === 'font') {
137
+ $buttonIcon = $('<span>',{
138
+ 'class': 'icon-preferences',
139
+ 'aria-hidden': 'true'
140
+ });
141
+ $newButton.append($buttonIcon);
142
+ }
143
+ else {
144
+ // use image
145
+ buttonImgSrc = this.rootPath + 'button-icons/' + this.toolbarIconColor + '/preferences.png';
146
+ $buttonImg = $('<img>',{
147
+ 'src': buttonImgSrc,
148
+ 'alt': '',
149
+ 'role': 'presentation'
150
+ });
151
+ $newButton.append($buttonImg);
152
+ }
153
+
154
+ // add the visibly-hidden label for screen readers that don't support aria-label on the button
155
+ $buttonLabel = $('<span>',{
156
+ 'class': 'able-clipped'
157
+ }).text(this.tt.windowButtonLabel);
158
+ $newButton.append($buttonLabel);
159
+
160
+ // add a tooltip that displays aria-label on mouseenter or focus
161
+ tooltipId = this.mediaId + '-' + windowName + '-tooltip';
162
+ $tooltip = $('<div>',{
163
+ 'class' : 'able-tooltip',
164
+ 'id' : tooltipId
165
+ }).hide();
166
+ $newButton.on('mouseenter focus',function(e) {
167
+ var label = $(this).attr('aria-label');
168
+ // get position of this button
169
+ var position = $(this).position();
170
+ var buttonHeight = $(this).height();
171
+ var buttonWidth = $(this).width();
172
+ var tooltipY = position.top - buttonHeight - 5;
173
+ var tooltipX = 0;
174
+ var tooltipStyle = {
175
+ left: '',
176
+ right: tooltipX + 'px',
177
+ top: tooltipY + 'px'
178
+ };
179
+ var tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(label).css(tooltipStyle);
180
+ thisObj.showTooltip(tooltip);
181
+ $(this).on('mouseleave blur',function() {
182
+ AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide();
183
+ });
184
+ });
185
+
186
+ // setup popup menu
187
+ $popup = this.setupPopups(windowName); // 'transcript-window' or 'sign-window'
188
+ // define vars and assemble all the parts
189
+ if (which === 'transcript') {
190
+ this.$transcriptAlert = $windowAlert;
191
+ this.$transcriptPopupButton = $newButton;
192
+ this.$transcriptPopup = $popup;
193
+ this.$transcriptToolbar.append($windowAlert,$newButton,$tooltip,$popup);
194
+ }
195
+ else if (which === 'sign') {
196
+ this.$signAlert = $windowAlert;
197
+ this.$signPopupButton = $newButton;
198
+ this.$signPopup = $popup;
199
+ this.$signToolbar.append($windowAlert,$newButton,$tooltip,$popup);
200
+ }
201
+
202
+ // handle button click
203
+ $newButton.on('click mousedown keydown',function(e) {
204
+ e.stopPropagation();
205
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
206
+ // don't set windowMenuClickRegistered yet; that happens in handler function
207
+ thisObj.handleWindowButtonClick(which, e);
208
+ }
209
+ thisObj.finishingDrag = false;
210
+ });
211
+
212
+ this.addResizeDialog(which, $window);
213
+ };
214
+
215
+ AblePlayer.prototype.addResizeDialog = function (which, $window) {
216
+
217
+ var thisObj, $windowPopup, $windowButton,
218
+ widthId, heightId, startingWidth, startingHeight, aspectRatio,
219
+ $resizeForm, $resizeWrapper,
220
+ $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel,
221
+ $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel,
222
+ tempWidth, tempHeight,
223
+ $saveButton, $cancelButton, newWidth, newHeight, resizeDialog;
224
+
225
+ thisObj = this;
226
+
227
+ if (which === 'transcript') {
228
+ $windowPopup = this.$transcriptPopup;
229
+ $windowButton = this.$transcriptPopupButton;
230
+ }
231
+ else if (which === 'sign') {
232
+ $windowPopup = this.$signPopup;
233
+ $windowButton = this.$signPopupButton;
234
+ }
235
+
236
+ widthId = this.mediaId + '-resize-' + which + '-width';
237
+ heightId = this.mediaId + '-resize-' + which + '-height';
238
+ startingWidth = $window.width();
239
+ startingHeight = $window.height();
240
+ aspectRatio = startingWidth / startingHeight;
241
+
242
+ $resizeForm = $('<div></div>',{
243
+ 'class' : 'able-resize-form'
244
+ });
245
+
246
+ // inner container for all content, will be assigned to modal div's aria-describedby
247
+ $resizeWrapper = $('<div></div>');
248
+
249
+ // width field
250
+ $resizeWidthDiv = $('<div></div>');
251
+ $resizeWidthInput = $('<input>',{
252
+ 'type': 'text',
253
+ 'id': widthId,
254
+ 'value': startingWidth
255
+ });
256
+ $resizeWidthLabel = $('<label>',{
257
+ 'for': widthId
258
+ }).text(this.tt.width);
259
+
260
+ // height field
261
+ $resizeHeightDiv = $('<div></div>');
262
+ $resizeHeightInput = $('<input>',{
263
+ 'type': 'text',
264
+ 'id': heightId,
265
+ 'value': startingHeight
266
+ });
267
+ $resizeHeightLabel = $('<label>',{
268
+ 'for': heightId
269
+ }).text(this.tt.height);
270
+
271
+ if (which === 'sign') {
272
+ // make height a read-only field
273
+ // and calculate its value based on width to preserve aspect ratio
274
+ $resizeHeightInput.prop('readonly',true);
275
+ $resizeWidthInput.on('input',function() {
276
+ tempWidth = $(this).val();
277
+ tempHeight = Math.round(tempWidth/aspectRatio, 0);
278
+ $resizeHeightInput.val(tempHeight);
279
+ })
280
+ }
281
+
282
+ // Add save and cancel buttons.
283
+ $saveButton = $('<button class="modal-button">' + this.tt.save + '</button>');
284
+ $cancelButton = $('<button class="modal-button">' + this.tt.cancel + '</button>');
285
+ $saveButton.on('click',function () {
286
+ newWidth = $('#' + widthId).val();
287
+ newHeight = $('#' + heightId).val();
288
+ if (newWidth !== startingWidth || newHeight !== startingHeight) {
289
+ thisObj.resizeObject(which,newWidth,newHeight);
290
+ thisObj.updateCookie(which);
291
+ }
292
+ resizeDialog.hide();
293
+ $windowPopup.hide();
294
+ $windowButton.focus();
295
+ });
296
+ $cancelButton.on('click',function () {
297
+ resizeDialog.hide();
298
+ $windowPopup.hide();
299
+ $windowButton.focus();
300
+ });
301
+
302
+ // Now assemble all the parts
303
+ $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput);
304
+ $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput);
305
+ $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv);
306
+ $resizeForm.append($resizeWrapper,'<hr>',$saveButton,$cancelButton);
307
+
308
+ // must be appended to the BODY!
309
+ // otherwise when aria-hidden="true" is applied to all background content
310
+ // that will include an ancestor of the dialog,
311
+ // which will render the dialog unreadable by screen readers
312
+ $('body').append($resizeForm);
313
+ resizeDialog = new AccessibleDialog($resizeForm, $windowButton, 'alert', this.tt.windowResizeHeading, $resizeWrapper, this.tt.closeButtonLabel, '20em');
314
+ if (which === 'transcript') {
315
+ this.transcriptResizeDialog = resizeDialog;
316
+ }
317
+ else if (which === 'sign') {
318
+ this.signResizeDialog = resizeDialog;
319
+ }
320
+ };
321
+
322
+ AblePlayer.prototype.handleWindowButtonClick = function (which, e) {
323
+
324
+ var thisObj, $windowPopup, $windowButton, $toolbar, popupTop;
325
+
326
+ thisObj = this;
327
+
328
+ if (which === 'transcript') {
329
+ $windowPopup = this.$transcriptPopup;
330
+ $windowButton = this.$transcriptPopupButton;
331
+ $toolbar = this.$transcriptToolbar;
332
+ }
333
+ else if (which === 'sign') {
334
+ $windowPopup = this.$signPopup;
335
+ $windowButton = this.$signPopupButton;
336
+ $toolbar = this.$signToolbar;
337
+ }
338
+
339
+ if (e.type === 'keydown') {
340
+ // user pressed a key
341
+ if (e.which === 32 || e.which === 13) {
342
+ // this was Enter or space
343
+ this.windowMenuClickRegistered = true;
344
+ }
345
+ else if (e.which === 27) { // escape
346
+ // hide the popup menu
347
+ $windowPopup.hide('fast', function() {
348
+ // also reset the Boolean
349
+ thisObj.windowMenuClickRegistered = false;
350
+ // also restore menu items to their original state
351
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
352
+ // also return focus to window options button
353
+ $windowButton.focus();
354
+ });
355
+ }
356
+ else {
357
+ return false;
358
+ }
359
+ }
360
+ else {
361
+ // this was a mouse event
362
+ this.windowMenuClickRegistered = true;
363
+ }
364
+
365
+ if ($windowPopup.is(':visible')) {
366
+ $windowPopup.hide(200,'',function() {
367
+ thisObj.windowMenuClickRegistered = false; // reset
368
+ });
369
+ $windowPopup.find('li').removeClass('able-focus');
370
+ $windowButton.attr('aria-expanded','false').focus();
371
+ }
372
+ else {
373
+ // first, be sure window is on top
374
+ this.updateZIndex(which);
375
+ popupTop = $windowButton.position().top + $windowButton.outerHeight();
376
+ $windowPopup.css('top', popupTop);
377
+ $windowPopup.show(200,'',function() {
378
+ $windowButton.attr('aria-expanded','true');
379
+ $(this).find('li').first().focus().addClass('able-focus');
380
+ thisObj.windowMenuClickRegistered = false; // reset
381
+ });
382
+ }
383
+ };
384
+
385
+ AblePlayer.prototype.handleMenuChoice = function (which, choice, e) {
386
+
387
+ var thisObj, $window, $windowPopup, $windowButton, resizeDialog, $thisRadio;
388
+
389
+ thisObj = this;
390
+
391
+ if (which === 'transcript') {
392
+ $window = this.$transcriptArea;
393
+ $windowPopup = this.$transcriptPopup;
394
+ $windowButton = this.$transcriptPopupButton;
395
+ resizeDialog = this.transcriptResizeDialog;
396
+ }
397
+ else if (which === 'sign') {
398
+ $window = this.$signWindow;
399
+ $windowPopup = this.$signPopup;
400
+ $windowButton = this.$signPopupButton;
401
+ resizeDialog = this.signResizeDialog;
402
+ }
403
+
404
+ if (e.type === 'keydown') {
405
+ if (e.which === 27) { // escape
406
+ // hide the popup menu
407
+ $windowPopup.hide('fast', function() {
408
+ // also reset the Boolean
409
+ thisObj.windowMenuClickRegistered = false;
410
+ // also restore menu items to their original state
411
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
412
+ // also return focus to window options button
413
+ $windowButton.focus();
414
+ });
415
+ return false;
416
+ }
417
+ else {
418
+ // all other keys will be handled by upstream functions
419
+ return false;
420
+ }
421
+ }
422
+
423
+ // hide the popup menu
424
+ $windowPopup.hide('fast', function() {
425
+ // also reset the boolean
426
+ thisObj.windowMenuClickRegistered = false;
427
+ // also restore menu items to their original state
428
+ $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1');
429
+ });
430
+ if (choice !== 'close') {
431
+ $windowButton.focus();
432
+ }
433
+
434
+ if (choice === 'move') {
435
+ if (!this.showedAlert(which)) {
436
+ this.showAlert(this.tt.windowMoveAlert,which);
437
+ if (which === 'transcript') {
438
+ this.showedTranscriptAlert = true;
439
+ }
440
+ else if (which === 'sign') {
441
+ this.showedSignAlert = true;
442
+ }
443
+ }
444
+ if (e.type === 'keydown') {
445
+ this.dragDevice = 'keyboard';
446
+ }
447
+ else {
448
+ this.dragDevice = 'mouse';
449
+ }
450
+ this.startDrag(which, $window);
451
+ $windowPopup.hide().parent().focus();
452
+ }
453
+ else if (choice == 'resize') {
454
+ // resize through the menu uses a form, not drag
455
+ resizeDialog.show();
456
+ }
457
+ else if (choice == 'close') {
458
+ // close window, place focus on corresponding button on controller bar
459
+ if (which === 'transcript') {
460
+ this.handleTranscriptToggle();
461
+ }
462
+ else if (which === 'sign') {
463
+ this.handleSignToggle();
464
+ }
465
+ }
466
+ };
467
+
468
+ AblePlayer.prototype.startDrag = function(which, $element) {
469
+ var thisObj, $windowPopup, zIndex, startPos, newX, newY;
470
+ thisObj = this;
471
+
472
+ this.$activeWindow = $element;
473
+ this.dragging = true;
474
+
475
+ if (which === 'transcript') {
476
+ $windowPopup = this.$transcriptPopup;
477
+ }
478
+ else if (which === 'sign') {
479
+ $windowPopup = this.$signPopup;
480
+ }
481
+
482
+ if (!this.showedAlert(which)) {
483
+ this.showAlert(this.tt.windowMoveAlert,which);
484
+ if (which === 'transcript') {
485
+ this.showedTranscriptAlert = true;
486
+ }
487
+ else if (which === 'sign') {
488
+ this.showedSignAlert = true;
489
+ }
490
+ }
491
+
492
+ // if window's popup menu is open, close it
493
+ if ($windowPopup.is(':visible')) {
494
+ $windowPopup.hide();
495
+ }
496
+
497
+ // be sure this window is on top
498
+ this.updateZIndex(which);
499
+
500
+ // get starting position of element
501
+ startPos = this.$activeWindow.position();
502
+ this.dragStartX = startPos.left;
503
+ this.dragStartY = startPos.top;
504
+
505
+ if (typeof this.startMouseX === 'undefined') {
506
+ this.dragDevice = 'keyboard';
507
+ this.dragKeyX = this.dragStartX;
508
+ this.dragKeyY = this.dragStartY;
509
+ // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd()
510
+ this.startingDrag = true;
511
+ }
512
+ else {
513
+ this.dragDevice = 'mouse';
514
+ // get offset between mouse position and top left corner of draggable element
515
+ this.dragOffsetX = this.startMouseX - this.dragStartX;
516
+ this.dragOffsetY = this.startMouseY - this.dragStartY;
517
+ }
518
+
519
+ // prepare element for dragging
520
+ this.$activeWindow.addClass('able-drag').css({
521
+ 'position': 'absolute',
522
+ 'top': this.dragStartY + 'px',
523
+ 'left': this.dragStartX + 'px'
524
+ }).focus();
525
+
526
+ // add device-specific event listeners
527
+ if (this.dragDevice === 'mouse') {
528
+ $(document).on('mousemove',function(e) {
529
+ if (thisObj.dragging) {
530
+ // calculate new top left based on current mouse position - offset
531
+ newX = e.pageX - thisObj.dragOffsetX;
532
+ newY = e.pageY - thisObj.dragOffsetY;
533
+ thisObj.resetDraggedObject( newX, newY );
534
+ }
535
+ });
536
+ }
537
+ else if (this.dragDevice === 'keyboard') {
538
+ this.$activeWindow.on('keydown',function(e) {
539
+ if (thisObj.dragging) {
540
+ thisObj.dragKeys(which, e);
541
+ }
542
+ });
543
+ }
544
+ return false;
545
+ };
546
+
547
+ AblePlayer.prototype.dragKeys = function(which, e) {
548
+
549
+ var key, keySpeed;
550
+
551
+ var thisObj = this;
552
+
553
+ // stopgap to prevent firing on initial Enter or space
554
+ // that selected "Move" from menu
555
+ if (this.startingDrag) {
556
+ this.startingDrag = false;
557
+ return false;
558
+ }
559
+ key = e.which;
560
+ keySpeed = 10; // pixels per keypress event
561
+
562
+ switch (key) {
563
+ case 37: // left
564
+ case 63234:
565
+ this.dragKeyX -= keySpeed;
566
+ break;
567
+ case 38: // up
568
+ case 63232:
572
569
  this.dragKeyY -= keySpeed;
573
- break;
574
- case 39: // right
575
- case 63235:
570
+ break;
571
+ case 39: // right
572
+ case 63235:
576
573
  this.dragKeyX += keySpeed;
577
- break;
578
- case 40: // down
579
- case 63233:
574
+ break;
575
+ case 40: // down
576
+ case 63233:
580
577
  this.dragKeyY += keySpeed;
581
- break;
582
- case 13: // enter
583
- case 27: // escape
578
+ break;
579
+ case 13: // enter
580
+ case 27: // escape
584
581
  this.endDrag(which);
585
- return false;
586
- default:
587
582
  return false;
583
+ default:
584
+ return false;
585
+ }
586
+ this.resetDraggedObject(this.dragKeyX,this.dragKeyY);
587
+ if (e.preventDefault) {
588
+ e.preventDefault();
589
+ }
590
+ return false;
591
+ };
592
+
593
+ AblePlayer.prototype.resetDraggedObject = function ( x, y) {
594
+ this.$activeWindow.css({
595
+ 'left': x + 'px',
596
+ 'top': y + 'px'
597
+ });
598
+ },
599
+
600
+ AblePlayer.prototype.resizeObject = function ( which, width, height ) {
601
+
602
+ var innerHeight;
603
+
604
+ // which is either 'transcript' or 'sign'
605
+ this.$activeWindow.css({
606
+ 'width': width + 'px',
607
+ 'height': height + 'px'
608
+ });
609
+
610
+ if (which === 'transcript') {
611
+ // $activeWindow is the outer $transcriptArea
612
+ // but the inner able-transcript also needs to be resized proporitionally
613
+ // (it's 50px less than its outer container)
614
+ innerHeight = height - 50;
615
+ this.$transcriptDiv.css('height', innerHeight + 'px');
588
616
  }
589
- this.resetDraggedObject(this.dragKeyX,this.dragKeyY);
590
- if (e.preventDefault) {
591
- e.preventDefault();
592
- }
593
- return false;
594
- };
595
-
596
- AblePlayer.prototype.resetDraggedObject = function ( x, y) {
597
- this.$activeWindow.css({
598
- 'left': x + 'px',
599
- 'top': y + 'px'
600
- });
601
- },
602
-
603
- AblePlayer.prototype.resizeObject = function ( which, width, height ) {
604
-
605
- var innerHeight;
606
-
607
- // which is either 'transcript' or 'sign'
608
- this.$activeWindow.css({
609
- 'width': width + 'px',
610
- 'height': height + 'px'
611
- });
612
-
613
- if (which === 'transcript') {
614
- // $activeWindow is the outer $transcriptArea
615
- // but the inner able-transcript also needs to be resized proporitionally
616
- // (it's 50px less than its outer container)
617
- innerHeight = height - 50;
618
- this.$transcriptDiv.css('height', innerHeight + 'px');
619
- }
620
- };
621
-
622
- AblePlayer.prototype.endDrag = function(which) {
623
-
624
- var $window, $windowPopup, $windowButton;
625
-
626
- if (which === 'transcript') {
627
- $windowPopup = this.$transcriptPopup;
628
- $windowButton = this.$transcriptPopupButton;
629
- }
630
- else if (which === 'sign') {
631
- $windowPopup = this.$signPopup;
632
- $windowButton = this.$signPopupButton;
633
- }
634
-
635
- $(document).off('mousemove mouseup');
636
- this.$activeWindow.off('keydown').removeClass('able-drag');
637
-
638
- if (this.dragDevice === 'keyboard') {
639
- $windowButton.focus();
640
- }
641
- this.dragging = false;
642
-
643
- // save final position of dragged element
644
- this.updateCookie(which);
645
-
646
- // reset starting mouse positions
647
- this.startMouseX = undefined;
648
- this.startMouseY = undefined;
649
-
650
- // Boolean to stop stray events from firing
651
- this.windowMenuClickRegistered = false;
652
- this.finishingDrag = true; // will be reset after window click event
653
-
654
- // finishingDrag should e reset after window click event,
655
- // which is triggered automatically after mouseup
656
- // However, in case that's not reliable in some browsers
657
- // need to ensure this gets cancelled
658
- setTimeout(function() {
659
- this.finishingDrag = false;
660
- }, 100);
661
- };
662
-
663
- AblePlayer.prototype.isCloseToCorner = function($window, mouseX, mouseY) {
664
-
665
- // return true if mouse is close to bottom right corner (resize target)
666
- var tolerance, position, top, left, width, height, bottom, right;
667
-
668
- tolerance = 10; // number of pixels in both directions considered "close enough"
669
-
670
- // first, get position of element
671
- position = $window.offset();
672
- top = position.top;
673
- left = position.left;
674
- width = $window.width();
675
- height = $window.height();
676
- bottom = top + height;
677
- right = left + width;
678
- if ((Math.abs(bottom-mouseY) <= tolerance) && (Math.abs(right-mouseX) <= tolerance)) {
679
- return true;
680
- }
681
- return false;
682
- };
683
-
684
- AblePlayer.prototype.startResize = function(which, $element) {
685
-
686
- var thisObj, $windowPopup, zIndex, startPos, newWidth, newHeight;
687
- thisObj = this;
688
-
689
- this.$activeWindow = $element;
690
- this.resizing = true;
691
-
692
- if (which === 'transcript') {
693
- $windowPopup = this.$transcriptPopup;
694
- }
695
- else if (which === 'sign') {
696
- $windowPopup = this.$signPopup;
697
- }
698
-
699
- // if window's popup menu is open, close it & place focus on button (???)
700
- if ($windowPopup.is(':visible')) {
701
- $windowPopup.hide().parent().focus();
702
- }
703
-
704
- // get starting width and height
705
- startPos = this.$activeWindow.position();
706
- this.dragKeyX = this.dragStartX;
707
- this.dragKeyY = this.dragStartY;
708
- this.dragStartWidth = this.$activeWindow.width();
709
- this.dragStartHeight = this.$activeWindow.height();
710
-
711
- // add event listeners
712
- $(document).on('mousemove',function(e) {
713
- if (thisObj.resizing) {
714
- // calculate new width and height based on changes to mouse position
715
- newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX);
716
- newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY);
717
- thisObj.resizeObject( which, newWidth, newHeight );
718
- }
719
- });
720
- return false;
721
- };
722
-
723
- AblePlayer.prototype.endResize = function(which) {
724
-
725
- var $window, $windowPopup, $windowButton;
726
-
727
- if (which === 'transcript') {
728
- $windowPopup = this.$transcriptPopup;
729
- $windowButton = this.$transcriptPopupButton;
730
- }
731
- else if (which === 'sign') {
732
- $windowPopup = this.$signPopup;
733
- $windowButton = this.$signPopupButton;
734
- }
735
-
736
- $(document).off('mousemove mouseup');
737
- this.$activeWindow.off('keydown');
738
-
739
- $windowButton.show().focus();
740
- this.resizing = false;
741
- this.$activeWindow.removeClass('able-resize');
742
-
743
- // save final width and height of dragged element
744
- this.updateCookie(which);
745
-
746
- // Booleans for preventing stray events
747
- this.windowMenuClickRegistered = false;
748
- this.finishingDrag = true;
749
-
750
- // finishingDrag should e reset after window click event,
751
- // which is triggered automatically after mouseup
752
- // However, in case that's not reliable in some browsers
753
- // need to ensure this gets cancelled
754
- setTimeout(function() {
755
- this.finishingDrag = false;
756
- }, 100);
757
- };
617
+ };
618
+
619
+ AblePlayer.prototype.endDrag = function(which) {
620
+
621
+ var $window, $windowPopup, $windowButton;
622
+
623
+ if (which === 'transcript') {
624
+ $windowPopup = this.$transcriptPopup;
625
+ $windowButton = this.$transcriptPopupButton;
626
+ }
627
+ else if (which === 'sign') {
628
+ $windowPopup = this.$signPopup;
629
+ $windowButton = this.$signPopupButton;
630
+ }
631
+
632
+ $(document).off('mousemove mouseup');
633
+ this.$activeWindow.off('keydown').removeClass('able-drag');
634
+
635
+ if (this.dragDevice === 'keyboard') {
636
+ $windowButton.focus();
637
+ }
638
+ this.dragging = false;
639
+
640
+ // save final position of dragged element
641
+ this.updateCookie(which);
642
+
643
+ // reset starting mouse positions
644
+ this.startMouseX = undefined;
645
+ this.startMouseY = undefined;
646
+
647
+ // Boolean to stop stray events from firing
648
+ this.windowMenuClickRegistered = false;
649
+ this.finishingDrag = true; // will be reset after window click event
650
+
651
+ // finishingDrag should e reset after window click event,
652
+ // which is triggered automatically after mouseup
653
+ // However, in case that's not reliable in some browsers
654
+ // need to ensure this gets cancelled
655
+ setTimeout(function() {
656
+ this.finishingDrag = false;
657
+ }, 100);
658
+ };
659
+
660
+ AblePlayer.prototype.isCloseToCorner = function($window, mouseX, mouseY) {
661
+
662
+ // return true if mouse is close to bottom right corner (resize target)
663
+ var tolerance, position, top, left, width, height, bottom, right;
664
+
665
+ tolerance = 10; // number of pixels in both directions considered "close enough"
666
+
667
+ // first, get position of element
668
+ position = $window.offset();
669
+ top = position.top;
670
+ left = position.left;
671
+ width = $window.width();
672
+ height = $window.height();
673
+ bottom = top + height;
674
+ right = left + width;
675
+ if ((Math.abs(bottom-mouseY) <= tolerance) && (Math.abs(right-mouseX) <= tolerance)) {
676
+ return true;
677
+ }
678
+ return false;
679
+ };
680
+
681
+ AblePlayer.prototype.startResize = function(which, $element) {
682
+
683
+ var thisObj, $windowPopup, zIndex, startPos, newWidth, newHeight;
684
+ thisObj = this;
685
+
686
+ this.$activeWindow = $element;
687
+ this.resizing = true;
688
+
689
+ if (which === 'transcript') {
690
+ $windowPopup = this.$transcriptPopup;
691
+ }
692
+ else if (which === 'sign') {
693
+ $windowPopup = this.$signPopup;
694
+ }
695
+
696
+ // if window's popup menu is open, close it & place focus on button (???)
697
+ if ($windowPopup.is(':visible')) {
698
+ $windowPopup.hide().parent().focus();
699
+ }
700
+
701
+ // get starting width and height
702
+ startPos = this.$activeWindow.position();
703
+ this.dragKeyX = this.dragStartX;
704
+ this.dragKeyY = this.dragStartY;
705
+ this.dragStartWidth = this.$activeWindow.width();
706
+ this.dragStartHeight = this.$activeWindow.height();
707
+
708
+ // add event listeners
709
+ $(document).on('mousemove',function(e) {
710
+ if (thisObj.resizing) {
711
+ // calculate new width and height based on changes to mouse position
712
+ newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX);
713
+ newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY);
714
+ thisObj.resizeObject( which, newWidth, newHeight );
715
+ }
716
+ });
717
+ return false;
718
+ };
719
+
720
+ AblePlayer.prototype.endResize = function(which) {
721
+
722
+ var $window, $windowPopup, $windowButton;
723
+
724
+ if (which === 'transcript') {
725
+ $windowPopup = this.$transcriptPopup;
726
+ $windowButton = this.$transcriptPopupButton;
727
+ }
728
+ else if (which === 'sign') {
729
+ $windowPopup = this.$signPopup;
730
+ $windowButton = this.$signPopupButton;
731
+ }
732
+
733
+ $(document).off('mousemove mouseup');
734
+ this.$activeWindow.off('keydown');
735
+
736
+ $windowButton.show().focus();
737
+ this.resizing = false;
738
+ this.$activeWindow.removeClass('able-resize');
739
+
740
+ // save final width and height of dragged element
741
+ this.updateCookie(which);
742
+
743
+ // Booleans for preventing stray events
744
+ this.windowMenuClickRegistered = false;
745
+ this.finishingDrag = true;
746
+
747
+ // finishingDrag should e reset after window click event,
748
+ // which is triggered automatically after mouseup
749
+ // However, in case that's not reliable in some browsers
750
+ // need to ensure this gets cancelled
751
+ setTimeout(function() {
752
+ this.finishingDrag = false;
753
+ }, 100);
754
+ };
758
755
 
759
756
  })(jQuery);