| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package mx.accessibility |
| { |
| |
| import flash.accessibility.Accessibility; |
| import flash.accessibility.AccessibilityProperties; |
| import flash.events.Event; |
| import flash.system.ApplicationDomain; |
| |
| import mx.accessibility.AccImpl; |
| import mx.core.UIComponent; |
| import mx.core.mx_internal; |
| |
| use namespace mx_internal; |
| |
| /** |
| * UIComponentAccProps is a subclass of AccessibilityProperties |
| * for use by various UIComponents. |
| * It is used to provide accessibility to Form, ToolTip, and Error ToolTip. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class UIComponentAccProps extends AccessibilityProperties |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Enables accessibility in the UIComponent class. |
| * |
| * <p>This method is called by application startup code |
| * that is autogenerated by the MXML compiler. |
| * Afterwards, when instances of UIComponent are initialized, |
| * their <code>accessibilityProperties</code> property |
| * will be set to an instance of this class.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function enableAccessibility():void |
| { |
| UIComponent.createAccessibilityImplementation = |
| createAccessibilityImplementation; |
| } |
| |
| /** |
| * @private |
| * Creates a UIComponent's AccessibilityProperties object. |
| * This method is called from UIComponent's |
| * initializeAccessibility() method. |
| */ |
| mx_internal static function createAccessibilityImplementation( |
| component:UIComponent):void |
| { |
| component.accessibilityProperties = |
| new UIComponentAccProps(component); |
| } |
| |
| /** |
| * @private |
| * Determines whether a component should avoid producing MSAA information |
| * directly. Components that are represented otherwise, such as |
| * a form field's Required Field indicator (which causes "Required field" |
| * to be included in the field's accessible name) should be made silent |
| * in this way. |
| * |
| * @param component The component to check. |
| * |
| * @return true if this component should be silent. |
| */ |
| mx_internal static function componentShouldBeSilent(component:UIComponent):Boolean |
| { |
| // All tests below require Group to exist and to be under a FormItem. |
| var groupClass:Class = Class(AccImpl.getDefinition( |
| "spark.components.Group", component.moduleFactory |
| )); |
| if (!groupClass) |
| return false; |
| var formItem:UIComponent = AccImpl.findMatchingAncestor(component, AccImpl.isFormItem); |
| if (!formItem) |
| return false; |
| |
| // This catches labels for FormItem fields, |
| // and also one object related to the Required Field indicator. |
| // TODO: We might want to silence all Group components under a FormItem, |
| // but this theory remains to be tested and so is not implemented here. |
| // component.parent should be a FormItem skin (possibly a custom one), |
| // so the parent of that should be the FormItem. |
| // The try/catch block prevents an RTE if |
| // component.parent.parent doesn't exist. |
| try |
| { |
| if (component is groupClass |
| && component.parent.parent === formItem) |
| return true; |
| } |
| catch (e:Error) |
| { |
| } |
| |
| // This catches the Required Field graphic itself. |
| // Sought structure: Image in Group in skin in FormItem. |
| var imageClass:Class = Class(AccImpl.getDefinition( |
| "spark.components.Image", component.moduleFactory |
| )); |
| if (!imageClass) |
| return false; |
| try |
| { |
| if (component is imageClass && component.parent is groupClass |
| && component.parent.parent.parent === formItem) |
| return true; |
| } |
| catch (e:Error) |
| { |
| } |
| |
| return false; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @param master The UIComponent instance that this |
| * AccessibilityProperties instance is making accessible. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function UIComponentAccProps(component:UIComponent) |
| { |
| super(); |
| |
| master = component; |
| |
| if (component.accessibilityProperties) |
| { |
| silent = component.accessibilityProperties.silent; |
| |
| forceSimple = component.accessibilityProperties.forceSimple; |
| |
| noAutoLabeling = component.accessibilityProperties.noAutoLabeling; |
| |
| if (component.accessibilityProperties.name) |
| name = component.accessibilityProperties.name; |
| |
| if (component.accessibilityProperties.description) |
| description = component.accessibilityProperties.description; |
| |
| if (component.accessibilityProperties.shortcut) |
| shortcut = component.accessibilityProperties.shortcut; |
| } |
| |
| if (AccImpl.getMatchingDefinition(master, |
| AccImpl.getDefinitions("ScrollBar", master.moduleFactory) |
| )) |
| { |
| silent = true; |
| return; |
| } |
| |
| if (isFormItemLabel(master)) |
| { |
| // TODO: Why is name set here? Is this name used somewhere? |
| name = AccImpl.getFormName(master); |
| silent = true; |
| return; |
| } |
| |
| // Silence various subparts of Spark forms besides FormItem labels. |
| if (componentShouldBeSilent(component)) |
| { |
| // We can't set silent=true or whole FormItems and their fields |
| // will disappear from MSAA, but if we set name="", the Player |
| // will filter out these items for us. |
| name = ""; |
| return; |
| } |
| |
| // In complex layouts, the text of a FormHeading might not appear |
| // where it should for assistive technology, because the FormHeading's |
| // tabIndex does not also get applied to the text item. |
| // That is fixed here when the FormHeading is being constructed. |
| if (AccImpl.isFormHeading(master) && master.tabIndex > 0) |
| { |
| // Spark-specific solution. |
| try |
| { |
| if (Object(master).labelDisplay.tabIndex == -1) |
| Object(master).labelDisplay.tabIndex = master.tabIndex; |
| } |
| catch (e:Error) |
| { |
| } |
| // TODO: Not solved for MX even though the problem does apply there. |
| } |
| |
| var formName:String = AccImpl.getFormName(master); |
| if (formName && formName.length != 0) |
| name = formName + name; |
| |
| if (master.toolTip && master.toolTip.length != 0) |
| if (!component.accessibilityProperties || (component.accessibilityProperties && !component.accessibilityProperties.name)) |
| { |
| oldToolTip = " " + master.toolTip; |
| name += oldToolTip; |
| } |
| |
| if (master.errorString && master.errorString.length != 0) |
| { |
| oldErrorString = " " + master.errorString; |
| name += oldErrorString; |
| } |
| |
| master.addEventListener("toolTipChanged", eventHandler); |
| master.addEventListener("errorStringChanged", eventHandler); |
| } |
| |
| /** |
| * @private |
| * Determines whether a component is a formItem label (Spark or MX). |
| * |
| * @param component The component to check. |
| * |
| * @return true if this is a label for a formItem. |
| */ |
| protected function isFormItemLabel(component:UIComponent):Boolean |
| { |
| // This handles Spark labels on forms. |
| var thisName:String = master.name; |
| if (thisName == "labelDisplay" |
| || thisName == "sequenceLabelDisplay" |
| || thisName == "helpContentGroup" |
| || thisName == "errorTextDisplay" |
| ) |
| return true; |
| |
| // This handles MX FormItemLabel objects. |
| return Boolean(AccImpl.getMatchingDefinition(master, |
| AccImpl.getDefinitions("FormItemLabel", master.moduleFactory) |
| )); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var oldToolTip:String; |
| |
| /** |
| * @private |
| */ |
| private var oldErrorString:String; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // master |
| //---------------------------------- |
| |
| /** |
| * A reference to the UIComponent itself. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var master:UIComponent; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Generic event handler. |
| * All UIComponentAccProps subclasses must implement this |
| * to listen for events from its master component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function eventHandler(event:Event):void |
| { |
| var pos:int; |
| |
| switch (event.type) |
| { |
| case "errorStringChanged": |
| { |
| if (name && name.length != 0 && oldErrorString) |
| { |
| pos = name.indexOf(oldErrorString); |
| if (pos != -1) |
| { |
| name = name.substring(0, pos) + |
| name.substring(pos + oldErrorString.length); |
| } |
| oldErrorString = null; |
| } |
| |
| if (master.errorString && master.errorString.length != 0) |
| { |
| if (!name) |
| name = ""; |
| |
| oldErrorString = " " + master.errorString; |
| name += oldErrorString; |
| } |
| |
| Accessibility.updateProperties(); |
| break; |
| } |
| |
| case "toolTipChanged": |
| { |
| if (name && name.length != 0 && oldToolTip) |
| { |
| pos = name.indexOf(oldToolTip); |
| if (pos != -1) |
| { |
| name = name.substring(0, pos) + |
| name.substring(pos + oldToolTip.length); |
| } |
| oldToolTip = null; |
| } |
| |
| if (master.toolTip && master.toolTip.length != 0) |
| { |
| if (!master.accessibilityProperties || (master.accessibilityProperties && !master.accessibilityProperties.name)) |
| { |
| if (!name) |
| name = ""; |
| |
| oldToolTip = " " + master.toolTip; |
| name += oldToolTip; |
| } |
| } |
| |
| Accessibility.updateProperties(); |
| break; |
| } |
| } |
| } |
| } |
| |
| } |