forked from: 【FocusRotation】フォーカスの巡回を作成する
forked from 【FocusRotation】フォーカスの巡回を作成する (diff: 1)
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);
}
}
}