wai-website-theme 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +52 -0
  4. data/_data/lang.json +730 -0
  5. data/_data/techniques.yml +180 -0
  6. data/_data/wcag.yml +125 -0
  7. data/_includes/.DS_Store +0 -0
  8. data/_includes/body-class.html +1 -0
  9. data/_includes/box.html +10 -0
  10. data/_includes/excol.html +13 -0
  11. data/_includes/footer.html +40 -0
  12. data/_includes/head.html +23 -0
  13. data/_includes/header.html +59 -0
  14. data/_includes/icon.html +6 -0
  15. data/_includes/img.html +17 -0
  16. data/_includes/multilang-list-policy-links.html +29 -0
  17. data/_includes/multilang-list.html +35 -0
  18. data/_includes/multilang-policy-title.html +5 -0
  19. data/_includes/multilang-title-full.html +1 -0
  20. data/_includes/multilang-title.html +1 -0
  21. data/_includes/navlist.html +22 -0
  22. data/_includes/notes.html +2 -0
  23. data/_includes/prevnext.html +34 -0
  24. data/_includes/resources.html +19 -0
  25. data/_includes/sidenav.html +65 -0
  26. data/_includes/sidenote.html +14 -0
  27. data/_includes/toc.html +10 -0
  28. data/_includes/video-player.html +99 -0
  29. data/_layouts/default.html +26 -0
  30. data/_layouts/home.html +14 -0
  31. data/_layouts/news.html +21 -0
  32. data/_layouts/none.html +1 -0
  33. data/_layouts/policy.html +72 -0
  34. data/_layouts/sidenav.html +27 -0
  35. data/_layouts/sidenavsidebar.html +22 -0
  36. data/assets/ableplayer/.gitattributes +14 -0
  37. data/assets/ableplayer/.gitignore +7 -0
  38. data/assets/ableplayer/Gruntfile.js +105 -0
  39. data/assets/ableplayer/LICENSE +26 -0
  40. data/assets/ableplayer/README.md +656 -0
  41. data/assets/ableplayer/build/ableplayer.dist.js +12157 -0
  42. data/assets/ableplayer/build/ableplayer.js +12157 -0
  43. data/assets/ableplayer/build/ableplayer.min.css +2 -0
  44. data/assets/ableplayer/build/ableplayer.min.js +8 -0
  45. data/assets/ableplayer/button-icons/able-icons.svg +116 -0
  46. data/assets/ableplayer/button-icons/black/captions.png +0 -0
  47. data/assets/ableplayer/button-icons/black/chapters.png +0 -0
  48. data/assets/ableplayer/button-icons/black/close.png +0 -0
  49. data/assets/ableplayer/button-icons/black/descriptions.png +0 -0
  50. data/assets/ableplayer/button-icons/black/ellipsis.png +0 -0
  51. data/assets/ableplayer/button-icons/black/faster.png +0 -0
  52. data/assets/ableplayer/button-icons/black/forward.png +0 -0
  53. data/assets/ableplayer/button-icons/black/fullscreen-collapse.png +0 -0
  54. data/assets/ableplayer/button-icons/black/fullscreen-expand.png +0 -0
  55. data/assets/ableplayer/button-icons/black/help.png +0 -0
  56. data/assets/ableplayer/button-icons/black/next.png +0 -0
  57. data/assets/ableplayer/button-icons/black/pause.png +0 -0
  58. data/assets/ableplayer/button-icons/black/pipe.png +0 -0
  59. data/assets/ableplayer/button-icons/black/play.png +0 -0
  60. data/assets/ableplayer/button-icons/black/preferences.png +0 -0
  61. data/assets/ableplayer/button-icons/black/previous.png +0 -0
  62. data/assets/ableplayer/button-icons/black/rabbit.png +0 -0
  63. data/assets/ableplayer/button-icons/black/restart.png +0 -0
  64. data/assets/ableplayer/button-icons/black/rewind.png +0 -0
  65. data/assets/ableplayer/button-icons/black/sign.png +0 -0
  66. data/assets/ableplayer/button-icons/black/slower.png +0 -0
  67. data/assets/ableplayer/button-icons/black/stop.png +0 -0
  68. data/assets/ableplayer/button-icons/black/transcript.png +0 -0
  69. data/assets/ableplayer/button-icons/black/turtle.png +0 -0
  70. data/assets/ableplayer/button-icons/black/volume-loud.png +0 -0
  71. data/assets/ableplayer/button-icons/black/volume-medium.png +0 -0
  72. data/assets/ableplayer/button-icons/black/volume-mute.png +0 -0
  73. data/assets/ableplayer/button-icons/black/volume-soft.png +0 -0
  74. data/assets/ableplayer/button-icons/fonts/able.eot +0 -0
  75. data/assets/ableplayer/button-icons/fonts/able.svg +40 -0
  76. data/assets/ableplayer/button-icons/fonts/able.ttf +0 -0
  77. data/assets/ableplayer/button-icons/fonts/able.woff +0 -0
  78. data/assets/ableplayer/button-icons/white/captions.png +0 -0
  79. data/assets/ableplayer/button-icons/white/chapters.png +0 -0
  80. data/assets/ableplayer/button-icons/white/close.png +0 -0
  81. data/assets/ableplayer/button-icons/white/descriptions.png +0 -0
  82. data/assets/ableplayer/button-icons/white/ellipsis.png +0 -0
  83. data/assets/ableplayer/button-icons/white/faster.png +0 -0
  84. data/assets/ableplayer/button-icons/white/forward.png +0 -0
  85. data/assets/ableplayer/button-icons/white/fullscreen-collapse.png +0 -0
  86. data/assets/ableplayer/button-icons/white/fullscreen-expand.png +0 -0
  87. data/assets/ableplayer/button-icons/white/help.png +0 -0
  88. data/assets/ableplayer/button-icons/white/next.png +0 -0
  89. data/assets/ableplayer/button-icons/white/pause.png +0 -0
  90. data/assets/ableplayer/button-icons/white/pipe.png +0 -0
  91. data/assets/ableplayer/button-icons/white/play.png +0 -0
  92. data/assets/ableplayer/button-icons/white/preferences.png +0 -0
  93. data/assets/ableplayer/button-icons/white/previous.png +0 -0
  94. data/assets/ableplayer/button-icons/white/rabbit.png +0 -0
  95. data/assets/ableplayer/button-icons/white/restart.png +0 -0
  96. data/assets/ableplayer/button-icons/white/rewind.png +0 -0
  97. data/assets/ableplayer/button-icons/white/sign.png +0 -0
  98. data/assets/ableplayer/button-icons/white/slower.png +0 -0
  99. data/assets/ableplayer/button-icons/white/stop.png +0 -0
  100. data/assets/ableplayer/button-icons/white/transcript.png +0 -0
  101. data/assets/ableplayer/button-icons/white/turtle.png +0 -0
  102. data/assets/ableplayer/button-icons/white/volume-loud.png +0 -0
  103. data/assets/ableplayer/button-icons/white/volume-medium.png +0 -0
  104. data/assets/ableplayer/button-icons/white/volume-mute.png +0 -0
  105. data/assets/ableplayer/button-icons/white/volume-soft.png +0 -0
  106. data/assets/ableplayer/images/wingrip.png +0 -0
  107. data/assets/ableplayer/package.json +22 -0
  108. data/assets/ableplayer/scripts/JQuery.doWhen.js +113 -0
  109. data/assets/ableplayer/scripts/ableplayer-base.js +440 -0
  110. data/assets/ableplayer/scripts/browser.js +162 -0
  111. data/assets/ableplayer/scripts/buildplayer.js +1609 -0
  112. data/assets/ableplayer/scripts/caption.js +385 -0
  113. data/assets/ableplayer/scripts/chapters.js +242 -0
  114. data/assets/ableplayer/scripts/control.js +1514 -0
  115. data/assets/ableplayer/scripts/description.js +283 -0
  116. data/assets/ableplayer/scripts/dialog.js +147 -0
  117. data/assets/ableplayer/scripts/dragdrop.js +766 -0
  118. data/assets/ableplayer/scripts/event.js +595 -0
  119. data/assets/ableplayer/scripts/initialize.js +725 -0
  120. data/assets/ableplayer/scripts/langs.js +750 -0
  121. data/assets/ableplayer/scripts/metadata.js +134 -0
  122. data/assets/ableplayer/scripts/misc.js +72 -0
  123. data/assets/ableplayer/scripts/preference.js +909 -0
  124. data/assets/ableplayer/scripts/search.js +171 -0
  125. data/assets/ableplayer/scripts/sign.js +92 -0
  126. data/assets/ableplayer/scripts/slider.js +454 -0
  127. data/assets/ableplayer/scripts/track.js +296 -0
  128. data/assets/ableplayer/scripts/transcript.js +590 -0
  129. data/assets/ableplayer/scripts/translation.js +66 -0
  130. data/assets/ableplayer/scripts/volume.js +383 -0
  131. data/assets/ableplayer/scripts/webvtt.js +765 -0
  132. data/assets/ableplayer/scripts/youtube.js +471 -0
  133. data/assets/ableplayer/styles/ableplayer.css +1241 -0
  134. data/assets/ableplayer/thirdparty/js.cookie.js +145 -0
  135. data/assets/ableplayer/thirdparty/modernizr.custom.js +4 -0
  136. data/assets/ableplayer/translations/ca.js +1 -0
  137. data/assets/ableplayer/translations/de.js +1 -0
  138. data/assets/ableplayer/translations/en.js +305 -0
  139. data/assets/ableplayer/translations/es.js +305 -0
  140. data/assets/ableplayer/translations/fr.js +305 -0
  141. data/assets/ableplayer/translations/it.js +303 -0
  142. data/assets/ableplayer/translations/ja.js +305 -0
  143. data/assets/ableplayer/translations/nl.js +305 -0
  144. data/assets/css/style.css +4360 -0
  145. data/assets/css/style.css.map +1 -0
  146. data/assets/fonts/anonymouspro-bold.woff +0 -0
  147. data/assets/fonts/anonymouspro-bold.woff2 +0 -0
  148. data/assets/fonts/anonymouspro-bolditalic.woff +0 -0
  149. data/assets/fonts/anonymouspro-bolditalic.woff2 +0 -0
  150. data/assets/fonts/anonymouspro-italic.woff +0 -0
  151. data/assets/fonts/anonymouspro-italic.woff2 +0 -0
  152. data/assets/fonts/anonymouspro-regular.woff +0 -0
  153. data/assets/fonts/anonymouspro-regular.woff2 +0 -0
  154. data/assets/fonts/notosans-bold.woff +0 -0
  155. data/assets/fonts/notosans-bold.woff2 +0 -0
  156. data/assets/fonts/notosans-bolditalic.woff +0 -0
  157. data/assets/fonts/notosans-bolditalic.woff2 +0 -0
  158. data/assets/fonts/notosans-italic.woff +0 -0
  159. data/assets/fonts/notosans-italic.woff2 +0 -0
  160. data/assets/fonts/notosans-regular.woff +0 -0
  161. data/assets/fonts/notosans-regular.woff2 +0 -0
  162. data/assets/images/.DS_Store +0 -0
  163. data/assets/images/Shape.svg +10 -0
  164. data/assets/images/icon-related-content.svg +14 -0
  165. data/assets/images/icons.svg +126 -0
  166. data/assets/images/teaser-image@1x.jpg +0 -0
  167. data/assets/images/teaser-image@2x.jpg +0 -0
  168. data/assets/images/w3c.sketch +0 -0
  169. data/assets/images/w3c.svg +10 -0
  170. data/assets/scripts/jquery.min.js +4 -0
  171. data/assets/scripts/main.js +208 -0
  172. data/assets/scripts/svg4everybody.js +1 -0
  173. metadata +257 -0
