     
     //--------------------------------------------------------------------------
     // 
-    // Event Handlers
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     *  Helper function for checkScrollPositionsOnUpdateComplete.  
-     */
-    private function getMotionPathCurrentVelocity(mp:MotionPath,currentTime:Number,totalTime:Number):Number
-    {
-        // Determine the fraction of the effect that has already played.
-        var fraction:Number = currentTime / totalTime;
-
-        // Now we need to determine the effective velocity at the effect's current position.
-        // Here we use a "poor man's" approximation that doesn't require us to know any of the
-        // derivative functions associated with the motion path.  We sample the position at two
-        // time values very close together and assume the velocity slope is a straight line 
-        // between them.  The smaller the distance between the two time values, the closer the 
-        // result will be to the "instantaneous" velocity.
-        const TINY_DELTA_TIME:Number = 0.00001; 
-        var value1:Number = Number(mp.getValue(fraction));
-        var value2:Number = Number(mp.getValue(fraction + (TINY_DELTA_TIME / totalTime)));
-        return (value2 - value1) / TINY_DELTA_TIME;
-    }
-    
-    /**
-     *  @private 
-     */
-    private function checkScrollPositionsOnUpdateComplete(event:FlexEvent):void
-    {
-        viewport.removeEventListener(FlexEvent.UPDATE_COMPLETE, 
-            checkScrollPositionsOnUpdateComplete);
-        
-        var curVelocity:Point;
-        
-        // Determine the new maximum valid scroll positions
-        var maxVSP:Number = viewport.contentHeight > viewport.height ? 
-            viewport.contentHeight-viewport.height : 0; 
-        var maxHSP:Number = viewport.contentWidth > viewport.width ? 
-            viewport.contentWidth-viewport.width : 0;
-        
-        // Determine whether we possibly need to re-throw because of changed max positions.
-        var didNotThrowFarEnough:Boolean = throwReachedMaximumScrollPosition &&
-            (throwFinalVSP < maxVSP || throwFinalHSP < maxHSP);
-        var threwTooFar:Boolean = (throwFinalVSP > maxVSP || throwFinalHSP > maxHSP);
-
-        if (throwEffect && throwEffect.isPlaying && (didNotThrowFarEnough || threwTooFar))
-        {
-            // There's currently a throw animation playing, and it's throwing to a 
-            // now-incorrect position.  We're going to stop the animation and start
-            // a better one to continue the throw.
-            
-            var velX:Number = 0;
-            var velY:Number = 0;
-
-            // Get the current position of the existing throw animation
-            var effectTime:Number = throwEffect.playheadTime;
-
-            // It's possible for playheadTime to not be set if we're getting it
-            // before the first animation timer call.
-            if (isNaN(effectTime))
-                effectTime = 0;
-
-            var effectDuration:Number = throwEffect.duration;
-            
-            // Now get the current effective velocity for each motionpath in the animation. 
-            for (var t:int = 0; t < throwEffect.motionPaths.length; t++)
-            {
-                var vel:Number = getMotionPathCurrentVelocity(throwEffect.motionPaths[t], effectTime, effectDuration);
-
-                // The property can only either be horizontalScrollPosition or verticalScrollPosition
-                if (throwEffect.motionPaths[t].property == "horizontalScrollPosition")
-                    velX = vel;
-                else
-                    velY = vel;
-            }
-
-            // Stop the existing throw animation now that we've determined its current velocities.
-            stoppedPreemptively = true;
-            throwEffect.stop();
-
-            // Now perform a new throw to get us to the right position.
-            performThrow(-velX, -velY);
-        }
-        else if (!inTouchInteraction)
-        {
-            // No touch interaction is in effect, but the content may be sitting at
-            // a scroll position that is now invalid.  Note that performThrow will
-            // only actually perform a throw if the positions actually are invalid.
-            performThrow(0, 0);
-        }
-    }
-    
-    /**
-     *  @private 
-     */
-    private function viewport_propertyChangeHandler(event:PropertyChangeEvent):void
-    {
-        switch(event.property) 
-        {
-            case "contentWidth": 
-            case "contentHeight": 
-                invalidateSkin();
-                if (getStyle("interactionMode") == InteractionMode.TOUCH)
-                {
-                    // If the content size changed, then the valid scroll position ranges 
-                    // may have changed.  In this case, we need to schedule an updateComplete 
-                    // handler to check and potentially correct the scroll positions. 
-                    viewport.addEventListener(FlexEvent.UPDATE_COMPLETE, 
-                        checkScrollPositionsOnUpdateComplete);
-                }
-                break;
-        }
-    }
-    
-    /**
-     *  @private 
-     *  Listens for any focusIn events from descendants 
+    // Methods
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  Scrolls the viewport so the element is visible in the viewable area
+     *  Adjusts for focusThickness.
+     * 
+     *  @param element A descendant element of the Scroller  
      */ 
