Tag Archives for brightcove
Brightcove videoplayer accessibility plugin
Q2 2014Javascript/Actionscript solution to Brightcove player accessibility problems
DOWNLOAD SRC
When I wrote this, Brightcove did have an “Accessible” template – which was not even remotely accessible. Accessible means I should be able to navigate the web page/application with my eyes closed, using only the keyboard, and access the same content in as smooth and efficient an experience as a visually-equipped user.
This solution isn’t perfect – I still received complaints from users about tab-accessibility inconsistency and video control button labels not changing on toggle, which I couldn’t control without access to the video src. Ultimately, we decided to move off of Brightcove as a video solution, but if you’re stuck with it, this will help significantly.
Tabbing into and out of Flash objects embedded on an HTML page is a common problem — if you can’t tab into an embedded application, it doesn’t exist to any user using a screenreader. The solution I stitched together uses a Class from Adobe to setup the tab ordering of clickable elements within the swf, in combination with some javascript by Richard England to handle focus into and out of the swf.
1. Create the swf that will become your custom Brightcove plugin. This is an empty .swf which, upon being added to the stage, will explore the heirarchy of the swf into which is has been imported, find the video controls, will pass those to the SWFFocus class. Below isthe Document class of your .fla.
package { import com.adobe.swffocus.SWFFocus; import flash.accessibility.AccessibilityProperties; import flash.accessibility.Accessibility; import flash.display.Sprite; import flash.events.Event; // import com.richardengland.utils.Tabbing; import flash.display.DisplayObjectContainer; import flash.display.DisplayObject; import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; public class SWFFocusFix extends Sprite { public function SWFFocusFix() { if (stage) { init(); } else { addEventListener(Event.ADDED_TO_STAGE, init); } } private function init(event:Event = null):void { trace("SWFFocusFix.init"); var player:Object = parent; var counter:Number = 0; var buttonContainer:Object; while (player.parent) { for (var i:uint = 0; i < player.numChildren; i++) { var child:DisplayObject = player.getChildAt(i); var childClass = getQualifiedClassName(child); if (childClass.indexOf("BEMLContainer") != -1) { //then this is where we want the tabbing focus to be buttonContainer = child; } } player = player.parent; counter++; if (buttonContainer) { break; } } traceDisplayList(DisplayObjectContainer(player)); if (player) { trace("Found player.stage! | " + player.stage); if (player.stage) { if (hasEventListener(Event.ADDED_TO_STAGE)) { removeEventListener(Event.ADDED_TO_STAGE, init); } /* if (buttonContainer) { var tabbing = new Tabbing(DisplayObjectContainer(buttonContainer)); } */ if (buttonContainer) { SWFFocus.init(buttonContainer.stage); } } } else { if (stage) { trace("Using local stage."); SWFFocus.init(stage); } } } private function traceDisplayList(container:DisplayObjectContainer, indentString:String = ""):void { var child:DisplayObject; for (var i:uint=0; i < container.numChildren; i++) { child = container.getChildAt(i); if (child.accessibilityProperties) { trace(child.accessibilityProperties.name, child.accessibilityProperties.description ); } trace(indentString, child, child.name); if (container.getChildAt(i) is DisplayObjectContainer) { traceDisplayList(DisplayObjectContainer(child), indentString + " "); } var childClass = getQualifiedClassName(child); //adjustment for the closedCaptions BG //if (child.name == "instance137" && childClass.indexOf("GlowingButton") != -1) { if (childClass.indexOf("GlowingButton") != -1){ if (getQualifiedClassName(child.parent.parent.parent).indexOf("CaptionControls") != -1){ trace("******* removed child " + child.name); //child.parent.removeChild(child); child.alpha = 0; } } } } } }Read More →