XML Accordion Tree Simple XML based multilevel accordion tree meix forked:1favorite:9lines:303license : MIT License modified : 2011-03-30 00:52:45 Embed Tweet /*****************************************************************************************/ /* ACCORDION TREE CLASS /*****************************************************************************************/ package{ import flash.display.*; import flash.text.*; import flash.events.*; import flash.geom.*; import gs.TweenLite; import gs.easing.Expo; import gs.plugins.TweenPlugin; import gs.plugins.TintPlugin; import idv.cjcat.signals.NativeSignal; public class AccordionTree extends Sprite { public static var ITEM_WIDTH:int = 260; public static var ITEM_HEIGHT:int = 25; private var menuSprite:Sprite; private var contractMask:Shape; private var expandMask:Shape; private var enterFrameSignal:NativeSignal; private var data:XML = new XML("<content><item>TreeItem 1</item><item>TreeItem 2</item><item>TreeItem 3<item>TreeItem 3-1</item><item>TreeItem 3-2</item><item>TreeItem 3-3</item><item>TreeItem 3-4</item><item>TreeItem 3-5</item><item>TreeItem 3-6</item><item>TreeItem 3-7</item><item>TreeItem 3-8</item><item>TreeItem 3-9</item><item>TreeItem 3-10</item><item>TreeItem 3-11</item></item><item>TreeItem 4</item><item>TreeItem 5<item>TreeItem 5-1<item>TreeItem 5-1-1</item><item>TreeItem 5-1-2</item><item>TreeItem 5-1-3<item>TreeItem 5-1-3-1</item></item><item>TreeItem 5-1-4<item>TreeItem 5-1-4-1</item><item>TreeItem 5-1-4-2</item><item>TreeItem 5-1-4-3<item>TreeItem 5-1-4-3-1</item><item>TreeItem 5-1-4-3-2</item></item><item>TreeItem 5-1-4-4</item></item><item>TreeItem 5-1-5</item></item><item>TreeItem 5-2</item></item><item>TreeItem 6</item><item>TreeItem 7</item><item>TreeItem 8<item>TreeItem 8-1</item><item>TreeItem 8-2</item><item>TreeItem 8-3</item><item>TreeItem 8-4</item></item><item>TreeItem 9</item></content>"); private var items:Vector.<Object> = new Vector.<Object>(); private var itemsCopy:Vector.<Object>; private var tweenDuration:Number = .5; private var tweenEase:Function = Expo.easeOut; private var selectedIndex:int = -1; public function AccordionTree(){ TweenPlugin.activate([TintPlugin]); enterFrameSignal = new NativeSignal(this, Event.ENTER_FRAME); menuSprite = new Sprite(); menuSprite.x = menuSprite.y = 10; addChild(menuSprite); contractMask = getMask(); expandMask = getMask(); parse(data); initChildAndParentIndices(); addChildren(); contractAll(); } private function getMask():Shape { var s:Shape = new Shape(); s.graphics.beginFill(0xFF0000, 0); s.graphics.drawRect(0, 0, 10, 10); s.graphics.endFill(); return s; } private function parse(node:XML, level:int = -1):void{ var item:TreeItem = new TreeItem(node, level); item.width = ITEM_WIDTH; item.height = ITEM_HEIGHT; item.clickSignal.add(onItemClick); items.push( { sprite:item, level:level, tweenY:0, parentIndex:-1, childIndices:[], visible:Boolean } ); node.item.(parse(valueOf(), level + 1)); } private function addChildren():void { for each (var o:Object in items) { menuSprite.addChild(o.sprite); } } private function initChildAndParentIndices():void { var levelsObject:Object = { }; var lastLevel:int = -1; for (var i:int = 0; i < items.length; i++) { var o:Object = items[i]; if (lastLevel < o.level){ o.parentIndex = i - 1; levelsObject["l" + o.level] = i; }else o.parentIndex = levelsObject["l" + o.level] - 1; if(o.parentIndex){ var parentSprite:TreeItem = items[o.parentIndex].sprite as TreeItem; if (parentSprite.hasChildren) items[o.parentIndex].childIndices.push(i); } lastLevel = o.level; } } private function draw():void { var iy:int = 0; for (var i:int = 0; i < items.length; i++) { var o:Object = items[i]; o.tweenY = iy; var item:TreeItem = o.sprite; if (o.visible) { item.visible = true; TweenLite.to(item, tweenDuration, { alpha:1, y:iy, ease:tweenEase } ); // Tween in visible items iy += ITEM_HEIGHT; }else { TweenLite.to(item, tweenDuration, { alpha:1, y:iy, ease:tweenEase, onComplete:hideItemSprite, onCompleteParams:[i] } ); // Set visible to false after tween out } } tweenMasks(); TweenLite.delayedCall(tweenDuration, afterTween); } private function afterTween():void { for each (var o:Object in items) o.sprite.mask = null; if(menuSprite.contains(contractMask)) menuSprite.removeChild(contractMask); if(menuSprite.contains(expandMask)) menuSprite.removeChild(expandMask); } private function tweenMasks():void { contractMask.width = expandMask.width = ITEM_WIDTH; menuSprite.addChild(contractMask); contractMask.y = 0; contractMask.height = 1; menuSprite.addChild(expandMask); expandMask.y = 0; expandMask.height = 1; var expandItems:Array = []; var contractItems:Array = []; if (itemsCopy) { for (var i:int = 0; i < items.length; i++) { if (items[i].visible != itemsCopy[i].visible) { if (items[i].visible) { expandItems.push(items[i]); items[i].sprite.mask = expandMask; // Mask expanding items }else { contractItems.push(items[i]); items[i].sprite.mask = contractMask; // Mask contracting items } } } if (expandItems.length > 0) { // Tween expand mask expandMask.y = expandItems[0].sprite.y; TweenLite.to(expandMask, tweenDuration, { y:expandItems[0].tweenY, height:expandItems.length * ITEM_HEIGHT, ease:tweenEase } ); } if(contractItems.length>0){ // Tween contract mask contractMask.y = contractItems[0].sprite.y; contractMask.height = contractItems.length * ITEM_HEIGHT; TweenLite.to(contractMask, tweenDuration, { y:contractItems[0].tweenY, height:0, ease:tweenEase } ); } } } private function hideItemSprite(index:int):void { items[index].sprite.visible = false; } private function expandIndex(index:int):void { var o:Object = items[index]; contractLevel(o.level); // Contract other nodes at the same level if (o.level > 0) expandIndex(o.parentIndex); // Expand parent nodes for (var i:int = 0; i < o.childIndices.length; i++) items[o.childIndices[i]].visible = true; // Show children on node invalidate(); } private function contractIndex(index:int):void { var o:Object = items[index]; for (var i:int = 0; i < o.childIndices.length; i++) { items[o.childIndices[i]].visible = false; contractIndex(o.childIndices[i]); // Contract all children } invalidate(); } private function contractLevel(level:int):void { for (var i:int = 0; i < items.length; i++) { if (items[i].level == level) contractIndex(i); } invalidate(); } private function contractAll():void { for each (var o:Object in items) { o.visible = o.level == 0 ? true : false; } invalidate(); } private function deselectAll():void { for each (var o:Object in items) { o.sprite.selected = false; } selectedIndex = -1; invalidate(); } private function selectIndex(index:int):void { deselectAll(); items[index].sprite.selected = true; selectedIndex = index; expandIndex(index); } private function selectFirstLeaf(index:int):void { if (items[index].childIndices.length > 0) { var o:Object = items[index]; var childIndex:int = o.childIndices[0]; items[childIndex].childIndices.length > 0 ? selectFirstLeaf(childIndex) : selectIndex(childIndex); }else { selectIndex(index); } } private function copyItems():void { itemsCopy = new Vector.<Object>(); for each (var o:Object in items) { itemsCopy.push({item:o.sprite, level:o.level, childIndices:o.childIndices, visible:o.visible } ); } } private function invalidate():void{ enterFrameSignal.addOnce(onInvalidate); } /*****************************************************************************************/ /* EVENT HANDLERS /*****************************************************************************************/ private function onInvalidate(e:Event):void{ enterFrameSignal.remove(onInvalidate); draw(); } private function onItemClick(e:MouseEvent):void { copyItems(); // Copy current items props deselectAll(); for (var i:int = 0; i < items.length; i++) { if (items[i].sprite == e.currentTarget) { if (items[i].childIndices.length > 0) { selectFirstLeaf(i); // Branch - open and select first leaf }else selectIndex(i); // Leaf - set selected } } } } } /*****************************************************************************************/ /* TREE ITEM CLASS /*****************************************************************************************/ import flash.display.*; import flash.events.*; import flash.text.*; import gs.TweenLite; import gs.easing.Expo; import gs.plugins.TweenPlugin; import gs.plugins.TintPlugin; import idv.cjcat.signals.NativeSignal; class TreeItem extends Sprite { private var _width:int = 250; private var _height:int = 25; private var _margin:int = 10; private var _indent:int = 25; private var _data:XML; private var _level:int; private var _selected:Boolean; private var _bgColor:uint = 0xCCCCCC; private var _frameColor:uint = 0xFFFFFF; private var _normalColor:uint = 0x666666; private var _overColor:uint = 0x888888; private var _selectedColor:uint = 0xCC0000; private var _selectedOverColor:uint = 0xFF0000; public var clickSignal:NativeSignal; private var enterFrameSignal:NativeSignal; private var tf:TextField; private var bg:Shape; private var frame:Shape; public function TreeItem(data:XML, level:int):void { mouseChildren = false; mouseEnabled = true; buttonMode = true; useHandCursor = true; enterFrameSignal = new NativeSignal(this, Event.ENTER_FRAME); clickSignal = new NativeSignal(this, MouseEvent.CLICK); clickSignal.add(onClick); new NativeSignal(this, MouseEvent.MOUSE_OVER).add(onMouseOver); new NativeSignal(this, MouseEvent.MOUSE_OUT).add(onMouseOut); frame = new Shape(); addChild(frame); bg = new Shape(); addChild(bg); tf = new TextField(); tf.x = _margin + level * _indent; tf.autoSize = TextFieldAutoSize.LEFT; tf.selectable = false; tf.defaultTextFormat = new TextFormat("Arial", 14, _normalColor, true); addChild(tf); this.data = data; } public function draw():void { tf.text = _data && _data.text() ? _data.text() : "---"; if (hasChildren) tf.text = "+ " + tf.text; tf.y = height / 2 - tf.height / 2; var tfm:TextFormat = tf.defaultTextFormat; tfm.color = selected ? _selectedColor : _normalColor; tf.setTextFormat(tfm); frame.graphics.clear(); frame.graphics.beginFill(_frameColor, 1); frame.graphics.drawRect(0, 0, width, height); frame.graphics.endFill(); bg.graphics.clear(); bg.graphics.beginFill(_bgColor, 1); bg.graphics.drawRoundRect(1, 1, width-2, height-2, 8); bg.graphics.endFill(); } private function invalidate():void{ enterFrameSignal.addOnce(onInvalidate); } /*****************************************************************************************/ /* EVENT HANDLERS /*****************************************************************************************/ private function onInvalidate(e:Event):void{ enterFrameSignal.remove(onInvalidate); draw(); } private function onClick(e:MouseEvent):void{ new TweenLite(tf, .2, {tint:null}); } private function onMouseOver(e:MouseEvent):void{ new TweenLite(tf, .2, {tint:selected ? _selectedOverColor : _overColor}); } private function onMouseOut(e:MouseEvent):void{ new TweenLite(tf, .2, {tint:null}); } /*****************************************************************************************/ /* GETTERS/SETTERS /*****************************************************************************************/ override public function set width(value:Number):void { _width = value; invalidate(); } override public function get width():Number { return _width; } override public function set height(value:Number):void { _height = value; invalidate(); } override public function get height():Number { return _height; } public function set data(value:XML):void { _data = value; invalidate(); } public function get data():XML { return _data; } public function set selected(value:Boolean):void { _selected = value; invalidate(); } public function get selected():Boolean { return _selected; } public function get hasChildren():Boolean { return data.item.length() > 0; } } Code Fullscreen Preview Fullscreen jimiwu ton_ tjoen alwAYs civet kleinschmidt.. andrewexex88.. xor bradsedito : cool accordion menu tree xml items invalidate index level childIndex value Object XML Date.parse Shape frame mask visible draw contains activate removeChild valueOf useHandCursor alpha sort new page view favorite forked pv0 forked from: XML Accordion Tre.. dowexworld forked:0 favorite:0lines:303 (diff:1)