forked from: 【FocusRotation】フォーカスの巡回を作成する

by nayu forked from 【FocusRotation】フォーカスの巡回を作成する (diff: 1)
♥0 | Line 263 | Modified 2010-09-26 08:54:27 | MIT License
play

ActionScript3 source code

/**
 * Copyright nayu ( http://wonderfl.net/user/nayu )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/sJ7t
 */

// forked from wetcradle's 【FocusRotation】フォーカスの巡回を作成する
/**
FocusRotation はタブキーによるフォーカスの巡回を作成します。
このサンプルでは[A1, A2, A3], [B1, B2, B3], [C1, C2, C3] の3つの巡回を作成しています。
*/
package {
    
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldType;
    
    public class FocusRotationSample extends Sprite {
        
        private var textFields:Vector.<TextField>;
        
        public function FocusRotationSample():void {
            super();
            configTextFields();
            
            textFields[0].text = "A1";
            textFields[4].text = "A2";
            textFields[8].text = "A3";
            var focusRotationA:FocusRotation = new FocusRotation([textFields[0], textFields[4], textFields[8]]);
            
            textFields[1].text = "B1";
            textFields[2].text = "B2";
            textFields[5].text = "B3";
            var focusRotationB:FocusRotation = new FocusRotation([textFields[1], textFields[2], textFields[5]]);
            
            textFields[3].text = "C1";
            textFields[6].text = "C2";
            textFields[7].text = "C3";
            var focusRotationC:FocusRotation = new FocusRotation([textFields[3], textFields[6], textFields[7]]);
            
            focusRotationA.focusFirst();
        }
        
        private function configTextFields():void {
            textFields = new Vector.<TextField>();
            for (var i:int=0; i<9; i++) {
                var textField:TextField = new TextField();
                textField.type = TextFieldType.INPUT;
                textField.border = true;
                textField.width = 100;
                textField.height = 22;
                textField.x = (i % 3) * 110 + 10;
                textField.y = Math.floor(i / 3) * 50 + 10;
                addChild(textField);
                textFields.push(textField);
            }
        }
        
    }
}

//import fl.core.UIComponent;
import flash.display.InteractiveObject;
import flash.events.Event;
import flash.events.FocusEvent;
class FocusRotation {
    
    protected var _members:Array;
    protected var _active:Boolean = false;
    
    //members のうち表示オブジェクトに含まれるもの
    //activeMembers は整合性は保たれない。validateActiveMembers を呼ぶ必要がある。
    protected var activeMembers:Array = [];
    protected var invalidActiveMembers:Boolean = false;
    
    ////////////////////////////////////////////////////////////
    //////////////コンストラクタ
    ////////////////////////////////////////////////////////////
    public function FocusRotation(members:Array=null):void {
        super();
        _members = members ? members : [];
        inactivate();
    }
    
    ////////////////////////////////////////////////////////////
    //////////////プロパティ
    ////////////////////////////////////////////////////////////
    
    //______________ members ______________//
    /**
    null を設定しようとするとエラーになります。
    */
    public function get members():Array {
        return _members;
    }
    public function set members(value:Array):void {
        if (!value) {
            throw new ArgumentError("null");
        }
        _members = value;
        refreshMembers();
    }
    
    //______________ active ______________//
    public function get active():Boolean {
        return _active;
    }
    
    //______________ length ______________//
    public function get length():int {
        return _members.length;
    }
    
    ////////////////////////////////////////////////////////////
    //////////////パブリックメソッド
    ////////////////////////////////////////////////////////////
    
    //______________ destroy ______________//
    public function destroy():void {
        members = [];
        inactivate();
        _members = null;
    }
    
    //______________ activate ______________//
    /**
    */
    public function activate():void {
        _active = true;
        refreshMembers();
        FocusRotationManager.focusRotationManager.activateRotation(this);
    }
    
    //______________ inactivate ______________//
    public function inactivate():void {
        _active = false;
        refreshMembers();
        FocusRotationManager.focusRotationManager.inactivateRotation(this);
    }
    