@@ -0,0 +1,766 @@
1
+ (function ($) {
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(event) {
46
+ event.stopPropagation();
47
+ if (!thisObj.windowMenuClickRegistered) {
48
+ thisObj.windowMenuClickRegistered = true;
49
+ thisObj.startMouseX = event.pageX;
50
+ thisObj.startMouseY = event.pageY;
51
+ thisObj.dragDevice = 'mouse';
52
+ thisObj.startDrag(which, $window);
53
+ }
54
+ return false;
55
+ });
56
+ $toolbar.on('mouseup', function(event) {
57
+ event.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(event) {
66
+ event.stopPropagation();
67
+ if (!thisObj.windowMenuClickRegistered) {
68
+ thisObj.windowMenuClickRegistered = true;
69
+ thisObj.startMouseX = event.pageX;
70
+ thisObj.startMouseY = event.pageY;
71
+ thisObj.startResize(which, $window);
72
+ return false;
73
+ }
74
+ });
75
+ $resizeHandle.on('mouseup', function(event) {
76
+ event.stopPropagation();
77
+ if (thisObj.resizing) {
78
+ thisObj.endResize(which);
79
+ }
80
+ return false;
81
+ });
82
+
83
+ // whenever a window is clicked, bring it to the foreground
84
+ $window.on('click', function() {
85
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
86
+ thisObj.updateZIndex(which);
87
+ }
88
+ thisObj.finishingDrag = false;
89
+ });
90
+
91
+ this.addWindowMenu(which,$window,windowName);
92
+ };
93
+
94
+ AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) {
95
+
96
+
97
+ var thisObj, $windowAlert, $newButton, $buttonIcon, buttonImgSrc, $buttonImg,
98
+ $buttonLabel, tooltipId, $tooltip, $popup,
99
+ label, position, buttonHeight, buttonWidth, tooltipY, tooltipX, tooltipStyle, tooltip,
100
+ $optionList, radioName, options, i, $optionItem, option,
101
+ radioId, $radioButton, $radioLabel;
102
+
103
+ thisObj = this;
104
+
105
+ // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked
106
+ // This will prevent the click event from also triggering a mousedown event on the toolbar
107
+ // (which would unexpectedly send the window into drag mode)
108
+ this.windowMenuClickRegistered = false;
109
+
110
+ // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag
111
+ // this will prevent the click event from being triggered
112
+ this.finishingDrag = false;
113
+
114
+ // create an alert div and add it to window
115
+ $windowAlert = $('<div role="alert"></div>');
116
+ $windowAlert.addClass('able-alert');
117
+ $windowAlert.appendTo(this.$activeWindow);
118
+ $windowAlert.css({
119
+ top: $window.offset().top
120
+ });
121
+
122
+ // add button to draggable window which triggers a popup menu
123
+ // for now, re-use preferences icon for this purpose
124
+ $newButton = $('<button>',{
125
+ 'type': 'button',
126
+ 'tabindex': '0',
127
+ 'aria-label': this.tt.windowButtonLabel,
128
+ 'class': 'able-button-handler-preferences'
129
+ });
130
+ if (this.iconType === 'font') {
131
+ $buttonIcon = $('<span>',{
132
+ 'class': 'icon-preferences',
133
+ 'aria-hidden': 'true'
134
+ });
135
+ $newButton.append($buttonIcon);
136
+ }
137
+ else {
138
+ // use image
139
+ buttonImgSrc = this.rootPath + 'button-icons/' + this.toolbarIconColor + '/preferences.png';
140
+ $buttonImg = $('<img>',{
141
+ 'src': buttonImgSrc,
142
+ 'alt': '',
143
+ 'role': 'presentation'
144
+ });
145
+ $newButton.append($buttonImg);
146
+ }
147
+
148
+ // add the visibly-hidden label for screen readers that don't support aria-label on the button
149
+ $buttonLabel = $('<span>',{
150
+ 'class': 'able-clipped'
151
+ }).text(this.tt.windowButtonLabel);
152
+ $newButton.append($buttonLabel);
153
+
154
+ // add a tooltip that displays aria-label on mouseenter or focus
155
+ tooltipId = this.mediaId + '-' + windowName + '-tooltip';
156
+ $tooltip = $('<div>',{
157
+ 'class' : 'able-tooltip',
158
+ 'id' : tooltipId
159
+ });
160
+ $newButton.on('mouseenter focus',function(event) {
161
+ var label = $(this).attr('aria-label');
162
+ // get position of this button
163
+ var position = $(this).position();
164
+ var buttonHeight = $(this).height();
165
+ var buttonWidth = $(this).width();
166
+ var tooltipY = position.top - buttonHeight - 5;
167
+ var tooltipX = 0;
168
+ var tooltipStyle = {
169
+ left: '',
170
+ right: tooltipX + 'px',
171
+ top: tooltipY + 'px'
172
+ };
173
+ var tooltip = $('#' + tooltipId).text(label).css(tooltipStyle);
174
+ thisObj.showTooltip(tooltip);
175
+ $(this).on('mouseleave blur',function() {
176
+ $('#' + tooltipId).text('').hide();
177
+ });
178
+ });
179
+
180
+ // add a popup menu
181
+ $popup = this.createPopup(windowName);
182
+ $optionList = $('<ul></ul>');
183
+ radioName = this.mediaId + '-' + windowName + '-choice';
184
+
185
+ options = [];
186
+ options.push({
187
+ 'name': 'move',
188
+ 'label': this.tt.windowMove
189
+ });
190
+ options.push({
191
+ 'name': 'resize',
192
+ 'label': this.tt.windowResize
193
+ });
194
+ for (i = 0; i < options.length; i++) {
195
+ $optionItem = $('<li></li>');
196
+ option = options[i];
197
+ radioId = radioName + '-' + i;
198
+ $radioButton = $('<input>',{
199
+ 'type': 'radio',
200
+ 'val': option.name,
201
+ 'name': radioName,
202
+ 'id': radioId
203
+ });
204
+ $radioLabel = $('<label>',{
205
+ 'for': radioId
206
+ });
207
+ $radioLabel.text(option.label);
208
+ $radioButton.on('focus',function(e) {
209
+ $(this).parents('ul').children('li').removeClass('able-focus');
210
+ $(this).parent('li').addClass('able-focus');
211
+ });
212
+ $radioButton.on('click',function(e) {
213
+ e.stopPropagation();
214
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
215
+ thisObj.windowMenuClickRegistered = true;
216
+ thisObj.handleMenuChoice( which, $(this).val(), e.type);
217
+ }
218
+ });
219
+ // due to an apparent bug (in jquery?) clicking the label
220
+ // does not result in a click event on the associated radio button
221
+ // Observed this in Firefox 45.0.2 and Chrome 50
222
+ // It works fine on a simple test page so this could be an Able Player bug
223
+ // Added the following as a workaround rather than mess with isolating the bug
224
+ $radioLabel.on('click mousedown', function() {
225
+ var clickedId = $(this).attr('for');
226
+ $('#' + clickedId).click();
227
+ })
228
+ $optionItem.append($radioButton,$radioLabel);
229
+ $optionList.append($optionItem);
230
+ }
231
+ $popup.append($optionList);
232
+ $newButton.on('click mousedown keydown',function(e) {
233
+ e.stopPropagation();
234
+ if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) {
235
+ // don't set windowMenuClickRegistered yet; that happens in handler function
236
+ thisObj.handleWindowButtonClick(which, e);
237
+ }
238
+ thisObj.finishingDrag = false;
239
+ });
240
+
241
+ $popup.on('keydown', function(event) {
242
+ // Escape key
243
+ if (event.which === 27) {
244
+ // Close Window Options Menu
245
+ $newButton.focus();
246
+ $popup.hide();
247
+ }
248
+ });
249
+
250
+ // define vars and assemble all the parts
251
+ if (which === 'transcript') {
252
+ this.$transcriptAlert = $windowAlert;
253
+ this.$transcriptPopupButton = $newButton;
254
+ this.$transcriptPopup = $popup;
255
+ this.$transcriptToolbar.append($windowAlert,$newButton,$tooltip,$popup);
256
+ }
257
+ else if (which === 'sign') {
258
+ this.$signAlert = $windowAlert;
259
+ this.$signPopupButton = $newButton;
260
+ this.$signPopup = $popup;
261
+ this.$signToolbar.append($windowAlert,$newButton,$tooltip,$popup);
262
+ }
263
+
264
+ this.addResizeDialog(which, $window);
265
+ };
266
+
267
+ AblePlayer.prototype.addResizeDialog = function (which, $window) {
268
+
269
+ var thisObj, $windowPopup, $windowButton,
270
+ widthId, heightId, startingWidth, startingHeight, aspectRatio,
271
+ $resizeForm, $resizeWrapper,
272
+ $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel,
273
+ $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel,
274
+ tempWidth, tempHeight,
275
+ $saveButton, $cancelButton, newWidth, newHeight, resizeDialog;
276
+
277
+ thisObj = this;
278
+
279
+ if (which === 'transcript') {
280
+ $windowPopup = this.$transcriptPopup;
281
+ $windowButton = this.$transcriptPopupButton;
282
+ }
283
+ else if (which === 'sign') {
284
+ $windowPopup = this.$signPopup;
285
+ $windowButton = this.$signPopupButton;
286
+ }
287
+
288
+ widthId = this.mediaId + '-resize-' + which + '-width';
289
+ heightId = this.mediaId + '-resize-' + which + '-height';
290
+ startingWidth = $window.width();
291
+ startingHeight = $window.height();
292
+ aspectRatio = startingWidth / startingHeight;
293
+
294
+ $resizeForm = $('<div></div>',{
295
+ 'class' : 'able-resize-form'
296
+ });
297
+
298
+ // inner container for all content, will be assigned to modal div's aria-describedby
299
+ $resizeWrapper = $('<div></div>');
300
+
301
+ // width field
302
+ $resizeWidthDiv = $('<div></div>');
303
+ $resizeWidthInput = $('<input>',{
304
+ 'type': 'text',
305
+ 'id': widthId,
306
+ 'value': startingWidth
307
+ });
308
+ $resizeWidthLabel = $('<label>',{
309
+ 'for': widthId
310
+ }).text(this.tt.width);
311
+
312
+ // height field
313
+ $resizeHeightDiv = $('<div></div>');
314
+ $resizeHeightInput = $('<input>',{
315
+ 'type': 'text',
316
+ 'id': heightId,
317
+ 'value': startingHeight
318
+ });
319
+ $resizeHeightLabel = $('<label>',{
320
+ 'for': heightId
321
+ }).text(this.tt.height);
322
+
323
+ if (which === 'sign') {
324
+ // make height a read-only field
325
+ // and calculate its value based on width to preserve aspect ratio
326
+ $resizeHeightInput.prop('readonly',true);
327
+ $resizeWidthInput.on('input',function() {
328
+ tempWidth = $(this).val();
329
+ tempHeight = Math.round(tempWidth/aspectRatio, 0);
330
+ $resizeHeightInput.val(tempHeight);
331
+ })
332
+ }
333
+
334
+ // Add save and cancel buttons.
335
+ $saveButton = $('<button class="modal-button">' + this.tt.save + '</button>');
336
+ $cancelButton = $('<button class="modal-button">' + this.tt.cancel + '</button>');
337
+ $saveButton.on('click',function () {
338
+ newWidth = $('#' + widthId).val();
339
+ newHeight = $('#' + heightId).val();
340
+ if (newWidth !== startingWidth || newHeight !== startingHeight) {
341
+ $window.css({
342
+ 'width': newWidth + 'px',
343
+ 'height': newHeight + 'px'
344
+ });
345
+ thisObj.updateCookie(which);
346
+ }
347
+ resizeDialog.hide();
348
+ $windowPopup.hide();
349
+ $windowButton.focus();
350
+ });
351
+ $cancelButton.on('click',function () {
352
+ resizeDialog.hide();
353
+ $windowPopup.hide();
354
+ $windowButton.focus();
355
+ });
356
+
357
+ // Now assemble all the parts
358
+ $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput);
359
+ $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput);
360
+ $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv);
361
+ $resizeForm.append($resizeWrapper,'<hr>',$saveButton,$cancelButton);
362
+
363
+ // must be appended to the BODY!
364
+ // otherwise when aria-hidden="true" is applied to all background content
365
+ // that will include an ancestor of the dialog,
366
+ // which will render the dialog unreadable by screen readers
367
+ $('body').append($resizeForm);
368
+ resizeDialog = new AccessibleDialog($resizeForm, $windowButton, 'alert', this.tt.windowResizeHeading, $resizeWrapper, this.tt.closeButtonLabel, '20em');
369
+ if (which === 'transcript') {
370
+ this.transcriptResizeDialog = resizeDialog;
371
+ }
372
+ else if (which === 'sign') {
373
+ this.signResizeDialog = resizeDialog;
374
+ }
375
+ };
376
+
377
+ AblePlayer.prototype.handleWindowButtonClick = function (which, e) {
378
+
379
+ var thisObj, $windowPopup, $windowButton, $toolbar, popupTop;
380
+
381
+ thisObj = this;
382
+
383
+ if (e.type === 'keydown') {
384
+ // user pressed a key
385
+ if (e.which === 32 || e.which === 13 || e.which === 27) {
386
+ // this was Enter, space, or escape
387
+ this.windowMenuClickRegistered = true;
388
+ }
389
+ else {
390
+ return false;
391
+ }
392
+ }
393
+ else {
394
+ // this was a mouse event
395
+ this.windowMenuClickRegistered = true;
396
+ }
397
+ if (which === 'transcript') {
398
+ $windowPopup = this.$transcriptPopup;
399
+ $windowButton = this.$transcriptPopupButton;
400
+ $toolbar = this.$transcriptToolbar;
401
+ }
402
+ else if (which === 'sign') {
403
+ $windowPopup = this.$signPopup;
404
+ $windowButton = this.$signPopupButton;
405
+ $toolbar = this.$signToolbar;
406
+ }
407
+
408
+ if ($windowPopup.is(':visible')) {
409
+ $windowPopup.hide(200,'',function() {
410
+ thisObj.windowMenuClickRegistered = false; // reset
411
+ });
412
+ $windowPopup.find('li').removeClass('able-focus');
413
+ $windowButton.focus();
414
+ }
415
+ else {
416
+ // first, be sure window is on top
417
+ this.updateZIndex(which);
418
+ popupTop = $windowButton.position().top + $windowButton.outerHeight();
419
+ $windowPopup.css('top', popupTop);
420
+ $windowPopup.show(200,'',function() {
421
+ $(this).find('input').first().focus().parent().addClass('able-focus');
422
+ thisObj.windowMenuClickRegistered = false; // reset
423
+ });
424
+ }
425
+ };
426
+
427
+ AblePlayer.prototype.handleMenuChoice = function (which, choice, eventType) {
428
+
429
+ var thisObj, $window, $windowPopup, $windowButton, resizeDialog, $thisRadio;
430
+
431
+ thisObj = this;
432
+
433
+ if (which === 'transcript') {
434
+ $window = this.$transcriptArea;
435
+ $windowPopup = this.$transcriptPopup;
436
+ $windowButton = this.$transcriptPopupButton;
437
+ resizeDialog = this.transcriptResizeDialog;
438
+ }
439
+ else if (which === 'sign') {
440
+ $window = this.$signWindow;
441
+ $windowPopup = this.$signPopup;
442
+ $windowButton = this.$signPopupButton;
443
+ resizeDialog = this.signResizeDialog;
444
+ }
445
+
446
+ // hide the popup menu, and reset the Boolean
447
+ $windowPopup.hide('fast', function() {
448
+ thisObj.windowMenuClickRegistered = false; // reset
449
+ });
450
+ $windowButton.focus();
451
+
452
+ if (choice === 'move') {
453
+ if (!this.showedAlert(which)) {
454
+ this.showAlert(this.tt.windowMoveAlert,which);
455
+ if (which === 'transcript') {
456
+ this.showedTranscriptAlert = true;
457
+ }
458
+ else if (which === 'sign') {
459
+ this.showedSignAlert = true;
460
+ }
461
+ }
462
+ if (eventType === 'keydown') {
463
+ this.dragDevice = 'keyboard';
464
+ }
465
+ else {
466
+ this.dragDevice = 'mouse';
467
+ }
468
+ this.startDrag(which, $window);
469
+ $windowPopup.hide().parent().focus();
470
+ }
471
+ else if (choice == 'resize') {
472
+ // resize through the menu uses a form, not drag
473
+ resizeDialog.show();
474
+ }
475
+ };
476
+
477
+ AblePlayer.prototype.startDrag = function(which, $element) {
478
+
479
+ var thisObj, $windowPopup, zIndex, startPos, newX, newY;
480
+ thisObj = this;
481
+
482
+ this.$activeWindow = $element;
483
+ this.dragging = true;
484
+
485
+ if (which === 'transcript') {
486
+ $windowPopup = this.$transcriptPopup;
487
+ }
488
+ else if (which === 'sign') {
489
+ $windowPopup = this.$signPopup;
490
+ }
491
+
492
+ if (!this.showedAlert(which)) {
493
+ this.showAlert(this.tt.windowMoveAlert,which);
494
+ if (which === 'transcript') {
495
+ this.showedTranscriptAlert = true;
496
+ }
497
+ else if (which === 'sign') {
498
+ this.showedSignAlert = true;
499
+ }
500
+ }
501
+
502
+ // if window's popup menu is open, close it
503
+ if ($windowPopup.is(':visible')) {
504
+ $windowPopup.hide();
505
+ }
506
+
507
+ // be sure this window is on top
508
+ this.updateZIndex(which);
509
+
510
+ // get starting position of element
511
+ startPos = this.$activeWindow.position();
512
+ this.dragStartX = startPos.left;
513
+ this.dragStartY = startPos.top;
514
+
515
+ if (typeof this.startMouseX === 'undefined') {
516
+ this.dragDevice = 'keyboard';
517
+ this.dragKeyX = this.dragStartX;
518
+ this.dragKeyY = this.dragStartY;
519
+ // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd()
520
+ this.startingDrag = true;
521
+ }
522
+ else {
523
+ this.dragDevice = 'mouse';
524
+ // get offset between mouse position and top left corner of draggable element
525
+ this.dragOffsetX = this.startMouseX - this.dragStartX;
526
+ this.dragOffsetY = this.startMouseY - this.dragStartY;
527
+ }
528
+
529
+ // prepare element for dragging
530
+ this.$activeWindow.addClass('able-drag').css({
531
+ 'position': 'absolute',
532
+ 'top': this.dragStartY + 'px',
533
+ 'left': this.dragStartX + 'px'
534
+ }).focus();
535
+
536
+ // add device-specific event listeners
537
+ if (this.dragDevice === 'mouse') {
538
+ $(document).on('mousemove',function(e) {
539
+ if (thisObj.dragging) {
540
+ // calculate new top left based on current mouse position - offset
541
+ newX = e.pageX - thisObj.dragOffsetX;
542
+ newY = e.pageY - thisObj.dragOffsetY;
543
+ thisObj.resetDraggedObject( newX, newY );
544
+ }
545
+ });
546
+ }
547
+ else if (this.dragDevice === 'keyboard') {
548
+ this.$activeWindow.on('keydown',function(e) {
549
+ if (thisObj.dragging) {
550
+ thisObj.dragKeys(which, e);
551
+ }
552
+ });
553
+ }
554
+ return false;
555
+ };
556
+
557
+ AblePlayer.prototype.dragKeys = function(which, e) {
558
+
559
+ var key, keySpeed;
560
+
561
+ var thisObj = this;
562
+
563
+ // stopgap to prevent firing on initial Enter or space
564
+ // that selected "Move" from menu
565
+ if (this.startingDrag) {
566
+ this.startingDrag = false;
567
+ return false;
568
+ }
569
+ key = e.which;
570
+ keySpeed = 10; // pixels per keypress event
571
+
572
+ switch (key) {
573
+ case 37: // left
574
+ case 63234:
575
+ this.dragKeyX -= keySpeed;
576
+ break;
577
+ case 38: // up
578
+ case 63232:
579
+ this.dragKeyY -= keySpeed;
580
+ break;
581
+ case 39: // right
582
+ case 63235:
583
+ this.dragKeyX += keySpeed;
584
+ break;
585
+ case 40: // down
586
+ case 63233:
587
+ this.dragKeyY += keySpeed;
588
+ break;
589
+ case 13: // enter
590
+ case 27: // escape
591
+ this.endDrag(which);
592
+ return false;
593
+ default:
594
+ return false;
595
+ }
596
+ this.resetDraggedObject(this.dragKeyX,this.dragKeyY);
597
+ if (e.preventDefault) {
598
+ e.preventDefault();
599
+ }
600
+ return false;
601
+ };
602
+
603
+ AblePlayer.prototype.resetDraggedObject = function ( x, y) {
604
+ this.$activeWindow.css({
605
+ 'left': x + 'px',
606
+ 'top': y + 'px'
607
+ });
608
+ },
609
+
610
+ AblePlayer.prototype.resizeObject = function ( which, width, height ) {
611
+
612
+ var innerHeight;
613
+
614
+ // which is either 'transcript' or 'sign'
615
+ this.$activeWindow.css({
616
+ 'width': width + 'px',
617
+ 'height': height + 'px'
618
+ });
619
+
620
+ if (which === 'transcript') {
621
+ // $activeWindow is the outer $transcriptArea
622
+ // but the inner able-transcript also needs to be resized proporitionally
623
+ // (it's 50px less than its outer container)
624
+ innerHeight = height - 50;
625
+ this.$transcriptDiv.css('height', innerHeight + 'px');
626
+ }
627
+ };
628
+
629
+ AblePlayer.prototype.endDrag = function(which) {
630
+
631
+ var $window, $windowPopup, $windowButton;
632
+
633
+ if (which === 'transcript') {
634
+ $windowPopup = this.$transcriptPopup;
635
+ $windowButton = this.$transcriptPopupButton;
636
+ }
637
+ else if (which === 'sign') {
638
+ $windowPopup = this.$signPopup;
639
+ $windowButton = this.$signPopupButton;
640
+ }
641
+
642
+ $(document).off('mousemove mouseup');
643
+ this.$activeWindow.off('keydown').removeClass('able-drag');
644
+
645
+ if (this.dragDevice === 'keyboard') {
646
+ $windowButton.focus();
647
+ }
648
+ this.dragging = false;
649
+
650
+ // save final position of dragged element
651
+ this.updateCookie(which);
652
+
653
+ // reset starting mouse positions
654
+ this.startMouseX = undefined;
655
+ this.startMouseY = undefined;
656
+
657
+ // Boolean to stop stray events from firing
658
+ this.windowMenuClickRegistered = false;
659
+ this.finishingDrag = true; // will be reset after window click event
660
+
661
+ // finishingDrag should e reset after window click event,
662
+ // which is triggered automatically after mouseup
663
+ // However, in case that's not reliable in some browsers
664
+ // need to ensure this gets cancelled
665
+ setTimeout(function() {
666
+ this.finishingDrag = false;
667
+ }, 100);
668
+ };
669
+
670
+ AblePlayer.prototype.isCloseToCorner = function($window, mouseX, mouseY) {
671
+
672
+ // return true if mouse is close to bottom right corner (resize target)
673
+ var tolerance, position, top, left, width, height, bottom, right;
674
+
675
+ tolerance = 10; // number of pixels in both directions considered "close enough"
676
+
677
+ // first, get position of element
678
+ position = $window.offset();
679
+ top = position.top;
680
+ left = position.left;
681
+ width = $window.width();
682
+ height = $window.height();
683
+ bottom = top + height;
684
+ right = left + width;
685
+ if ((Math.abs(bottom-mouseY) <= tolerance) && (Math.abs(right-mouseX) <= tolerance)) {
686
+ return true;
687
+ }
688
+ return false;
689
+ };
690
+
691
+ AblePlayer.prototype.startResize = function(which, $element) {
692
+
693
+ var thisObj, $windowPopup, zIndex, startPos, newWidth, newHeight;
694
+ thisObj = this;
695
+
696
+ this.$activeWindow = $element;
697
+ this.resizing = true;
698
+
699
+ if (which === 'transcript') {
700
+ $windowPopup = this.$transcriptPopup;
701
+ }
702
+ else if (which === 'sign') {
703
+ $windowPopup = this.$signPopup;
704
+ }
705
+
706
+ // if window's popup menu is open, close it & place focus on button (???)
707
+ if ($windowPopup.is(':visible')) {
708
+ $windowPopup.hide().parent().focus();
709
+ }
710
+
711
+ // get starting width and height
712
+ startPos = this.$activeWindow.position();
713
+ this.dragKeyX = this.dragStartX;
714
+ this.dragKeyY = this.dragStartY;
715
+ this.dragStartWidth = this.$activeWindow.width();
716
+ this.dragStartHeight = this.$activeWindow.height();
717
+
718
+ // add event listeners
719
+ $(document).on('mousemove',function(e) {
720
+ if (thisObj.resizing) {
721
+ // calculate new width and height based on changes to mouse position
722
+ newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX);
723
+ newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY);
724
+ thisObj.resizeObject( which, newWidth, newHeight );
725
+ }
726
+ });
727
+ return false;
728
+ };
729
+
730
+ AblePlayer.prototype.endResize = function(which) {
731
+
732
+ var $window, $windowPopup, $windowButton;
733
+
734
+ if (which === 'transcript') {
735
+ $windowPopup = this.$transcriptPopup;
736
+ $windowButton = this.$transcriptPopupButton;
737
+ }
738
+ else if (which === 'sign') {
739
+ $windowPopup = this.$signPopup;
740
+ $windowButton = this.$signPopupButton;
741
+ }
742
+
743
+ $(document).off('mousemove mouseup');
744
+ this.$activeWindow.off('keydown');
745
+
746
+ $windowButton.show().focus();
747
+ this.resizing = false;
748
+ this.$activeWindow.removeClass('able-resize');
749
+
750
+ // save final width and height of dragged element
751
+ this.updateCookie(which);
752
+
753
+ // Booleans for preventing stray events
754
+ this.windowMenuClickRegistered = false;
755
+ this.finishingDrag = true;
756
+
757
+ // finishingDrag should e reset after window click event,
758
+ // which is triggered automatically after mouseup
759
+ // However, in case that's not reliable in some browsers
760
+ // need to ensure this gets cancelled
761
+ setTimeout(function() {
762
+ this.finishingDrag = false;
763
+ }, 100);
764
+ };
765
+
766
+ })(jQuery);