Author: tink Date: Thu Jan 19 23:57:17 2012 New Revision: 1233697 URL: http://svn.apache.org/viewvc?rev=1233697&view=rev Log: Initial import of browse history classes for use with navigators
Added: incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/ incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/INavigatorBrowserManager.as incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManager.as incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManagerImpl.as Added: incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/INavigatorBrowserManager.as URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/INavigatorBrowserManager.as?rev=1233697&view=auto ============================================================================== --- incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/INavigatorBrowserManager.as (added) +++ incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/INavigatorBrowserManager.as Thu Jan 19 23:57:17 2012 @@ -0,0 +1,122 @@ +/* + +Copyright (c) 2011 Tink Ltd - http://www.tink.ws + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package ws.tink.spark.managers +{ + import ws.tink.spark.layouts.supportClasses.INavigatorLayout; + + /** + * The interface that the shared instance of the NavigtorBrowserManager + * implements, which is accessed with the <code>NavigtorBrowserManager.getInstance()</code> method. + * + * @see ws.tink.spark.managers.NavigtorBrowserManager + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public interface INavigatorBrowserManager + { + + + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // fragmentField + //---------------------------------- + + /** + * The portion of current URL after the '#' as it appears + * in the browser address bar, or the default fragment + * used in setup() if there is nothing after the '#'. + * Use setFragment to change this value. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function get fragmentField():String + /** + * @private + */ + function set fragmentField( value:String ):void + + + //---------------------------------- + // fragmentFunction + //---------------------------------- + + /** + * The portion of current URL after the '#' as it appears + * in the browser address bar, or the default fragment + * used in setup() if there is nothing after the '#'. + * Use setFragment to change this value. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + function get fragmentFunction():Function + /** + * @private + */ + function set fragmentFunction( value:Function ):void + + + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * Registers a layout so that it can be managed. + * + * @param value The INavigatorLayout to be registered. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + function registerLayout( value:INavigatorLayout ):void + + /** + * Unregisters a layout so that it is no longer managed. + * + * @param value The INavigatorLayout to be unregistered. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + function unRegisterLayout( value:INavigatorLayout ):void + } +} \ No newline at end of file Added: incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManager.as URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManager.as?rev=1233697&view=auto ============================================================================== --- incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManager.as (added) +++ incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManager.as Thu Jan 19 23:57:17 2012 @@ -0,0 +1,94 @@ +/* + +Copyright (c) 2011 Tink Ltd - http://www.tink.ws + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package ws.tink.spark.managers +{ + + import mx.core.Singleton; + + /** + * @private + * The NavigatorBrowserManager is a Singleton manager that acts as + * a proxy between the BrowserManager and INavigatorLayout instances + * added to it. + * + * <p>It updates the <code>fragment</code> property of the IBrowserManager + * when a registered INavigatorLayout changes its <code>selectedindex</code>, + * and also sets the <code>selectedIndex</code> of registered INavigatorLayout instances + * when the <code>fragment</code> property of the IBrowserManager changes. + * + * @see ws.tink.spark.managers.INavigatorBrowserManager + * @see ws.tink.spark.layouts.supportClasses.INavigatorLayout + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public class NavigatorBrowserManager + { + + + + //-------------------------------------------------------------------------- + // + // Class Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Linker dependency on implementation class. + */ + private static var implClassDependency:NavigatorBrowserManagerImpl; + + /** + * @private + */ + private static var instance:INavigatorBrowserManager; + + + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * Returns the sole instance of this Singleton class; + * creates it if it does not already exist. + * + * @return Returns the sole instance of this Singleton class; + * creates it if it does not already exist. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function getInstance():INavigatorBrowserManager + { + if( !instance ) instance = INavigatorBrowserManager( Singleton.getInstance( "ws.tink.spark.managers::INavigatorBrowserManager" ) ); + return instance; + } + } + +} Added: incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManagerImpl.as URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManagerImpl.as?rev=1233697&view=auto ============================================================================== --- incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManagerImpl.as (added) +++ incubator/flex/whiteboard/tink/navigators/src/ws/tink/spark/managers/NavigatorBrowserManagerImpl.as Thu Jan 19 23:57:17 2012 @@ -0,0 +1,591 @@ +/* + +Copyright (c) 2011 Tink Ltd - http://www.tink.ws + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and +to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +package ws.tink.spark.managers +{ + import flash.display.DisplayObjectContainer; + + import mx.core.IVisualElement; + import mx.events.BrowserChangeEvent; + import mx.events.FlexEvent; + import mx.managers.BrowserManager; + import mx.managers.IBrowserManager; + + import spark.components.DataGroup; + import spark.components.supportClasses.GroupBase; + import spark.events.IndexChangeEvent; + import spark.layouts.supportClasses.LayoutBase; + import spark.utils.LabelUtil; + + import ws.tink.spark.layouts.supportClasses.INavigatorLayout; + + [ExcludeClass] + /** + * @private + * The NavigatorBrowserManager is a Singleton manager that acts as + * a proxy between the BrowserManager and INavigatorLayout instances + * added to it. + * + * <p>It updates the <code>fragment</code> property of the IBrowserManager + * when a registered INavigatorLayout changes its <code>selectedindex</code>, + * and also sets the <code>selectedIndex</code> of registered INavigatorLayout instances + * when the <code>fragment</code> property of the IBrowserManager changes. + * + * @see mx.managers.IBrowserManager + * @see ws.tink.spark.layouts.supportClasses.INavigatorLayout + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public class NavigatorBrowserManagerImpl implements INavigatorBrowserManager + { + + + + //-------------------------------------------------------------------------- + // + // Class Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private static var _instance:NavigatorBrowserManagerImpl; + + + + //-------------------------------------------------------------------------- + // + // Class Methods + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + public static function getInstance():NavigatorBrowserManagerImpl + { + if( !_instance ) _instance = new NavigatorBrowserManagerImpl(); + return _instance; + } + + + + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function NavigatorBrowserManagerImpl() + { + super(); + + _browserManager = BrowserManager.getInstance(); + _browserManager.addEventListener( BrowserChangeEvent.BROWSER_URL_CHANGE, onBrowserManagerBrowserURLChange, false, 0, true ); + _browserManager.init("", ""); + + parseFrament(); + updateFragment(); + } + + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * Instance of the browser manager to be used. + */ + private var _browserManager:IBrowserManager; + + /** + * @private + * The list of layouts being managed. + */ + private var _layouts:Vector.<INavigatorLayout> = new Vector.<INavigatorLayout>(); + + /** + * @private + * The list of layouts that can still be parsed after a URL change. + */ + private var _layoutsToParse:Vector.<INavigatorLayout> = new Vector.<INavigatorLayout>(); + + /** + * @private + * The list of layouts to ignore their <code>FlexEvent.VALUE_COMMIT</code> events. + * When the index of a layout is changed, we want to ignore the value commit, if + * the layouts <code>selectedIndex</code> is the same as the index set. + */ + private var _layoutsToIgnore:Vector.<LayoutToIgnore> = new Vector.<LayoutToIgnore>(); + + /** + * @private + * A list of fragment parts that still need to be parsed. + */ + private var _fragmentsToParse:Array; + + + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // fragmentField + //---------------------------------- + + /** + * @private + * Storage property for fragmentField. + */ + private var _fragmentField:String; + + /** + * The portion of current URL after the '#' as it appears + * in the browser address bar, or the default fragment + * used in setup() if there is nothing after the '#'. + * Use setFragment to change this value. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get fragmentField():String + { + return _fragmentField; + } + /** + * @private + */ + public function set fragmentField( value:String ):void + { + if( _fragmentField == value ) return; + + _fragmentField = value; + updateFragment(); + } + + + //---------------------------------- + // fragmentFunction + //---------------------------------- + + /** + * @private + * Storage property for fragmentFunction. + */ + private var _fragmentFunction:Function; + + /** + * The portion of current URL after the '#' as it appears + * in the browser address bar, or the default fragment + * used in setup() if there is nothing after the '#'. + * Use setFragment to change this value. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get fragmentFunction():Function + { + return _fragmentFunction; + } + /** + * @private + */ + public function set fragmentFunction( value:Function ):void + { + if( _fragmentFunction == value ) return; + + _fragmentFunction = value; + updateFragment(); + } + + + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function registerLayout( value:INavigatorLayout ):void + { + if( _layouts.indexOf( value ) == -1 ) + { + value.addEventListener( FlexEvent.VALUE_COMMIT, onLayoutIndexChange, false, 0, true ); + _layouts.push( value ); + _layouts.sort( nestLevelCompareFunction ); + + _layoutsToParse.push( value ); + _layoutsToParse.sort( nestLevelCompareFunction ); + } + + if( _fragmentsToParse && _fragmentsToParse.length ) + { + parseFrament(); + } + else + { + updateFragment(); + } + } + + /** + * @inheritDoc + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function unRegisterLayout( value:INavigatorLayout ):void + { + const index:int = _layouts.indexOf( value ) + if( index != -1 ) + { + const l:INavigatorLayout = _layouts.splice( index, 1 )[ 0 ]; + l.removeEventListener( IndexChangeEvent.CHANGE, onLayoutIndexChange, false ); + } + + updateFragment(); + } + + + /** + * @private + * Sorts the layouts into order depending on th nestLevel (how deep they are in the displayList). + */ + private function nestLevelCompareFunction( a:INavigatorLayout, b:INavigatorLayout ):int + { + const at:GroupBase = LayoutBase( a ).target; + const bt:GroupBase = LayoutBase( b ).target; + + if( !at && !bt ) + { + return 0; + } + else if( !at ) + { + return 1; + } + else if( !bt ) + { + return -1; + } + else + { + return Math.min( 1, Math.max( -1, at.nestLevel - bt.nestLevel ) ); + } + } + + + /** + * @private + * Parses the fragments by looking for the correct layouts to select the index on. + */ + private function parseFrament( override:Boolean = true ):void + { + if( !_fragmentsToParse || !_fragmentsToParse.length ) return; + + var target:GroupBase; + var part:String; + var layout:INavigatorLayout; + var elements:Array; + + const numLayouts:int = _layoutsToParse.length; + for( var i:int = 0; i < numLayouts; i++ ) + { + part = _fragmentsToParse[ 0 ]; + layout = _layoutsToParse[ 0 ]; + target = LayoutBase( layout ).target; + + if( target ) + { + elements = getElements( target ); + var numElements:int = elements.length; + for( var e:int = 0; e < numElements; e++ ) + { + if( LabelUtil.itemToLabel( elements[ e ], fragmentField, fragmentFunction ) == part ) + { + // Remove both from their lists + _fragmentsToParse.splice( 0, 1 ); + _layoutsToParse.splice( 0, 1 ); + + // Make sure we ignore this layouts valueCommit. + _layoutsToIgnore.push( new LayoutToIgnore( layout, e ) ); + + layout.selectedIndex = e; + + if( _fragmentsToParse.length ) + { + break; + } + else + { + return; + } + } + } + } + } + } + + + + /** + * @private + * Util method to get a list of the items being rendrered. + * These could be visual items or data items. + */ + private function updateFragment():void + { + _layouts.sort( nestLevelCompareFunction ); + + var target:GroupBase; + var fragment:String = ""; + + var selectedElement:IVisualElement; + for each( var layout:INavigatorLayout in _layouts ) + { + target = LayoutBase( layout ).target; + + if( target ) + { + if( !selectedElement ) + { + selectedElement = layout.selectedElement; + fragment += getFragment( layout, target ); + } + // Make sure that this layouts target is a child of the + // previously selectedElement. + else if( selectedElement is DisplayObjectContainer && + DisplayObjectContainer( selectedElement ).contains( target ) ) + { + fragment += getFragment( layout, target ); + selectedElement = layout.selectedElement; + } + } + } + + if( _browserManager.fragment != fragment ) _browserManager.setFragment( fragment ); + } + + /** + * @private + * Util method to get a list of the items being rendrered. + * These could be visual items or data items. + */ + protected function getElements( target:GroupBase ):Array + { + if( target is DataGroup ) + { + return DataGroup( target ).dataProvider.toArray(); + } + else + { + try + { + return target[ "getMXMLContent" ](); + } + catch( e:Error ) + { + return target[ "toArray" ](); + } + catch( e:Error ) + { + throw new Error( "NavigatorLayoutBase cannot be used as a layout for this kind of container" ); + return new Array(); + } + } + + return new Array(); + } + + /** + * @private + * Util method get a framenet string for the selectedIndex. + */ + private function getFragment( l:INavigatorLayout, target:GroupBase ):String + { + const elements:Array = getElements( target ); + return LabelUtil.itemToLabel( elements[ l.selectedIndex ], fragmentField, fragmentFunction ) + "/"; + } + + + + //-------------------------------------------------------------------------- + // + // Event Listeners + // + //-------------------------------------------------------------------------- + + /** + * @private + * Invoked by the the URL is changed in the browser. + */ + private function onBrowserManagerBrowserURLChange( event:BrowserChangeEvent ):void + { + _layoutsToParse = _layouts.concat(); + + _fragmentsToParse = _browserManager.fragment.split( "/" ); + _fragmentsToParse.splice( _fragmentsToParse.length - 1, 1 ); + parseFrament(); + } + + /** + * @private + * Invoked when the selectedIndex changes in a layout. + */ + private function onLayoutIndexChange( event:FlexEvent ):void + { + const l:INavigatorLayout = INavigatorLayout( event.currentTarget ); + const numLayouts:int = _layoutsToIgnore.length; + + for( var i:int = 0; i < numLayouts; i++ ) + { + if( _layoutsToIgnore[ i ].layout == l && _layoutsToIgnore[ i ].selectedIndex == l.selectedIndex ) + { + _layoutsToIgnore.splice( i, 1 ); + return; + } + } + updateFragment(); + } + } +} + + + +import ws.tink.spark.layouts.supportClasses.INavigatorLayout; + +/** + * @private + * Util class used to store layouts whos valueCommit property + * we want to ignore due to use setting their selectedIndex. + */ +internal class LayoutToIgnore +{ + + + + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Constructor. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function LayoutToIgnore( layout:INavigatorLayout, selectedIndex:int ) + { + _layout = layout; + _selectedIndex = selectedIndex; + } + + + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // index + //---------------------------------- + + /** + * @private + * Storage property for selectedIndex. + */ + private var _selectedIndex:int; + + /** + * The selectedIndex that the NavigatorBrowserManager set on the layout. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function get selectedIndex():int + { + return _selectedIndex; + } + + + //---------------------------------- + // layout + //---------------------------------- + + /** + * @private + * Storage property for layout. + */ + private var _layout:INavigatorLayout; + + /** + * The layout that the NavigatorBroswerManager updated. + * + * @langversion 3.0 + * @playerversion Flash 10 + * @playerversion AIR 1.5 + * @productversion Flex 4 + */ + public function get layout():INavigatorLayout + { + return _layout; + } +} \ No newline at end of file