assets/ableplayer/scripts/dragdrop.js in wai-website-theme-1.3.1 vs assets/ableplayer/scripts/dragdrop.js in wai-website-theme-1.4

- old
+ new

@@ -1,759 +1,756 @@ (function ($) { - AblePlayer.prototype.initDragDrop = function ( which ) { + AblePlayer.prototype.initDragDrop = function ( which ) { - // supported values of which: 'sign', 'transcript' + // supported values of which: 'sign', 'transcript' - // NOTE: "Drag and Drop" for Able Player is a metaphor only!!! - // HTML5 Drag & Drop API enables moving elements to new locations in the DOM - // Thats not our purpose; we're simply changing the visible position on-screen - // Therefore, the drag & drop interface was overhauled in v2.3.41 to simple - // use mouse (and keyboard) events to change CSS positioning properties + // NOTE: "Drag and Drop" for Able Player is a metaphor only!!! + // HTML5 Drag & Drop API enables moving elements to new locations in the DOM + // Thats not our purpose; we're simply changing the visible position on-screen + // Therefore, the drag & drop interface was overhauled in v2.3.41 to simple + // use mouse (and keyboard) events to change CSS positioning properties - // There are nevertheless lessons to be learned from Drag & Drop about accessibility: - // http://dev.opera.com/articles/accessible-drag-and-drop/ + // There are nevertheless lessons to be learned from Drag & Drop about accessibility: + // http://dev.opera.com/articles/accessible-drag-and-drop/ - var thisObj, $window, $toolbar, windowName, $resizeHandle, resizeZIndex; + var thisObj, $window, $toolbar, windowName, $resizeHandle, resizeZIndex; - thisObj = this; + thisObj = this; - if (which === 'transcript') { - $window = this.$transcriptArea; - windowName = 'transcript-window'; - $toolbar = this.$transcriptToolbar; - } - else if (which === 'sign') { - $window = this.$signWindow; - windowName = 'sign-window'; - $toolbar = this.$signToolbar; - } + if (which === 'transcript') { + $window = this.$transcriptArea; + windowName = 'transcript-window'; + $toolbar = this.$transcriptToolbar; + } + else if (which === 'sign') { + $window = this.$signWindow; + windowName = 'sign-window'; + $toolbar = this.$signToolbar; + } - // add class to trigger change in cursor on hover - $toolbar.addClass('able-draggable'); + // add class to trigger change in cursor on hover + $toolbar.addClass('able-draggable'); - // add resize handle selector to bottom right corner - $resizeHandle = $('<div>',{ - 'class': 'able-resizable' - }); - // assign z-index that's slightly higher than parent window - resizeZIndex = parseInt($window.css('z-index')) + 100; - $resizeHandle.css('z-index',resizeZIndex); - $window.append($resizeHandle); + // add resize handle selector to bottom right corner + $resizeHandle = $('<div>',{ + 'class': 'able-resizable' + }); + // assign z-index that's slightly higher than parent window + resizeZIndex = parseInt($window.css('z-index')) + 100; + $resizeHandle.css('z-index',resizeZIndex); + $window.append($resizeHandle); - // add event listener to toolbar to start and end drag - // other event listeners will be added when drag starts - $toolbar.on('mousedown', function(e) { - e.stopPropagation(); - if (!thisObj.windowMenuClickRegistered) { - thisObj.windowMenuClickRegistered = true; - thisObj.startMouseX = e.pageX; - thisObj.startMouseY = e.pageY; - thisObj.dragDevice = 'mouse'; - thisObj.startDrag(which, $window); - } - return false; - }); - $toolbar.on('mouseup', function(e) { - e.stopPropagation(); - if (thisObj.dragging && thisObj.dragDevice === 'mouse') { - thisObj.endDrag(which); - } - return false; - }); + // add event listener to toolbar to start and end drag + // other event listeners will be added when drag starts + $toolbar.on('mousedown', function(e) { + e.stopPropagation(); + if (!thisObj.windowMenuClickRegistered) { + thisObj.windowMenuClickRegistered = true; + thisObj.startMouseX = e.pageX; + thisObj.startMouseY = e.pageY; + thisObj.dragDevice = 'mouse'; + thisObj.startDrag(which, $window); + } + return false; + }); + $toolbar.on('mouseup', function(e) { + e.stopPropagation(); + if (thisObj.dragging && thisObj.dragDevice === 'mouse') { + thisObj.endDrag(which); + } + return false; + }); - // add event listeners for resizing - $resizeHandle.on('mousedown', function(e) { + // add event listeners for resizing + $resizeHandle.on('mousedown', function(e) { - e.stopPropagation(); - if (!thisObj.windowMenuClickRegistered) { - thisObj.windowMenuClickRegistered = true; - thisObj.startMouseX = e.pageX; - thisObj.startMouseY = e.pageY; - thisObj.startResize(which, $window); - return false; - } - }); + e.stopPropagation(); + if (!thisObj.windowMenuClickRegistered) { + thisObj.windowMenuClickRegistered = true; + thisObj.startMouseX = e.pageX; + thisObj.startMouseY = e.pageY; + thisObj.startResize(which, $window); + return false; + } + }); - $resizeHandle.on('mouseup', function(e) { - e.stopPropagation(); - if (thisObj.resizing) { - thisObj.endResize(which); - } - return false; - }); + $resizeHandle.on('mouseup', function(e) { + e.stopPropagation(); + if (thisObj.resizing) { + thisObj.endResize(which); + } + return false; + }); - // whenever a window is clicked, bring it to the foreground - $window.on('click', function() { + // whenever a window is clicked, bring it to the foreground + $window.on('click', function() { - if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) { - thisObj.updateZIndex(which); - } - thisObj.finishingDrag = false; - }); + if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) { + thisObj.updateZIndex(which); + } + thisObj.finishingDrag = false; + }); - this.addWindowMenu(which,$window,windowName); - }; + this.addWindowMenu(which,$window,windowName); + }; - AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) { + AblePlayer.prototype.addWindowMenu = function(which, $window, windowName) { - var thisObj, $windowAlert, menuId, $newButton, $buttonIcon, buttonImgSrc, $buttonImg, - $buttonLabel, tooltipId, $tooltip, $popup, - label, position, buttonHeight, buttonWidth, tooltipY, tooltipX, tooltipStyle, tooltip, - $optionList, menuBaseId, options, i, $optionItem, option, menuId; + var thisObj, $windowAlert, menuId, $newButton, $buttonIcon, buttonImgSrc, $buttonImg, + $buttonLabel, tooltipId, $tooltip, $popup, + label, position, buttonHeight, buttonWidth, tooltipY, tooltipX, tooltipStyle, tooltip, + $optionList, menuBaseId, options, i, $optionItem, option, menuId; - thisObj = this; + thisObj = this; - // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked - // This will prevent the click event from also triggering a mousedown event on the toolbar - // (which would unexpectedly send the window into drag mode) - this.windowMenuClickRegistered = false; + // Add a Boolean that will be set to true temporarily if window button or a menu item is clicked + // This will prevent the click event from also triggering a mousedown event on the toolbar + // (which would unexpectedly send the window into drag mode) + this.windowMenuClickRegistered = false; - // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag - // this will prevent the click event from being triggered - this.finishingDrag = false; + // Add another Boolean that will be set to true temporarily when mouseup fires at the end of a drag + // this will prevent the click event from being triggered + this.finishingDrag = false; - // create an alert div and add it to window - $windowAlert = $('<div role="alert"></div>'); - $windowAlert.addClass('able-alert'); - $windowAlert.hide(); - $windowAlert.appendTo(this.$activeWindow); - $windowAlert.css({ - top: $window.offset().top - }); + // create an alert div and add it to window + $windowAlert = $('<div role="alert"></div>'); + $windowAlert.addClass('able-alert'); + $windowAlert.hide(); + $windowAlert.appendTo(this.$activeWindow); + $windowAlert.css({ + top: $window.offset().top + }); - // add button to draggable window which triggers a popup menu - // for now, re-use preferences icon for this purpose - menuId = this.mediaId + '-' + windowName + '-menu'; - $newButton = $('<button>',{ - 'type': 'button', - 'tabindex': '0', - 'aria-label': this.tt.windowButtonLabel, - 'aria-haspopup': 'true', - 'aria-controls': menuId, - 'class': 'able-button-handler-preferences' - }); - if (this.iconType === 'font') { - $buttonIcon = $('<span>',{ - 'class': 'icon-preferences', - 'aria-hidden': 'true' - }); - $newButton.append($buttonIcon); - } - else { - // use image - buttonImgSrc = this.rootPath + 'button-icons/' + this.toolbarIconColor + '/preferences.png'; - $buttonImg = $('<img>',{ - 'src': buttonImgSrc, - 'alt': '', - 'role': 'presentation' - }); - $newButton.append($buttonImg); - } + // add button to draggable window which triggers a popup menu + // for now, re-use preferences icon for this purpose + menuId = this.mediaId + '-' + windowName + '-menu'; + $newButton = $('<button>',{ + 'type': 'button', + 'tabindex': '0', + 'aria-label': this.tt.windowButtonLabel, + 'aria-haspopup': 'true', + 'aria-controls': menuId, + 'class': 'able-button-handler-preferences' + }); + if (this.iconType === 'font') { + $buttonIcon = $('<span>',{ + 'class': 'icon-preferences', + 'aria-hidden': 'true' + }); + $newButton.append($buttonIcon); + } + else { + // use image + buttonImgSrc = this.rootPath + 'button-icons/' + this.toolbarIconColor + '/preferences.png'; + $buttonImg = $('<img>',{ + 'src': buttonImgSrc, + 'alt': '', + 'role': 'presentation' + }); + $newButton.append($buttonImg); + } - // add the visibly-hidden label for screen readers that don't support aria-label on the button - $buttonLabel = $('<span>',{ - 'class': 'able-clipped' - }).text(this.tt.windowButtonLabel); - $newButton.append($buttonLabel); + // add the visibly-hidden label for screen readers that don't support aria-label on the button + $buttonLabel = $('<span>',{ + 'class': 'able-clipped' + }).text(this.tt.windowButtonLabel); + $newButton.append($buttonLabel); - // add a tooltip that displays aria-label on mouseenter or focus - tooltipId = this.mediaId + '-' + windowName + '-tooltip'; - $tooltip = $('<div>',{ - 'class' : 'able-tooltip', - 'id' : tooltipId - }).hide(); - $newButton.on('mouseenter focus',function(e) { - var label = $(this).attr('aria-label'); - // get position of this button - var position = $(this).position(); - var buttonHeight = $(this).height(); - var buttonWidth = $(this).width(); - var tooltipY = position.top - buttonHeight - 5; - var tooltipX = 0; - var tooltipStyle = { - left: '', - right: tooltipX + 'px', - top: tooltipY + 'px' - }; - var tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(label).css(tooltipStyle); - thisObj.showTooltip(tooltip); - $(this).on('mouseleave blur',function() { - AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide(); - }); - }); + // add a tooltip that displays aria-label on mouseenter or focus + tooltipId = this.mediaId + '-' + windowName + '-tooltip'; + $tooltip = $('<div>',{ + 'class' : 'able-tooltip', + 'id' : tooltipId + }).hide(); + $newButton.on('mouseenter focus',function(e) { + var label = $(this).attr('aria-label'); + // get position of this button + var position = $(this).position(); + var buttonHeight = $(this).height(); + var buttonWidth = $(this).width(); + var tooltipY = position.top - buttonHeight - 5; + var tooltipX = 0; + var tooltipStyle = { + left: '', + right: tooltipX + 'px', + top: tooltipY + 'px' + }; + var tooltip = AblePlayer.localGetElementById($newButton[0], tooltipId).text(label).css(tooltipStyle); + thisObj.showTooltip(tooltip); + $(this).on('mouseleave blur',function() { + AblePlayer.localGetElementById($newButton[0], tooltipId).text('').hide(); + }); + }); - // setup popup menu - $popup = this.setupPopups(windowName); // 'transcript-window' or 'sign-window' - // define vars and assemble all the parts - if (which === 'transcript') { - this.$transcriptAlert = $windowAlert; - this.$transcriptPopupButton = $newButton; - this.$transcriptPopup = $popup; - this.$transcriptToolbar.append($windowAlert,$newButton,$tooltip,$popup); - } - else if (which === 'sign') { - this.$signAlert = $windowAlert; - this.$signPopupButton = $newButton; - this.$signPopup = $popup; - this.$signToolbar.append($windowAlert,$newButton,$tooltip,$popup); - } + // setup popup menu + $popup = this.setupPopups(windowName); // 'transcript-window' or 'sign-window' + // define vars and assemble all the parts + if (which === 'transcript') { + this.$transcriptAlert = $windowAlert; + this.$transcriptPopupButton = $newButton; + this.$transcriptPopup = $popup; + this.$transcriptToolbar.append($windowAlert,$newButton,$tooltip,$popup); + } + else if (which === 'sign') { + this.$signAlert = $windowAlert; + this.$signPopupButton = $newButton; + this.$signPopup = $popup; + this.$signToolbar.append($windowAlert,$newButton,$tooltip,$popup); + } - // handle button click - $newButton.on('click mousedown keydown',function(e) { - e.stopPropagation(); - if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) { - // don't set windowMenuClickRegistered yet; that happens in handler function - thisObj.handleWindowButtonClick(which, e); - } - thisObj.finishingDrag = false; - }); + // handle button click + $newButton.on('click mousedown keydown',function(e) { + e.stopPropagation(); + if (!thisObj.windowMenuClickRegistered && !thisObj.finishingDrag) { + // don't set windowMenuClickRegistered yet; that happens in handler function + thisObj.handleWindowButtonClick(which, e); + } + thisObj.finishingDrag = false; + }); - this.addResizeDialog(which, $window); - }; + this.addResizeDialog(which, $window); + }; - AblePlayer.prototype.addResizeDialog = function (which, $window) { + AblePlayer.prototype.addResizeDialog = function (which, $window) { - var thisObj, $windowPopup, $windowButton, - widthId, heightId, startingWidth, startingHeight, aspectRatio, - $resizeForm, $resizeWrapper, - $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel, - $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel, - tempWidth, tempHeight, - $saveButton, $cancelButton, newWidth, newHeight, resizeDialog; + var thisObj, $windowPopup, $windowButton, + widthId, heightId, startingWidth, startingHeight, aspectRatio, + $resizeForm, $resizeWrapper, + $resizeWidthDiv, $resizeWidthInput, $resizeWidthLabel, + $resizeHeightDiv, $resizeHeightInput, $resizeHeightLabel, + tempWidth, tempHeight, + $saveButton, $cancelButton, newWidth, newHeight, resizeDialog; - thisObj = this; + thisObj = this; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - $windowButton = this.$transcriptPopupButton; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - $windowButton = this.$signPopupButton; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + $windowButton = this.$transcriptPopupButton; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + $windowButton = this.$signPopupButton; + } - widthId = this.mediaId + '-resize-' + which + '-width'; - heightId = this.mediaId + '-resize-' + which + '-height'; - startingWidth = $window.width(); - startingHeight = $window.height(); - aspectRatio = startingWidth / startingHeight; + widthId = this.mediaId + '-resize-' + which + '-width'; + heightId = this.mediaId + '-resize-' + which + '-height'; + startingWidth = $window.width(); + startingHeight = $window.height(); + aspectRatio = startingWidth / startingHeight; - $resizeForm = $('<div></div>',{ - 'class' : 'able-resize-form' - }); + $resizeForm = $('<div></div>',{ + 'class' : 'able-resize-form' + }); - // inner container for all content, will be assigned to modal div's aria-describedby - $resizeWrapper = $('<div></div>'); + // inner container for all content, will be assigned to modal div's aria-describedby + $resizeWrapper = $('<div></div>'); - // width field - $resizeWidthDiv = $('<div></div>'); - $resizeWidthInput = $('<input>',{ - 'type': 'text', - 'id': widthId, - 'value': startingWidth - }); - $resizeWidthLabel = $('<label>',{ - 'for': widthId - }).text(this.tt.width); + // width field + $resizeWidthDiv = $('<div></div>'); + $resizeWidthInput = $('<input>',{ + 'type': 'text', + 'id': widthId, + 'value': startingWidth + }); + $resizeWidthLabel = $('<label>',{ + 'for': widthId + }).text(this.tt.width); - // height field - $resizeHeightDiv = $('<div></div>'); - $resizeHeightInput = $('<input>',{ - 'type': 'text', - 'id': heightId, - 'value': startingHeight - }); - $resizeHeightLabel = $('<label>',{ - 'for': heightId - }).text(this.tt.height); + // height field + $resizeHeightDiv = $('<div></div>'); + $resizeHeightInput = $('<input>',{ + 'type': 'text', + 'id': heightId, + 'value': startingHeight + }); + $resizeHeightLabel = $('<label>',{ + 'for': heightId + }).text(this.tt.height); - if (which === 'sign') { - // make height a read-only field - // and calculate its value based on width to preserve aspect ratio - $resizeHeightInput.prop('readonly',true); - $resizeWidthInput.on('input',function() { - tempWidth = $(this).val(); - tempHeight = Math.round(tempWidth/aspectRatio, 0); - $resizeHeightInput.val(tempHeight); - }) - } + if (which === 'sign') { + // make height a read-only field + // and calculate its value based on width to preserve aspect ratio + $resizeHeightInput.prop('readonly',true); + $resizeWidthInput.on('input',function() { + tempWidth = $(this).val(); + tempHeight = Math.round(tempWidth/aspectRatio, 0); + $resizeHeightInput.val(tempHeight); + }) + } - // Add save and cancel buttons. - $saveButton = $('<button class="modal-button">' + this.tt.save + '</button>'); - $cancelButton = $('<button class="modal-button">' + this.tt.cancel + '</button>'); - $saveButton.on('click',function () { - newWidth = $('#' + widthId).val(); - newHeight = $('#' + heightId).val(); - if (newWidth !== startingWidth || newHeight !== startingHeight) { - $window.css({ - 'width': newWidth + 'px', - 'height': newHeight + 'px' - }); - thisObj.updateCookie(which); - } - resizeDialog.hide(); - $windowPopup.hide(); - $windowButton.focus(); - }); - $cancelButton.on('click',function () { - resizeDialog.hide(); - $windowPopup.hide(); - $windowButton.focus(); - }); + // Add save and cancel buttons. + $saveButton = $('<button class="modal-button">' + this.tt.save + '</button>'); + $cancelButton = $('<button class="modal-button">' + this.tt.cancel + '</button>'); + $saveButton.on('click',function () { + newWidth = $('#' + widthId).val(); + newHeight = $('#' + heightId).val(); + if (newWidth !== startingWidth || newHeight !== startingHeight) { + thisObj.resizeObject(which,newWidth,newHeight); + thisObj.updateCookie(which); + } + resizeDialog.hide(); + $windowPopup.hide(); + $windowButton.focus(); + }); + $cancelButton.on('click',function () { + resizeDialog.hide(); + $windowPopup.hide(); + $windowButton.focus(); + }); - // Now assemble all the parts - $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput); - $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput); - $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv); - $resizeForm.append($resizeWrapper,'<hr>',$saveButton,$cancelButton); + // Now assemble all the parts + $resizeWidthDiv.append($resizeWidthLabel,$resizeWidthInput); + $resizeHeightDiv.append($resizeHeightLabel,$resizeHeightInput); + $resizeWrapper.append($resizeWidthDiv,$resizeHeightDiv); + $resizeForm.append($resizeWrapper,'<hr>',$saveButton,$cancelButton); - // must be appended to the BODY! - // otherwise when aria-hidden="true" is applied to all background content - // that will include an ancestor of the dialog, - // which will render the dialog unreadable by screen readers - $('body').append($resizeForm); - resizeDialog = new AccessibleDialog($resizeForm, $windowButton, 'alert', this.tt.windowResizeHeading, $resizeWrapper, this.tt.closeButtonLabel, '20em'); - if (which === 'transcript') { - this.transcriptResizeDialog = resizeDialog; - } - else if (which === 'sign') { - this.signResizeDialog = resizeDialog; - } - }; + // must be appended to the BODY! + // otherwise when aria-hidden="true" is applied to all background content + // that will include an ancestor of the dialog, + // which will render the dialog unreadable by screen readers + $('body').append($resizeForm); + resizeDialog = new AccessibleDialog($resizeForm, $windowButton, 'alert', this.tt.windowResizeHeading, $resizeWrapper, this.tt.closeButtonLabel, '20em'); + if (which === 'transcript') { + this.transcriptResizeDialog = resizeDialog; + } + else if (which === 'sign') { + this.signResizeDialog = resizeDialog; + } + }; - AblePlayer.prototype.handleWindowButtonClick = function (which, e) { + AblePlayer.prototype.handleWindowButtonClick = function (which, e) { - var thisObj, $windowPopup, $windowButton, $toolbar, popupTop; + var thisObj, $windowPopup, $windowButton, $toolbar, popupTop; - thisObj = this; + thisObj = this; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - $windowButton = this.$transcriptPopupButton; - $toolbar = this.$transcriptToolbar; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - $windowButton = this.$signPopupButton; - $toolbar = this.$signToolbar; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + $windowButton = this.$transcriptPopupButton; + $toolbar = this.$transcriptToolbar; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + $windowButton = this.$signPopupButton; + $toolbar = this.$signToolbar; + } - if (e.type === 'keydown') { - // user pressed a key - if (e.which === 32 || e.which === 13) { - // this was Enter or space - this.windowMenuClickRegistered = true; - } - else if (e.which === 27) { // escape - // hide the popup menu - $windowPopup.hide('fast', function() { - // also reset the Boolean - thisObj.windowMenuClickRegistered = false; - // also restore menu items to their original state - $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); - // also return focus to window options button - $windowButton.focus(); - }); - } - else { - return false; - } - } - else { - // this was a mouse event - this.windowMenuClickRegistered = true; - } + if (e.type === 'keydown') { + // user pressed a key + if (e.which === 32 || e.which === 13) { + // this was Enter or space + this.windowMenuClickRegistered = true; + } + else if (e.which === 27) { // escape + // hide the popup menu + $windowPopup.hide('fast', function() { + // also reset the Boolean + thisObj.windowMenuClickRegistered = false; + // also restore menu items to their original state + $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); + // also return focus to window options button + $windowButton.focus(); + }); + } + else { + return false; + } + } + else { + // this was a mouse event + this.windowMenuClickRegistered = true; + } - if ($windowPopup.is(':visible')) { - $windowPopup.hide(200,'',function() { - thisObj.windowMenuClickRegistered = false; // reset - }); - $windowPopup.find('li').removeClass('able-focus'); - $windowButton.attr('aria-expanded','false').focus(); - } - else { - // first, be sure window is on top - this.updateZIndex(which); - popupTop = $windowButton.position().top + $windowButton.outerHeight(); - $windowPopup.css('top', popupTop); - $windowPopup.show(200,'',function() { - $windowButton.attr('aria-expanded','true'); - $(this).find('li').first().focus().addClass('able-focus'); - thisObj.windowMenuClickRegistered = false; // reset - }); - } - }; + if ($windowPopup.is(':visible')) { + $windowPopup.hide(200,'',function() { + thisObj.windowMenuClickRegistered = false; // reset + }); + $windowPopup.find('li').removeClass('able-focus'); + $windowButton.attr('aria-expanded','false').focus(); + } + else { + // first, be sure window is on top + this.updateZIndex(which); + popupTop = $windowButton.position().top + $windowButton.outerHeight(); + $windowPopup.css('top', popupTop); + $windowPopup.show(200,'',function() { + $windowButton.attr('aria-expanded','true'); + $(this).find('li').first().focus().addClass('able-focus'); + thisObj.windowMenuClickRegistered = false; // reset + }); + } + }; - AblePlayer.prototype.handleMenuChoice = function (which, choice, e) { + AblePlayer.prototype.handleMenuChoice = function (which, choice, e) { - var thisObj, $window, $windowPopup, $windowButton, resizeDialog, $thisRadio; + var thisObj, $window, $windowPopup, $windowButton, resizeDialog, $thisRadio; - thisObj = this; + thisObj = this; - if (which === 'transcript') { - $window = this.$transcriptArea; - $windowPopup = this.$transcriptPopup; - $windowButton = this.$transcriptPopupButton; - resizeDialog = this.transcriptResizeDialog; - } - else if (which === 'sign') { - $window = this.$signWindow; - $windowPopup = this.$signPopup; - $windowButton = this.$signPopupButton; - resizeDialog = this.signResizeDialog; - } + if (which === 'transcript') { + $window = this.$transcriptArea; + $windowPopup = this.$transcriptPopup; + $windowButton = this.$transcriptPopupButton; + resizeDialog = this.transcriptResizeDialog; + } + else if (which === 'sign') { + $window = this.$signWindow; + $windowPopup = this.$signPopup; + $windowButton = this.$signPopupButton; + resizeDialog = this.signResizeDialog; + } - if (e.type === 'keydown') { - if (e.which === 27) { // escape - // hide the popup menu - $windowPopup.hide('fast', function() { - // also reset the Boolean - thisObj.windowMenuClickRegistered = false; - // also restore menu items to their original state - $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); - // also return focus to window options button - $windowButton.focus(); - }); - return false; - } - else { - // all other keys will be handled by upstream functions - return false; - } - } + if (e.type === 'keydown') { + if (e.which === 27) { // escape + // hide the popup menu + $windowPopup.hide('fast', function() { + // also reset the Boolean + thisObj.windowMenuClickRegistered = false; + // also restore menu items to their original state + $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); + // also return focus to window options button + $windowButton.focus(); + }); + return false; + } + else { + // all other keys will be handled by upstream functions + return false; + } + } - // hide the popup menu - $windowPopup.hide('fast', function() { - // also reset the boolean - thisObj.windowMenuClickRegistered = false; - // also restore menu items to their original state - $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); - }); - if (choice !== 'close') { - $windowButton.focus(); - } + // hide the popup menu + $windowPopup.hide('fast', function() { + // also reset the boolean + thisObj.windowMenuClickRegistered = false; + // also restore menu items to their original state + $windowPopup.find('li').removeClass('able-focus').attr('tabindex','-1'); + }); + if (choice !== 'close') { + $windowButton.focus(); + } - if (choice === 'move') { - if (!this.showedAlert(which)) { - this.showAlert(this.tt.windowMoveAlert,which); - if (which === 'transcript') { - this.showedTranscriptAlert = true; - } - else if (which === 'sign') { - this.showedSignAlert = true; - } - } - if (e.type === 'keydown') { - this.dragDevice = 'keyboard'; - } - else { - this.dragDevice = 'mouse'; - } - this.startDrag(which, $window); - $windowPopup.hide().parent().focus(); - } - else if (choice == 'resize') { - // resize through the menu uses a form, not drag - resizeDialog.show(); - } - else if (choice == 'close') { - // close window, place focus on corresponding button on controller bar - if (which === 'transcript') { - this.handleTranscriptToggle(); - } - else if (which === 'sign') { - this.handleSignToggle(); - } - } - }; + if (choice === 'move') { + if (!this.showedAlert(which)) { + this.showAlert(this.tt.windowMoveAlert,which); + if (which === 'transcript') { + this.showedTranscriptAlert = true; + } + else if (which === 'sign') { + this.showedSignAlert = true; + } + } + if (e.type === 'keydown') { + this.dragDevice = 'keyboard'; + } + else { + this.dragDevice = 'mouse'; + } + this.startDrag(which, $window); + $windowPopup.hide().parent().focus(); + } + else if (choice == 'resize') { + // resize through the menu uses a form, not drag + resizeDialog.show(); + } + else if (choice == 'close') { + // close window, place focus on corresponding button on controller bar + if (which === 'transcript') { + this.handleTranscriptToggle(); + } + else if (which === 'sign') { + this.handleSignToggle(); + } + } + }; - AblePlayer.prototype.startDrag = function(which, $element) { - var thisObj, $windowPopup, zIndex, startPos, newX, newY; - thisObj = this; + AblePlayer.prototype.startDrag = function(which, $element) { + var thisObj, $windowPopup, zIndex, startPos, newX, newY; + thisObj = this; - this.$activeWindow = $element; - this.dragging = true; + this.$activeWindow = $element; + this.dragging = true; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + } - if (!this.showedAlert(which)) { - this.showAlert(this.tt.windowMoveAlert,which); - if (which === 'transcript') { - this.showedTranscriptAlert = true; - } - else if (which === 'sign') { - this.showedSignAlert = true; - } - } + if (!this.showedAlert(which)) { + this.showAlert(this.tt.windowMoveAlert,which); + if (which === 'transcript') { + this.showedTranscriptAlert = true; + } + else if (which === 'sign') { + this.showedSignAlert = true; + } + } - // if window's popup menu is open, close it - if ($windowPopup.is(':visible')) { - $windowPopup.hide(); - } + // if window's popup menu is open, close it + if ($windowPopup.is(':visible')) { + $windowPopup.hide(); + } - // be sure this window is on top - this.updateZIndex(which); + // be sure this window is on top + this.updateZIndex(which); - // get starting position of element - startPos = this.$activeWindow.position(); - this.dragStartX = startPos.left; - this.dragStartY = startPos.top; + // get starting position of element + startPos = this.$activeWindow.position(); + this.dragStartX = startPos.left; + this.dragStartY = startPos.top; - if (typeof this.startMouseX === 'undefined') { - this.dragDevice = 'keyboard'; - this.dragKeyX = this.dragStartX; - this.dragKeyY = this.dragStartY; - // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd() - this.startingDrag = true; - } - else { - this.dragDevice = 'mouse'; - // get offset between mouse position and top left corner of draggable element - this.dragOffsetX = this.startMouseX - this.dragStartX; - this.dragOffsetY = this.startMouseY - this.dragStartY; - } + if (typeof this.startMouseX === 'undefined') { + this.dragDevice = 'keyboard'; + this.dragKeyX = this.dragStartX; + this.dragKeyY = this.dragStartY; + // add stopgap to prevent the Enter that triggered startDrag() from also triggering dragEnd() + this.startingDrag = true; + } + else { + this.dragDevice = 'mouse'; + // get offset between mouse position and top left corner of draggable element + this.dragOffsetX = this.startMouseX - this.dragStartX; + this.dragOffsetY = this.startMouseY - this.dragStartY; + } - // prepare element for dragging - this.$activeWindow.addClass('able-drag').css({ - 'position': 'absolute', - 'top': this.dragStartY + 'px', - 'left': this.dragStartX + 'px' - }).focus(); + // prepare element for dragging + this.$activeWindow.addClass('able-drag').css({ + 'position': 'absolute', + 'top': this.dragStartY + 'px', + 'left': this.dragStartX + 'px' + }).focus(); - // add device-specific event listeners - if (this.dragDevice === 'mouse') { - $(document).on('mousemove',function(e) { - if (thisObj.dragging) { - // calculate new top left based on current mouse position - offset - newX = e.pageX - thisObj.dragOffsetX; - newY = e.pageY - thisObj.dragOffsetY; - thisObj.resetDraggedObject( newX, newY ); - } - }); - } - else if (this.dragDevice === 'keyboard') { - this.$activeWindow.on('keydown',function(e) { - if (thisObj.dragging) { - thisObj.dragKeys(which, e); - } - }); - } - return false; - }; + // add device-specific event listeners + if (this.dragDevice === 'mouse') { + $(document).on('mousemove',function(e) { + if (thisObj.dragging) { + // calculate new top left based on current mouse position - offset + newX = e.pageX - thisObj.dragOffsetX; + newY = e.pageY - thisObj.dragOffsetY; + thisObj.resetDraggedObject( newX, newY ); + } + }); + } + else if (this.dragDevice === 'keyboard') { + this.$activeWindow.on('keydown',function(e) { + if (thisObj.dragging) { + thisObj.dragKeys(which, e); + } + }); + } + return false; + }; - AblePlayer.prototype.dragKeys = function(which, e) { + AblePlayer.prototype.dragKeys = function(which, e) { - var key, keySpeed; + var key, keySpeed; - var thisObj = this; + var thisObj = this; - // stopgap to prevent firing on initial Enter or space - // that selected "Move" from menu - if (this.startingDrag) { - this.startingDrag = false; - return false; - } - key = e.which; - keySpeed = 10; // pixels per keypress event + // stopgap to prevent firing on initial Enter or space + // that selected "Move" from menu + if (this.startingDrag) { + this.startingDrag = false; + return false; + } + key = e.which; + keySpeed = 10; // pixels per keypress event - switch (key) { - case 37: // left - case 63234: - this.dragKeyX -= keySpeed; - break; - case 38: // up - case 63232: + switch (key) { + case 37: // left + case 63234: + this.dragKeyX -= keySpeed; + break; + case 38: // up + case 63232: this.dragKeyY -= keySpeed; - break; - case 39: // right - case 63235: + break; + case 39: // right + case 63235: this.dragKeyX += keySpeed; - break; - case 40: // down - case 63233: + break; + case 40: // down + case 63233: this.dragKeyY += keySpeed; - break; - case 13: // enter - case 27: // escape + break; + case 13: // enter + case 27: // escape this.endDrag(which); - return false; - default: return false; + default: + return false; } - this.resetDraggedObject(this.dragKeyX,this.dragKeyY); - if (e.preventDefault) { - e.preventDefault(); - } - return false; - }; + this.resetDraggedObject(this.dragKeyX,this.dragKeyY); + if (e.preventDefault) { + e.preventDefault(); + } + return false; + }; - AblePlayer.prototype.resetDraggedObject = function ( x, y) { - this.$activeWindow.css({ - 'left': x + 'px', - 'top': y + 'px' - }); - }, + AblePlayer.prototype.resetDraggedObject = function ( x, y) { + this.$activeWindow.css({ + 'left': x + 'px', + 'top': y + 'px' + }); + }, - AblePlayer.prototype.resizeObject = function ( which, width, height ) { + AblePlayer.prototype.resizeObject = function ( which, width, height ) { - var innerHeight; + var innerHeight; - // which is either 'transcript' or 'sign' - this.$activeWindow.css({ - 'width': width + 'px', - 'height': height + 'px' - }); + // which is either 'transcript' or 'sign' + this.$activeWindow.css({ + 'width': width + 'px', + 'height': height + 'px' + }); - if (which === 'transcript') { - // $activeWindow is the outer $transcriptArea - // but the inner able-transcript also needs to be resized proporitionally - // (it's 50px less than its outer container) - innerHeight = height - 50; - this.$transcriptDiv.css('height', innerHeight + 'px'); - } - }; + if (which === 'transcript') { + // $activeWindow is the outer $transcriptArea + // but the inner able-transcript also needs to be resized proporitionally + // (it's 50px less than its outer container) + innerHeight = height - 50; + this.$transcriptDiv.css('height', innerHeight + 'px'); + } + }; - AblePlayer.prototype.endDrag = function(which) { + AblePlayer.prototype.endDrag = function(which) { - var $window, $windowPopup, $windowButton; + var $window, $windowPopup, $windowButton; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - $windowButton = this.$transcriptPopupButton; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - $windowButton = this.$signPopupButton; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + $windowButton = this.$transcriptPopupButton; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + $windowButton = this.$signPopupButton; + } - $(document).off('mousemove mouseup'); - this.$activeWindow.off('keydown').removeClass('able-drag'); + $(document).off('mousemove mouseup'); + this.$activeWindow.off('keydown').removeClass('able-drag'); - if (this.dragDevice === 'keyboard') { - $windowButton.focus(); - } - this.dragging = false; + if (this.dragDevice === 'keyboard') { + $windowButton.focus(); + } + this.dragging = false; - // save final position of dragged element - this.updateCookie(which); + // save final position of dragged element + this.updateCookie(which); - // reset starting mouse positions - this.startMouseX = undefined; - this.startMouseY = undefined; + // reset starting mouse positions + this.startMouseX = undefined; + this.startMouseY = undefined; - // Boolean to stop stray events from firing - this.windowMenuClickRegistered = false; - this.finishingDrag = true; // will be reset after window click event + // Boolean to stop stray events from firing + this.windowMenuClickRegistered = false; + this.finishingDrag = true; // will be reset after window click event - // finishingDrag should e reset after window click event, - // which is triggered automatically after mouseup - // However, in case that's not reliable in some browsers - // need to ensure this gets cancelled - setTimeout(function() { - this.finishingDrag = false; - }, 100); - }; + // finishingDrag should e reset after window click event, + // which is triggered automatically after mouseup + // However, in case that's not reliable in some browsers + // need to ensure this gets cancelled + setTimeout(function() { + this.finishingDrag = false; + }, 100); + }; - AblePlayer.prototype.isCloseToCorner = function($window, mouseX, mouseY) { + AblePlayer.prototype.isCloseToCorner = function($window, mouseX, mouseY) { - // return true if mouse is close to bottom right corner (resize target) - var tolerance, position, top, left, width, height, bottom, right; + // return true if mouse is close to bottom right corner (resize target) + var tolerance, position, top, left, width, height, bottom, right; - tolerance = 10; // number of pixels in both directions considered "close enough" + tolerance = 10; // number of pixels in both directions considered "close enough" - // first, get position of element - position = $window.offset(); - top = position.top; - left = position.left; - width = $window.width(); - height = $window.height(); - bottom = top + height; - right = left + width; - if ((Math.abs(bottom-mouseY) <= tolerance) && (Math.abs(right-mouseX) <= tolerance)) { - return true; - } - return false; - }; + // first, get position of element + position = $window.offset(); + top = position.top; + left = position.left; + width = $window.width(); + height = $window.height(); + bottom = top + height; + right = left + width; + if ((Math.abs(bottom-mouseY) <= tolerance) && (Math.abs(right-mouseX) <= tolerance)) { + return true; + } + return false; + }; - AblePlayer.prototype.startResize = function(which, $element) { + AblePlayer.prototype.startResize = function(which, $element) { - var thisObj, $windowPopup, zIndex, startPos, newWidth, newHeight; - thisObj = this; + var thisObj, $windowPopup, zIndex, startPos, newWidth, newHeight; + thisObj = this; - this.$activeWindow = $element; - this.resizing = true; + this.$activeWindow = $element; + this.resizing = true; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + } - // if window's popup menu is open, close it & place focus on button (???) - if ($windowPopup.is(':visible')) { - $windowPopup.hide().parent().focus(); - } + // if window's popup menu is open, close it & place focus on button (???) + if ($windowPopup.is(':visible')) { + $windowPopup.hide().parent().focus(); + } - // get starting width and height - startPos = this.$activeWindow.position(); - this.dragKeyX = this.dragStartX; - this.dragKeyY = this.dragStartY; - this.dragStartWidth = this.$activeWindow.width(); - this.dragStartHeight = this.$activeWindow.height(); + // get starting width and height + startPos = this.$activeWindow.position(); + this.dragKeyX = this.dragStartX; + this.dragKeyY = this.dragStartY; + this.dragStartWidth = this.$activeWindow.width(); + this.dragStartHeight = this.$activeWindow.height(); - // add event listeners - $(document).on('mousemove',function(e) { - if (thisObj.resizing) { - // calculate new width and height based on changes to mouse position - newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX); - newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY); - thisObj.resizeObject( which, newWidth, newHeight ); - } - }); - return false; - }; + // add event listeners + $(document).on('mousemove',function(e) { + if (thisObj.resizing) { + // calculate new width and height based on changes to mouse position + newWidth = thisObj.dragStartWidth + (e.pageX - thisObj.startMouseX); + newHeight = thisObj.dragStartHeight + (e.pageY - thisObj.startMouseY); + thisObj.resizeObject( which, newWidth, newHeight ); + } + }); + return false; + }; - AblePlayer.prototype.endResize = function(which) { + AblePlayer.prototype.endResize = function(which) { - var $window, $windowPopup, $windowButton; + var $window, $windowPopup, $windowButton; - if (which === 'transcript') { - $windowPopup = this.$transcriptPopup; - $windowButton = this.$transcriptPopupButton; - } - else if (which === 'sign') { - $windowPopup = this.$signPopup; - $windowButton = this.$signPopupButton; - } + if (which === 'transcript') { + $windowPopup = this.$transcriptPopup; + $windowButton = this.$transcriptPopupButton; + } + else if (which === 'sign') { + $windowPopup = this.$signPopup; + $windowButton = this.$signPopupButton; + } - $(document).off('mousemove mouseup'); - this.$activeWindow.off('keydown'); + $(document).off('mousemove mouseup'); + this.$activeWindow.off('keydown'); - $windowButton.show().focus(); - this.resizing = false; - this.$activeWindow.removeClass('able-resize'); + $windowButton.show().focus(); + this.resizing = false; + this.$activeWindow.removeClass('able-resize'); - // save final width and height of dragged element - this.updateCookie(which); + // save final width and height of dragged element + this.updateCookie(which); - // Booleans for preventing stray events - this.windowMenuClickRegistered = false; - this.finishingDrag = true; + // Booleans for preventing stray events + this.windowMenuClickRegistered = false; + this.finishingDrag = true; - // finishingDrag should e reset after window click event, - // which is triggered automatically after mouseup - // However, in case that's not reliable in some browsers - // need to ensure this gets cancelled - setTimeout(function() { - this.finishingDrag = false; - }, 100); - }; + // finishingDrag should e reset after window click event, + // which is triggered automatically after mouseup + // However, in case that's not reliable in some browsers + // need to ensure this gets cancelled + setTimeout(function() { + this.finishingDrag = false; + }, 100); + }; })(jQuery);