-    override protected function focusInHandler(event:FocusEvent):void
-    {
-        super.focusInHandler(event);
-        
-        // When we gain focus, make sure the focused element is visible
-        if (viewport && ensureFocusedElementIsVisible)
-        {
-            var elt:IVisualElement = focusManager.getFocus() as IVisualElement; 
-            lastFocusedElement = elt;
-            
-            if (elt)
-                scrollElementIntoView(elt);
-        }
-        
-    }
-    
-    /**
-     *  @private
-     *  Scrolls the viewport so the element is visible in the viewable area  
-     */ 
-    private function scrollElementIntoView(element:IVisualElement):void
+    public function ensureElementIsVisible(element:IVisualElement):void
     {   
+        // First check that the element is a descendant
+        // If we are a GraphicElement, use the element's parent
+        var possibleDescendant:DisplayObject = element as DisplayObject;
+        
+        if (element is IGraphicElement)
+            possibleDescendant = IGraphicElement(element).parent as DisplayObject;
+        
+        if (!possibleDescendant || !contains(possibleDescendant))
+            return;
+        
         var layout:LayoutBase = null;
         
         if (viewport is GroupBase)
             layout = GroupBase(viewport).layout;
         else if (viewport is SkinnableContainer)
             layout = SkinnableContainer(viewport).layout;
-     
+        
         if (layout)
         {
             // Scroll the element into view

     *  application to resize itself and fix the scroll position if necessary
     */ 
    private function softKeyboardDeactivateHandler(event:SoftKeyboardEvent):void
    {   
        // Adjust the scroll position after the application's size is restored. 
        adjustScrollPositionAfterSoftKeyboardDeactivate();
    }
    
    /**
     *  @private
     */ 
    mx_internal function adjustScrollPositionAfterSoftKeyboardDeactivate():void
    {      
        // If contentHeight is shorter than height, we no longer can scroll and we should reset to 0
        // If contentHeight is taller than height, make sure the position doesn't 
        // exceed the max scroll position
        
        if (viewport.contentHeight <= height)
            viewport.verticalScrollPosition = 0;
        else
            viewport.verticalScrollPosition = Math.min(viewport.verticalScrollPosition, viewport.contentHeight - height);
        
        if (viewport.contentWidth <= width)
            viewport.horizontalScrollPosition = 0;
        else
            viewport.horizontalScrollPosition = Math.min(viewport.horizontalScrollPosition, viewport.contentWidth - width);
    }


}


    private function softKeyboardActivateHandler(event:SoftKeyboardEvent):void
    {
        // Size of app has changed, so run this logic again
        var keyboardRect:Rectangle = stage.softKeyboardRect;
        
        if (keyboardRect.width > 0 && keyboardRect.height > 0)
        {
            if (lastFocusedElement && !isSoftKeyboardActive && ensureElementIsVisibleForSoftKeyboard)
                ensureElementIsVisible(lastFocusedElement);
            
            isSoftKeyboardActive = true;
        }
    }
    
    /**