    //______________ focusFirst ______________//
    /**
    activate メソッドを呼び、最初のメンバにフォーカスを設定します。
    */
    public function focusFirst():void {
        activate();//refreshMembers が呼ばれるので validateActiveMembers は必要ない
        if (activeMembers.length) {
            var member:InteractiveObject = InteractiveObject(activeMembers[0]);
            if (member.stage) {//member.stage は refreshMembers が直前に呼ばれてるため保証されているはずだが、null になることがある
                member.stage.focus = member;
            }
        }
    }
    
    //______________ focusLast ______________//
    /**
    activate メソッドを呼び、最後のメンバにフォーカスを設定します。
    */
    public function focusLast():void {
        activate();//refreshMembers が呼ばれるので validateActiveMembers は必要ない
        if (activeMembers.length) {
            var member:InteractiveObject = InteractiveObject(activeMembers[activeMembers.length - 1]);
            if (member.stage) {//member.stage は refreshMembers が直前に呼ばれてるため保証されているはずだが、null になることがある
                member.stage.focus = member;
            }
        }
    }
    
    //______________ addMember ______________//
    public function addMember(member:InteractiveObject):void {
        addMemberAt(member, _members.length);
    }
    
    //______________ addMemberAt ______________//
    public function addMemberAt(member:InteractiveObject, index:uint):void {
        _members.splice(index, 0, member);
        refreshMembers();
    }
    
    //______________ replaceMemberAt ______________//
    public function replaceMemberAt(member:InteractiveObject, index:uint):void {
        _members.splice(index, 1, member);
        refreshMembers();
    }
    
    //______________ removeMember ______________//
    public function removeMember(member:InteractiveObject):void {
        var index:int = members.indexOf(member);
        if (index == -1) {
            throw new Error("not found");
        }
        _members.splice(index, 1);
        refreshMembers();
    }
    
    ////////////////////////////////////////////////////////////
    //////////////メソッド
    ////////////////////////////////////////////////////////////
    
    //______________ refreshMembers ______________//
    protected function refreshMembers():void {
        var item:Object;
        var member:InteractiveObject;
        
        var lastMember:InteractiveObject;
        var firstMember:InteractiveObject;
        if (activeMembers) {
            for each (member in _members) {
                //member.tabIndex = -1;
                //member.tabEnabled = false;
                member.removeEventListener(FocusEvent.FOCUS_IN, memberFocusInHandler);
                member.removeEventListener(FocusEvent.KEY_FOCUS_CHANGE, keyFocusChangeEvent);
                member.removeEventListener(Event.ADDED_TO_STAGE, memberAddedToStageHandler);
                member.removeEventListener(Event.REMOVED_FROM_STAGE, memberRemovedFromStageHandler);
            }
        }
        
        activeMembers = [];
        if (_members) {
            var tabIndex:int = 1;
            for each (item in _members) {
                member = item as InteractiveObject;
                if (!member) {
                    throw new Error("member must be InteractiveObject: "+member);
                }
                if (_active && member.stage) {
                    member.tabEnabled = true;
                    member.tabIndex = tabIndex++;
                    activeMembers.push(member);
                }
                else {
                    //member.tabEnabled = false;
                    //member.tabIndex = -1;
                }
                member.addEventListener(FocusEvent.FOCUS_IN, memberFocusInHandler);
                member.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, keyFocusChangeEvent);
                member.addEventListener(Event.ADDED_TO_STAGE, memberAddedToStageHandler);
                member.addEventListener(Event.REMOVED_FROM_STAGE, memberRemovedFromStageHandler);
            }
        }
    }
    
    //______________ invalidateActiveMembers ______________//
    protected function invalidateActiveMembers():void {
        invalidActiveMembers = true;
        FunctionTools.callAfter(this, 1, validateActiveMembers)
    }
    
    //______________ validateActiveMembers ______________//
    protected function validateActiveMembers():void {
        if (invalidActiveMembers) {
            refreshMembers();
            invalidActiveMembers = false;
        }
    }
    
    ////////////////////////////////////////////////////////////
    //////////////イベントハンドラ
    ////////////////////////////////////////////////////////////
    
    //______________ memberFocusInHandler ______________//
    protected function memberFocusInHandler(e:FocusEvent):void {
        activate();
    }
    
    //______________ keyFocusChangeEvent ______________//
    protected function keyFocusChangeEvent(e:FocusEvent):void {
        validateActiveMembers();
        
        var i:int;
        var tempMember:InteractiveObject;
        var member:InteractiveObject = InteractiveObject(e.currentTarget);
        var memberIndex:int = activeMembers.indexOf(member);
        
        if (memberIndex == -1) {
            return;
        }
        if (e.shiftKey) {
            for (i=(memberIndex+activeMembers.length-1)%activeMembers.length; i!=memberIndex; i=(i-1)%activeMembers.length) {
                tempMember = InteractiveObject(activeMembers[i]);
                //if (!(tempMember is UIComponent) || UIComponent(tempMember).enabled) {
                    tempMember.stage.focus = tempMember;
                    break;
                //}
            }
        }
        else {
            for (i=(memberIndex+1)%activeMembers.length; i!=memberIndex; i=(i+1)%activeMembers.length) {
                tempMember = InteractiveObject(activeMembers[i]);
                //if (!(tempMember is UIComponent) || UIComponent(tempMember).enabled) {
                    tempMember.stage.focus = tempMember;
                    break;
                //}
            }
        }
        e.preventDefault();
    }
    
    //______________ memberAddedToStageHandler ______________//
    protected function memberAddedToStageHandler(e:Event):void {
        invalidateActiveMembers();
    }
    
    //______________ memberRemovedFromStageHandler ______________//
    protected function memberRemovedFromStageHandler(e:Event):void {
        invalidateActiveMembers();
    }
    
}

