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.
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);