robotlegs/robotlegs-framework — Issue #66: Mediators and Reparenting
Author: Stray
Created: 2012-02-02 21:37:01+00:00
State: open

### Background: the Robotlegs 1 'wait one frame' strategy

In Robotlegs 1, the MediatorMap employed a strategy of 'waiting for 1 frame' to check that a view really had been removed from the display list, before cleaning up its mediators.

In addition, when a view was passed to the mediatorMap to be mediated, we first checked that it wasn't one with a mediator marked for removal by the system. In this way, if a view was added and removed within a frame - usually by being reparented - its mediator would persist.

The reason for this was primarily that Flex 3 Scrollable Containers can do reparenting behind your back (they secretly remove and add items when you cross the threshold for needing the scrolling to be activated).

The Flash TileList component also does this sneaky reparenting during scrolling. Items still in view can be reparented when any other item is introduced to the view area.

There was a small but important bug in the RL1 process - it was possible to get false positives on the eventMap when your mediator was loitering for a frame. We now have a robust workaround for this bug: suspending / resuming eventMap activity within the mediator itself when the view is removed / added.

### What *should* happen when a view is reparented?

Let's assume for a moment that it's possible to employ a much more specific bug-fix for the known scrollable container problems, and that we can provide fixes for any similar problems emerging future. Or that we exclude those components from the game completely - perhaps by specifying Flex 4, and saying that contents of TileLists can't be mediated.

#### Are there scenarios in which reparenting shouldn't cause the mediator to be destroyed and a new one created?

A use case: a column-based UI in which the user can drag parts of the UI from one column to another.

It's common to have to attach a component to a higher 'layer' during dragging and then snap it back to the lower layer in which it normally lives when the drag is complete. If the initialize function in your Mediator also populates it in some way, you might not want that process to be repeated.

#### Are there scenarios in which reparenting should cause the mediator to be destroyed and a new one created?

##### 1. Switching 'context'

In Robotlegs 2, rather than having one enormous context view, you can target specific DisplayObjectContainers to be monitored for added / removed events. If you reparented the view in question into a DOC which has a different set of MediatorMap rules applied, or is outside of the scope of the current MediatorMap, your mediator should probably be cleaned up.

In the case of moving to a new 'context view', that context may have a different eventDispatcher to the one referenced in the eventMap inside your mediator and so on.

##### 2. Same context, but simple state inconsistencies

I'm a 'mediators-don't-hold-state' person myself, but let's assume for a moment that you've got a reason to hold a reference to the view's parent in the mediator. When the view is reparented, that parent might change.

### Guards and hooks make things more complicated

Should your mediator persist or vanish if your view would no longer pass your guards, and all you've done is drag it around? Possibly you've even dragged the item and returned it to the place where it was originally.

Of course this would probably be a sign that you've written your guards in a strange way, but - leaving guards aside - should any hooks be reapplied? You could write all your hooks with their own internal guard clauses (and in many cases this will be necessary - you'll need to cache which views you've already skinned so that you don't keep reskinning them over and over). But all of this is potentially inefficient.

### The crux: what's the most common 'least surprising' strategy for managing reparenting?

Here's a proposal - to which we'd like your responses. It really is only a draft attempt to figure out the least annoying strategy to employ. Inevitably any strategy will sometimes be incorrect - so the aim is to make it right more often that it's wrong, and ensure it can be overridden in those cases.

The most important thing is that the strategy is easy to understand - developers need to know what to expect from the framework.

1. The default behaviour is that if a view item is reparented and remains within the contextView that it was originally mediated in, nothing will happen. This is a 'local' reparenting. The mediator(s) will persist.

2. If a view item is reparented outside of the contextView that it was originally mediated in, the mediator(s) will be destroyed and new mediators will be created, guards permitting, and hooks will be reapplied. This __cannot be overridden by the mediator__ because the scope of the eventMap and other injections may no longer be valid.

3. If you want guards/hooks to be reapplied during local reparenting, or you want your mediator to be cleaned up and re-initialised during local reparenting, specify this in your mediator by setting `destroyOnReparent = true;`.

4. We'll abstract the reparenting strategy itself into a class _(whoop! strategy pattern!)_ so that if you want to dictate your own very specific strategy, there's a simple entry-point to do that.

### Please share your reactions, questions and thoughts - thanks!