//////////////////////////////////////////////////////////////////////////////// // // 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.states { import flash.events.EventDispatcher; import flash.utils.Dictionary; import mx.core.ComponentDescriptor; import mx.core.UIComponent; import mx.states.OverrideBase; import mx.core.IStateClient2; /** * The event handler function to execute in response to the event that is * specified by the name property. * *

Do not specify the handler property and the handlerFunction * property in a single <mx:SetEventHandler> tag.

* *

Flex does not dispatch a handler event. * You use the handler key word only as an MXML attribte. * When you use the handler handler attribute, you can specify a * method that takes multiple parameters, not just the Event object; * also, you can specify the handler code in-line in the MXML tag.

* * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ [Event(name="handler", type="Object")] /** * The SetEventHandler class specifies an event handler that is active * only during a particular view state. * For example, you might define a Button control that uses one event handler * in the base view state, but uses a different event handler when you change view state. * *

You use this class in the overrides property of the State class.

* * @mxml * *

The <mx:SetEventHanlder> tag * has the following attributes:

* *
 *  <mx:SetEventHandler
 *  Properties
 *  name="null"
 *  handlerFunction="null"
 *  target="null"
 *  
 *  Events
 *  handler=No default
 *  />
 *  
* * @see mx.states.State * @see mx.states.SetProperty * @see mx.states.SetStyle * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class SetEventHandler extends OverrideBase { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @param target The object that dispatches the event to be handled. * By default, Flex uses the immediate parent of the State object. * * @param event The event type for which to set the handler. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function SetEventHandler( target:EventDispatcher = null, name:String = null) { super(); this.target = target; this.name = name; } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private * Storage for the old event handler value. */ private var oldHandlerFunction:Function; /** * @private * Dictionary of installed event handlers. */ private static var installedHandlers:Dictionary; //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // name //---------------------------------- [Inspectable(category="General")] /** * The name of the event whose handler is being set. * You must set this property, either in * the SetEventHandler constructor or by setting * the property value directly. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var name:String; /** * The handler function for the event. * This property is intended for developers who use ActionScript to * create and access view states. * In MXML, you can use the equivalent handler * event attribute; do not use both in a single MXML tag. * * @default null * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var handlerFunction:Function; /** * The handler function to remove prior to applying our override. * * @default null * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 4.5 */ public var originalHandlerFunction:Function; //---------------------------------- // target //---------------------------------- [Inspectable(category="General")] /** * The component that dispatches the event. * If the property value is null, Flex uses the * immediate parent of the <mx:states> tag. * * @default null * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var target:Object; /** * The cached target for which we applied our override. * We keep track of the applied target while applied since * our target may be swapped out in the owning document and * we want to make sure we roll back the correct (original) * element. * * @private */ private var appliedTarget:Object; //-------------------------------------------------------------------------- // // Overridden methods: EventDispatcher // //-------------------------------------------------------------------------- /** * @private */ override public function addEventListener( type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { if (type == "handler") handlerFunction = listener; super.addEventListener(type, listener, useCapture, priority, useWeakReference); } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ override public function apply(parent:UIComponent):void { parentContext = parent; var obj:* = getOverrideContext(target, parent); if (obj != null) { appliedTarget = obj; var uiObj:UIComponent = obj as UIComponent; if (!installedHandlers) installedHandlers = new Dictionary(true); // Remember the current handler so it can be restored if (installedHandlers[obj] && installedHandlers[obj][name]) { oldHandlerFunction = installedHandlers[obj][name]; obj.removeEventListener(name, oldHandlerFunction); } else if (originalHandlerFunction != null) { oldHandlerFunction = originalHandlerFunction; obj.removeEventListener(name, oldHandlerFunction); } else if (uiObj && uiObj.descriptor) { var descriptor:ComponentDescriptor = uiObj.descriptor; if (descriptor.events && descriptor.events[name]) { oldHandlerFunction = uiObj.document[descriptor.events[name]]; obj.removeEventListener(name, oldHandlerFunction); } } // Set new handler as weak reference if (handlerFunction != null) { obj.addEventListener(name, handlerFunction, false, 0, true); // Add this handler to our installedHandlers list so it can // be removed if needed by a state based on this state. We // only do so for legacy MXML documents that support hierarchical // states. if (!(parent.document is IStateClient2)) { if (installedHandlers[obj] == undefined) installedHandlers[obj] = {}; installedHandlers[obj][name] = handlerFunction; } // Disable bindings for the base event handler if appropriate. If the binding // fires while our override is applied, the correct value will automatically // be applied when the binding is later enabled. enableBindings(obj, parent, name, false); } } else if (!applied) { // Our target context is unavailable so we attempt to register // a listener on our parent document to detect when/if it becomes // valid. addContextListener(target); } // Save state in case our value or target is changed while applied. This // can occur when our value property is databound or when a target is // deferred instantiated. applied = true; } /** * @inheritDoc * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ override public function remove(parent:UIComponent):void { var obj:* = getOverrideContext(appliedTarget, parent); if (obj != null && appliedTarget) { if (handlerFunction != null) obj.removeEventListener(name, handlerFunction); // Restore the old value if (oldHandlerFunction != null) obj.addEventListener(name, oldHandlerFunction, false, 0, true); if (installedHandlers[obj]) { var deleteObj:Boolean = true; // Remove this handler delete installedHandlers[obj][name]; // If no other handlers are installed for this object, delete // this object from the installedHandlers dictionary for (var i:String in installedHandlers[obj]) { // Found one - don't delete this object deleteObj = false; break; } if (deleteObj) delete installedHandlers[obj]; } // Re-enable bindings for the base event handler if appropriate. If the binding // fired while our override was applied, the current value will automatically // be applied once enabled. enableBindings(obj, parent, name); } else { // It seems our override is no longer active, but we were never // able to successfully apply ourselves, so remove our context // listener if applicable. removeContextListener(); } // Clear our flags and override context. applied = false; parentContext = null; appliedTarget = null; } } }