import flash.utils.Dictionary;
class FocusRotationManager {
    
    protected static var _focusRotationManager:FocusRotationManager;
    
    protected var _activeRotation:FocusRotation;
    
    private static var allowInstantiation:Boolean = false;
    
    ////////////////////////////////////////////////////////////
    //////////////コンストラクタ
    ////////////////////////////////////////////////////////////
    public function FocusRotationManager():void {
        super();
        if (!allowInstantiation) {
            throw new Error("Instantiation is prohibited");
        }
    }
    
    ////////////////////////////////////////////////////////////
    //////////////プロパティ
    ////////////////////////////////////////////////////////////
    
    //______________ focusRotationManager ______________//
    public static function get focusRotationManager():FocusRotationManager {
        if (!_focusRotationManager) {
            allowInstantiation = true;
            _focusRotationManager = new FocusRotationManager();
            allowInstantiation = false;
        }
        return _focusRotationManager;
    }
    
    //______________ activeRotation ______________//
    public function get activeRotation():FocusRotation {
        return _activeRotation;
    }
    
    ////////////////////////////////////////////////////////////
    //////////////メソッド
    ////////////////////////////////////////////////////////////
    
    //______________ activateRotation ______________//
    internal function activateRotation(rotation:FocusRotation):void {
        if (_activeRotation && _activeRotation !== rotation) {
            _activeRotation.inactivate();
        }
        _activeRotation = rotation;
    }
    
    //______________ inactivateRotation ______________//
    internal function inactivateRotation(rotation:FocusRotation):void {
        if (_activeRotation === rotation) {
            _activeRotation = null;
        }
    }
    
}

import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
class FunctionTools {
    
    //______________ callAfterFrame ______________//
    /**
    1フレーム後にメソッドをコールします。
    thisObjectにはfuncメソッドを持っているオブジェクトを指定します。
    ...argsにはfuncへ渡す引数を指定します。
    */
    public static function callAfterFrame(thisObject:Object, func:Function, ...args):void {
        var dispatcher:Sprite = new Sprite();
        if (args.length > 2) {
            throw new ArgumentError("over the limit of arguments count");
        }
        dispatcher.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        function enterFrameHandler(e:Event):void {
            dispatcher.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
            func.apply(thisObject, args);
        }
    }
    
    //______________ callAfter ______________//
    /**
    指定した時間後にメソッドをコールします。
    thisObjectにはfuncメソッドを持っているオブジェクトを指定します。
    ...argsにはfuncへ渡す引数を指定します。
    */
    public static function callAfter(thisObject:Object, msec:Number, func:Function, ...args):void {
        var timer:Timer = new Timer(msec, 1);
        if (args.length > 2) {
            throw new ArgumentError("over the limit of arguments count");
        }
        timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
        timer.start();
        function timerCompleteHandler(e:TimerEvent):void {
            timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
            func.apply(thisObject, args);
        }
    }
    
}