Skip to content

Commit

Permalink
Unified Model and Service into Actor. Updated demos to reflect.
Browse files Browse the repository at this point in the history
  • Loading branch information
darscan committed Oct 27, 2009
1 parent d153515 commit 7cc4e81
Show file tree
Hide file tree
Showing 29 changed files with 688 additions and 383 deletions.
Expand Up @@ -7,10 +7,10 @@ package org.robotlegs.demos.acmewidgetfactory.shell.model
import mx.modules.ModuleManager;

import org.robotlegs.demos.acmewidgetfactory.common.interfaces.IWidgetModule;
import org.robotlegs.mvcs.Model;
import org.robotlegs.mvcs.Actor;
import org.robotlegs.utils.NamedObjectMap;

public class ActiveWidgetModel extends Model
public class ActiveWidgetModel extends Actor
{
private static const MODULE_URL:String = 'org/robotlegs/demos/acmewidgetfactory/modules/widget/WidgetModule.swf';

Expand Down
Expand Up @@ -15,7 +15,7 @@ package org.robotlegs.demos.imagegallery.models
import org.robotlegs.demos.imagegallery.models.vo.GalleryImage;
import org.robotlegs.mvcs.*;

public class GalleryModel extends Model
public class GalleryModel extends Actor
{
private var _gallery:Gallery;

Expand Down
Expand Up @@ -20,9 +20,9 @@ package org.robotlegs.demos.imagegallery.remote.services
import org.robotlegs.demos.imagegallery.events.GalleryEvent;
import org.robotlegs.demos.imagegallery.models.vo.Gallery;
import org.robotlegs.demos.imagegallery.models.vo.GalleryImage;
import org.robotlegs.mvcs.Service;
import org.robotlegs.mvcs.Actor;

public class FlickrImageService extends Service implements IGalleryImageService
public class FlickrImageService extends Actor implements IGalleryImageService
{
private var service:FlickrService;
private var photos:Photos;
Expand Down
Expand Up @@ -27,15 +27,15 @@ package org.robotlegs.demos.flashgooglemaps.model.proxies
import flash.net.URLRequest;

import org.robotlegs.demos.flashgooglemaps.model.events.AssetLoaderProxyEvent;
import org.robotlegs.mvcs.Model;
import org.robotlegs.mvcs.Actor;

/**
* Proxy to load the xml content.
*
* @author Peter Lorent peter.lorent@gmail.com
*
*/
public class AssetLoaderProxy extends Model
public class AssetLoaderProxy extends Actor
{
//--------------------------------------------------------------------------
//
Expand Down
Expand Up @@ -22,20 +22,19 @@

package org.robotlegs.demos.flashgooglemaps.model.services
{
import org.robotlegs.mvcs.Service;
import org.robotlegs.demos.flashgooglemaps.model.events.GeoCodingServiceEvent;

import com.google.maps.services.ClientGeocoder;
import com.google.maps.services.GeocodingEvent;
import com.google.maps.LatLng;

import org.robotlegs.demos.flashgooglemaps.model.events.GeoCodingServiceEvent;
import org.robotlegs.mvcs.Actor;

/**
* A Service to get us some results from the Googlemaps API.
*
* @author Peter Lorent peter.lorent@gmail.com
*
*/
public class GeoCodingService extends Service
public class GeoCodingService extends Actor
{
//--------------------------------------------------------------------------
//
Expand Down
25 changes: 14 additions & 11 deletions GoogleMaps/web/FlashGoogleMaps.html
Expand Up @@ -12,15 +12,16 @@
// -->
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Include CSS to eliminate any default margins/padding and set the height of the html element and
the body element to 100%, because Firefox, or any Gecko based browser, interprets percentage as
the percentage of the height of its parent container, which has to be set explicitly. Initially,
don't display flashContent div so it won't show if JavaScript disabled.
-->
<style type="text/css" media="screen">
html, body { height:100%; }
body { margin:0; padding:0; overflow:auto; text-align:center; }
body { margin:0; padding:0; overflow:auto; text-align:center;
background-color: #ffffff; }
#flashContent { display:none; }
</style>

Expand Down Expand Up @@ -65,9 +66,11 @@
To view this page ensure that Adobe Flash Player version
10.0.0 or greater is installed.
</p>
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
</a>
<script type="text/javascript">
var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://");
document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='"
+ pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" );
</script>
</div>

<noscript>
Expand All @@ -77,25 +80,25 @@
<param name="bgcolor" value="#ffffff" />
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<!--[if !IE]>
<!--[if !IE]>-->
<object type="application/x-shockwave-flash" data="FlashGoogleMaps.swf" width="100%" height="100%">
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />
<param name="allowScriptAccess" value="sameDomain" />
<param name="allowFullScreen" value="true" />
<![endif]-->
<!--[if gte IE 6]>
<!--<![endif]-->
<!--[if gte IE 6]>-->
<p>
Either scripts and active content are not permitted to run or Adobe Flash Player version
10.0.0 or greater is not installed.
</p>
<![endif]-->
<!--<![endif]-->
<a href="http://www.adobe.com/go/getflashplayer">
<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
</a>
<!--[if !IE]>
<!--[if !IE]>-->
</object>
<![endif]-->
<!--<![endif]-->
</object>
</noscript>
</body>
Expand Down
Binary file modified GoogleMaps/web/FlashGoogleMaps.swf
Binary file not shown.
Binary file added GoogleMaps/web/assets/img/jos.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added GoogleMaps/web/assets/img/wild.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions GoogleMaps/web/assets/xml/content.xml
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<website>
<markers>
<marker headline="In de Wildeman, a famous beerpub" foto="wild.jpg" body="Situated in a former Amsterdam distillery, In de Wildeman offers an ideal opportunity to enjoy your beer in an authentic environment." lat="52.3761799" lng="4.8952004" stad="Amsterdam" adres="Kolksteeg 3"/>
<marker headline="Café Jos Meesterschenkerij" foto="jos.jpg" body="This pub is the 2009 number 1 pub in The Netherlands according to the official pub top 100! Be sure to visit this one." lat="51.8359761" lng="5.8781757" stad="Nijmegen" adres="Daalseweg 309"/>
</markers>
<contents>
<content type="how"><![CDATA[<font color='#b30d0d' size='21'>So, let's try and explain how everything works here.</font><br/><br/><font size='15px'>Remember, on github.com/darscan/robotlegs/tree/master you can read more about the framework.<br/><br/><span class='mbold'>First things first.</span><br/>The project is a FlashBuilder AS3-project using SDK4.0.0 build 7219. It is set to build in /web/assets/swf/ and opens the index.html in /web if you debug the project. The index.html embeds a loader.swf and it loads the swf we compile with FlashBuilder. The View (component) classes in the code embed graphical assets (movieclips) from fla files (Flash CS4). These are set to publish in src/main/flash/assets/swf/. If you change things in the fla's, compile in the Flash IDE and debug the project in FlashBuilder to see the changes. The Googlemap uses a custom marker. Its View class embeds a .png that resides in src/main/flash/assets/bitmaps/. One thing to mention: I used the word component. No, I don't mean a full fledged AS3 Component. In the context of the framework we merely use the word component to make a distinction between the Mediator and the view component it mediates.<br/><br/>The basic idea is to show how the framework is used to consume content like xml and a service. And (of course) how to set and change the state using events. On the Googlemap I show some pubs in our country with corresponding entries under the 'Tips' tab in the main navigation. Clicking on one of the markers triggers an event in the View component and its Mediator handles the event by calling the (Googlemaps API) service. The Mediator receives the result from the service and changes the state of the View component via its API. To demonstrate how to 'communicate' between the main content pane and the Googlemap (these two 'components' are obviously unaware of each other) the tips will 'trigger' an event when clicked and cause the Googlemap to change its state.<br/><br/>Within the main content pane the main navigation is a seperate component. It merely triggers an event when one of the tabs is clicked. The event carries an id and the Mediator that 'governs' the content view component uses this id to show the correct content from the xml.<br/><br/>Ok, that pretty much wraps it up. Last thing to mention: this is a work in progress so I'll probably refactor some things, so check back if you want to have the latest version. And now:</font><br/><br/><span class='link'><a href='event:showTips'>Show me the best pubs >></a></span>]]></content>
<content type="tips">
<tip text="Tip 1. Amsterdam - In de Wildeman, a famous pub with a nice collection of Belgian beers"/>
<tip text="Tip 2. Nijmegen - Café Jos. This pub is the number 1 pub on the hotlist!"/>
</content>
<content type="how"><![CDATA[<font color='#b30d0d' size='21'>Some words on how the code works.</font><br/><br/><br/><font size='15px'>Everything is a choice, right? I've just made some choices in the design to show how the framework does its job. For instance, in this demo I'm waiting for the Googlemap to broadcast its MapEvent.MAP_READY event before anything happens on the stage - see GoogleMapsView.handleEvent(). Only after that event fires, I'm loading the xml that contains the data for the markers, parse that data and animate the map to a position on the stage. 'onComplete' the main content pane moves to its final destination. It's only to show how to use the events from the framework to orchestrate what happens on the stage. So yes, if that MapEvent.MAP_READY doesn't fire, nothing will happen. In a real life website you would need to catch this and show some error message. Or opt for a different implementation all together for that matter.<br/><br/><span class='mbold'>Now, from the top.</span><br/>Ok, to get things working the framework requires some basic actors. One of the - in my opinion - nifty features of RobotLegs is that it 'listens' to what happens on the display list (later more on this). So the first thing you must provide is the container that holds all Sprites and Movieclips you want to put on the stage - see <span class='mbold'>FlashGoogleMaps.as</span> which is the 'Document class' of the project. You pass this information to what is known as the Context - see <span class='mbold'>FlashGoogleMapsContext.as.</span> The Context will initialize the framework. Next, you need to provide some information about your actors. Basically you map View components to their Mediators, map Commands to events (so things will happen when you want to) and... well, let's say save some stuff you can use later on in the code ('ask for' - for instance - Proxies and/or Services using the magic called Dependency Injection). When all of that is done, you fire a <span class='mbold'>ContextEvent.STARTUP</span> and... nothing happens. Here is where it starts to get interesting. Only when you add a Sprite to the display list, that is when things start happening. The framework detects the new child on the stage, provides the correct mediator and away we go. And once you are coding in RobotLegs you will experience why this is so freaking cool. Let's summarize the basic actors in this demo:<br/><br/>FlashGoogleMaps.as - serves as the Document Class<br/>FlashGoogleMapsContext.as - initializes the framework<br/>PrepViewCommand.as - map View components to Mediators<br/>PrepModelCommand.as - 'save' the model parts we will need<br/>PrepControllerCommand - map some Commands to events<br/>StartupCommand.as - add some Sprites to fire up this thing.<br/><br/><span class='mbold'>The Views and Mediators.</span><br/>Ok, with the basic actors in place we can add our Views and do something with the Model. As said, I'm dropping a GoogleMapsView on the stage. The framework detects this action and automatically provides the GoogleMapsMediator thanks to the mapping we did. Have a look at the GoogleMapsMediator. It listens for the GoogleMapsView.GOOGLEMAP_READY event fired by the GoogleMapsView. Once that events fires, handleGoogleMapReady() gets called and that's when I load the xml-file that contains the data for the markers and all other content. To load the xml (a Model related job) we dispatch an event that is mapped to the LoadXMLCommand. The GoogleMapsMediator obviously wants to know when the xml is loaded so it registers for AssetLoaderProxyEvent.XML_CONTENT_LOADED which will be fired by AssetLoaderProxy. Once the event fires handleXMLContentLoaded() modifies GoogleMapsView via its API. And that - basically - is it!<br/><br/>Ok, that was way more than 'some words', but you have to agree it's easy stuff and all you need to know to start coding with RobotLegs. Yes, there is more but once you are on your way you will discover and learn the more involved aspects of the framework.</font>]]></content>
<content type="how"><![CDATA[<font color='#b30d0d' size='21'>How about the nitty gritty?</font><br>
<font size='15px'>We have the basics covered and the purpose of this demo is to show just how easy it is to work with RobotLegs, but maybe I should explain some design choices in the code.<br/><br/><span class='mbold'>The Mediators.</span><br/>I could have done the demo with three Mediators:<br/><br/>GoogleMapsMediator, ContentViewMediator, TabViewMediator, mediating the three 'major' views in the demo.<br/><br/>In this setup the ContentView, representing the content pane, could listen to events from its view parts (PlainTextView and TipView(s)) and let the ContentMediator handle those events. Let's look at the tips. What we need here is that a click on the tip makes the Googlemap zoom in on the location and show the lay over with some information on the selected pub. The ContentView must listen for the event from the TipView(s) and let its Mediator know about this so the framework can notify the GoogleMapsMediator of the request. Let's say this works but it clutters the code in the ContentView. In comes that nifty feature again where RobotLegs detects new children on the stage. The moment the ContentView adds TipView(s) to the display list, RobotLegs makes sure there is a Mediator (provided we did the mapping!). This makes sense right? The dynamically created TipViewMediators now handle the click event and 'directly' inform the GooglemapsMediator. And yes, if we remove a child, RobotLegs removes the associated Mediator for us.<br/><br/>So, what about a Mediator for the SmartInfoWindow? I'll leave that up to you if you don't mind.<br/><br/><span class='mbold'>The content.</span><br/>There are so many ways to parse, save and distribute the (xml) content and it is beyond the scope of this demo to discuss this. I decided to use VO's for the markers on the Googlemap because this makes it much easier to work with (this is pretty much the way I would handle a result from a remoting gateway). Yes, you can also skip the VO stuff all together and just parse the tips in the GoogleView, or whatever approach you feel comfortable with. One thing to note on my VO approach: it is not really the Mediator way of doing things. You should be able to (re)use the view component as is in another project. Meaning, using its API, provide it with data and be done with it. The dependency on the VO's prevents this. Just so you know.<br/><br/><span class='mbold'>The events.</span><br/>I can hear you thinking, 'do we need all these events'? Technically, no. You could do with a generic event that can carry optional data. Downside: it means casting stuff all over the place and that's one of the things RobotLegs is not promoting. Bottom line: it's a matter of choice.<br/><br/><span class='mbold'>Final words.</span><br/>Found any flaws in the code? You know a better way to do things? Let me know. Join the RobotLegs AS3 Discussion Group, http://groups.google.com/group/robotlegs, and drop a message.<br/>I hope this demo helped you to get going with RobotLegs in a Flash AS3 environment. And I wish you happy coding!</font>]]></content>
</contents>
</website>
10 changes: 5 additions & 5 deletions GoogleMaps/web/index.html
Expand Up @@ -16,11 +16,11 @@
<meta name="author" content="" />
<meta name="formatter" content="" />

<link rel="stylesheet" type="text/css" href="./assets/css/flash.css" />
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="assets/css/flash.css" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />

<!-- Configuration -->
<script type="text/javascript" src="./assets/js/swfobject.js"></script>
<script type="text/javascript" src="assets/js/swfobject.js"></script>

</head>
<body class="fullscreen">
Expand All @@ -34,9 +34,9 @@ <h1></h1>
<script type="text/javascript">
// <![CDATA[
swfobject.embedSWF(
"./loader.swf", "flash_container",
"loader.swf", "flash_container",
"100%", "100%",
"10.0.0.0","./assets/swf/expressinstall.swf",
"10.0.0.0","assets/swf/expressinstall.swf",
{}, // flashvars
{scale:"noscale"}, // params
{}, // attributes
Expand Down

0 comments on commit 7cc4e81

Please sign in to comment.