Basic Structure of a Flash Website [AS2] · Dec 29, 12:28 AM

One of the most important considerations when creating a Flash Website is how to properly structure the site. The AllFlashWebsite.com (AFW) technique combines several open-source and freely available tools for a solution that is easy to maintain, and simple. To make it work, these are the tools we need: SWFObject, SWFAddress, and TextPattern. SWFObject uses JavaScript to embed your Flash movie into the web page, and is preferred over the automatically generated HTML by Flash gurus everywhere. SWFAddress enables deep linking which allows your visitors to bookmark your flash website, or use the back/forward buttons while browsing. SWFAddress is also essential if you want to achieve effective search engine optimization (SEO). Lastly, Textpattern is an open-source content management system (CMS), written in PHP. Textpattern is a good choice because of it’s simplicity and ease of customization, however the AFW technique is possible with almost any CMS you would like to use.

See the AFW demo here

Applicability

If you are reading this and are unsure whether an AFW-esque approach is correct for what you are trying to accomplish, please read about each tool: SWFAddress, SWFObject, Textpattern. Also consider whether you are interested in using a web-based editor for editing your Flash XML content, or publishing an RSS feed, or allowing visitors to print your web pages nicely, or providing a search box. All of these features are easily possible with this technique.

We will be publishing in Flash version 8, with ActionScript 2.0. Optionally, you can download SWFAddress for AS1.0 or AS3.0 that should allow you to achieve the same thing, however the code in this article has not been tested with these other versions.

Overview

The goal of this article is to create the simplest Flash website with deep linking, SEO, and CMS back-end. We must create a movie called main.swf which will have a preloader that loads in the media for our miniature website. The media will all be in just one file, home.swf. Then we will install Textpattern, and combine SWFAddress and Textpattern by modifying the index.php file installed with Textpattern.

Necessary Files

  • 2 Flash Movies: main.swf and home.swf
  • 3 ActionScript files: SWFAddress.as, AFWLoader.as, and SWFAddressEvent.as
  • 3 JavaScript files: swfaddress.js, swfaddress-optimizer.js, and swfobject.js
  • 3 images: home.jpg, about.jpg, contact.jpg

Download all the files here

If you’re having trouble modifying your index.php as described later, you can download an already-modified version. However, it’s possible that this index.php is taken from a different version of TextPattern than the one you chose to install.

Download TextPattern’s index.php modified for SWFAddress

The Main Movie: main.swf

The preloader for this project is called AFWLoader. We place an instance of the AFWLoader movie on our stage called loader_mc and resize it to take up the entire stage. Then, just invoke the loader_mc.loadMovie(…) function to load home.swf.

loader_mc.loadMovie("home.swf", "home", path);

The second argument specifies the name assigned to the new MovieClip. The new MovieClip is a child of loader_mc and can be accessed with:

loader_mc["home"]

We will call the loader_mc.loadMovie() function repeatedly from main.swf with the same first two arguments, but the movie only gets downloaded the first time. Every time you call loadMovie(), loader_mc will call the function loader_mc[“home”].setPath(path). setPath() is a function that we will need to create, it actually does most of the work in the home movie. The path argument is an array that specifies the content we are loading. For the URL http://www.allflashwebsite.com/demo/about/, the path argument will be a one-element array where the first element equals “about”.

Now lets write the code for main.swf. We will place this code in the second frame of the main timeline in a layer called actions:

  1. stop();
  2.  
  3. // returns an array, eg: /eat/menu/fried/ returns ('eat','menu','fried')
  4. // note: there must be a beginning and trailing slash (/)
  5. function extractPaths(str) {
  6. str = str.substr(1,str.length - 2);
  7. return str.split('/');
  8. }
  9.  
  10. // SWFAddress calls this function when the address changes
  11. // (2 Ways: The Browser's address bar , or SWFAddress.setValue())
  12. function handleChange(event:SWFAddressEvent) {
  13. var path = extractPaths(event.path);
  14. loader_mc.loadMovie("home.swf", "home", path);
  15.  
  16. // Set the title bar text
  17. var flink = (path[0] eq '') ? '' : ': ' + path.join(" / ") + '';
  18. SWFAddress.setTitle('AFW' + flink);
  19. }
  20. SWFAddress.addEventListener(SWFAddressEvent.CHANGE, handleChange);
  21. Download this code: /files/code1.1.txt

Notice that nothing happens until the handleChange() function gets invoked. SWFAddress will automatically call handleChange() when the movie is initially loaded, or when a visitor presses the back/forward buttons of their web browser. Furthermore, every time the user clicks on link within home.swf, we will purposefully, but indirectly invoke handleChange() by calling SWFAddress.setValue(”/section/”).

The Content Movie: home.swf

Screenshot of home.swf Movie Timeline
p. The home movie represents all the content in our website. To keep it simple, we will use AFWLoader again to load in the content for each section of the site. The content will be three different JPEG image files, one for each section:

  • home.jpg for the “/” (default) section
  • about.jpg for the “/about” section
  • contact.jpg for the “/contact” section

Keep in mind that the images could just as easily be SWF files and the code would be the same except for the file names.

We create some buttons for the navigation system that look like this:

Screenshot of home.swf Stage

Now, we need some code in the first frame of the main timeline. Any time you use AFWLoader, the setPath() function must be in the first frame of the target movie (home.swf, in this case). Make sure you understand this code and how this approach differs from the way you usually structure the interactivity in your flash movie flies.

  1. stop();
  2.  
  3. // linkTo corresponds to labels in the "actions" layer
  4. blogitty_btn.linkTo = "home";
  5. about_btn.linkTo = "about";
  6. contact_btn.linkTo = "contact";
  7.  
  8. blogitty_btn.onPress = buttonClick
  9. about_btn.onPress = buttonClick;
  10. contact_btn.onPress = buttonClick;
  11.  
  12. // Event handler for buttons
  13. function buttonClick() {
  14. link = this.linkTo eq "home" ? "" : this.linkTo;
  15.  
  16. if (link ne "") {
  17. SWFAddress.setValue('/'+link+'/');
  18. } else {
  19. SWFAddress.setValue('/');
  20. }
  21. }
  22.  
  23. // This function gets called by:
  24. // buttonClick() -> SWFAddress.setValue() -> _level0.handleChange() -> AFWLoader.loadMovie() -> setPath()
  25. // ... or when the page is loaded via the address bar (or back/forward button is pressed)
  26. // _level0.handleChange() -> AFWLoader.loadMovie() -> setPath()
  27. function setPath(path_arr) {
  28. link = path_arr[0] eq "" ? "home" : path_arr[0] ;
  29. url = "images/"+link+".jpg";
  30. loader_mc.loadMovie(url, link);
  31. }
  32. Download this code: /files/code1.2.txt

Whenever a button click occurs, SWFAddress.setValue() gets invoked. The action is not actually processed until setPath() gets called. setPath() is the all-purpose event handler that allows an event to be processed in the same way whether it’s initiated through the address bar, back/forward button, or a button click.

Testing

You should now be able to test your site from the Flash development environment. Open main.fla and press Ctrl+Enter. You should be able to navigate your site. However, you won’t be able to confirm that deep-linking is fully functional until you test your movie in the web browser.

Dive into Texpattern

Everything up to this point has already been done for you. You can just download this article’s .zip file which contains all the .fla/.swf/.as/.js files that you need. However, setting up TextPattern is going to require a little bit more effort. By effort I mean that you will have to transfer some files via FTP, create a MySql database, and copy-and-paste some code.

Install Textpattern

First download textpattern here then simply follow the instructions. Installing Textpattern is really very easy, as long as you know how to create a new MySQL database on your web server. Most commercial web-hosts provide this function in their control panel. However, if you can’t figure it out, just contact tech support.

Modify Textpattern’s index.php

We need to add code to Textpattern’s index.php to make it work with SWFAddress. The following code is a combination of fragments cut-and-pasted from some of the sample code distributed with SWFAddress (\samples\seo). Insert this code immediately after <?php in your index.php file:

  1. //
  2. //
  3. // SWFAddress -- Modified for TextPattern by Pickle
  4. //
  5. //
  6.  
  7. // SWFAddress code fully compatible with Apache HTTPD
  8.  
  9. session_start();
  10.  
  11. $base = substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
  12.  
  13. if ('application/x-swfaddress' == (isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] :
  14. (isset($_SERVER['HTTP_CONTENT_TYPE']) ? $_SERVER['HTTP_CONTENT_TYPE'] : ''))) {
  15. $_SESSION['swfaddress'] = $_SERVER['QUERY_STRING'];
  16. echo('location.replace("' . $base . '/#' . $_SERVER['QUERY_STRING'] . '")');
  17. exit();
  18. }
  19.  
  20. $swfaddress = '/';
  21.  
  22. if (isset($_SESSION['swfaddress'])) {
  23. $swfaddress = $_SESSION['swfaddress'];
  24. unset($_SESSION['swfaddress']);
  25. } else {
  26. $page = substr($_SERVER['PHP_SELF'], strrpos($_SERVER['PHP_SELF'], '/') + 1);
  27. $swfaddress = str_replace($base, '', (strpos($page, '.php') && $page != 'index.php') ? $_SERVER['REQUEST_URI'] : str_replace($page, '', $_SERVER['REQUEST_URI']));
  28. }
  29. $swfaddress = preg_replace('/^([^\?.]*[^\/])(\?|$)/', '$1/$2', $swfaddress, 1);
  30.  
  31. $query_string = (strpos($swfaddress, '?')) ? substr($swfaddress, strpos($swfaddress, '?') + 1, strlen($swfaddress)) : '';
  32. $swfaddress_path = ($query_string != '') ? substr($swfaddress, 0, strpos($swfaddress, '?')) : $swfaddress;
  33. $swfaddress_parameters = array();
  34.  
  35. if (strpos($swfaddress, '?')) {
  36. $params = explode('&', str_replace($swfaddress_path . '?', '', $swfaddress));
  37. for ($i = 0; $i < count($params); $i++) {
  38. $pair = explode('=', $params[$i]);
  39. $swfaddress_parameters[$pair[0]] = $pair[1];
  40. }
  41. }
  42.  
  43. if (strstr(strtoupper($_SERVER['HTTP_USER_AGENT']), 'MSIE')) {
  44.  
  45. $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
  46. preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE']) : '';
  47.  
  48. $file_last_modified = filemtime($_SERVER['PATH_TRANSLATED']);
  49. $gmdate_modified = gmdate('D, d M Y H:i:s', $file_last_modified) . ' GMT';
  50.  
  51. if ($if_modified_since == $gmdate_modified) {
  52. if (php_sapi_name() == 'cgi') {
  53. header('Status: 304 Not Modified');
  54. } else {
  55. header('HTTP/1.1 304 Not Modified');
  56. }
  57. exit();
  58. }
  59.  
  60. header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
  61. header('Last-Modified: ' . $gmdate_modified);
  62. header('Cache-control: max-age=' . 86400);
  63. }
  64.  
  65. function swfaddress_optimizer($resource, $flashver) {
  66. global $swfaddress, $base;
  67. echo($base . $resource . (strstr($resource, '?') ? '&amp;' : '?') . 'swfaddress=' . urlencode($swfaddress) . '&amp;base=' . urlencode($base) . '&amp;flash=' . urlencode($flashver));
  68. }
  69.  
  70. //
  71. //
  72. //
  73. // END OF SWFADDRESS
  74. //
  75. //
  76. Download this code: /files/code1.3.txt

TextPattern Admin Settings

Login to TextPattern and navigate to Admin / Preferences. Change the Permanent link mode to /section/title.

Create TextPattern Page: default

Now that you’re logged into TextPattern, navigate to the Presentation tab, and the Pages sub-tab. Page default should be selected by default. Replace the code with the following and save:

  1. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  2.  
  3. <head>
  4. <txp:output_form form="static_head_swfopt" />
  5. <title>AFW Demo</title>
  6. <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  7. <txp:output_form form="static_head_swf" />
  8. </head>
  9.  
  10. <body bgcolor="#ffffff">
  11. <div id="content">
  12. This is the homepage. Here are links to sections:<br>
  13. <a href="about">About</a><br>
  14. <a href="contact">Contact</a><br>
  15. </div>
  16.  
  17. <txp:output_form form="static_swfscript" />
  18.  
  19. <txp:output_form form="static_urchin" />
  20. </body>
  21. </html>
  22.  
  23. Download this code: /files/code1.4.txt

Create TextPattern Page: basic

After saving default, where it says “copy page as”, enter basic, then click copy. Replace the code with the following and save:

  1. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  2.  
  3. <head>
  4. <txp:output_form form="static_head_swfopt" />
  5. <title>AFW Demo</title>
  6. <txp:output_form form="static_head_swf" />
  7. </head>
  8.  
  9. <body bgcolor="#ffffff">
  10. <div id="content">
  11. <txp:article form="basic" />
  12. </div>
  13. <txp:output_form form="static_swfscript" />
  14. <txp:output_form form="static_urchin" />
  15. </body>
  16.  
  17. </html>
  18.  
  19. Download this code: /files/code1.5.txt

Create TextPattern Form: static_head_swfopt

Click on the Forms sub-tab, then click Create new form. Name the form static_head_swfopt chose Type article, enter the following code and click Save.

  1. <script type="text/javascript" src="<txp:php>swfaddress_optimizer('/swfaddress-optimizer.js',8);</txp:php>"></script>
  2. Download this code: /files/code1.6.txt

Create TextPattern Form: static_head_swf

Click Create new form. Name the form static_head_swf chose Type article, enter the following code and click Save.

  1. <script type="text/javascript" src="swfobject.js"></script>
  2. <script type="text/javascript" src="swfaddress.js"></script>
  3. <style type="text/css">
  4. /* hide from ie on mac \*/
  5. html {
  6. height: 100%;
  7. overflow: hidden;
  8. }
  9. #content {
  10. height: 100%;
  11. }
  12. #content div {
  13. margin: 10px;
  14. }
  15. /* end hide */
  16. body {
  17. height: 100%;
  18. margin: 0;
  19. padding: 0;
  20. background-color: #ffffff;
  21. text-align: center;
  22. }
  23. </style>
  24. Download this code: /files/code1.7.txt

Create TextPattern Form: static_swfscript

Click Create new form. Name the form static_swfscript chose Type article, enter the following code and click Save.

  1. <script type="text/javascript">
  2. // <![CDATA[
  3. var so = new SWFObject("main.swf", "main", '100%', '100%', '8', '#ffffff', 'high');
  4. so.addParam("align", "middle");
  5. so.addParam("scale", "noscale");
  6. so.useExpressInstall('expressinstall.swf');
  7. so.write("content");
  8. // ]]>
  9. </script>
  10.  
  11. Download this code: /files/code1.8.txt

Create TextPattern Form: static_urchin

Click Create new form. Name the form static_urchin chose Type article, enter the following code and click Save.

  1. <script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
  2. <script type="text/javascript">
  3. _uacct = "UA-2952508-2";
  4. urchinTracker();
  5. </script>
  6. Download this code: /files/code1.9.txt

Create Textpattern Sections

Click the Sections sub-tab, and create two new sections: about and contact. For both sections, chose page basic, style default, and then options No, No, No, Yes.

By default, there should already be a section called article. Leave this section as-is.

Create SEO and Alternate Content

Navigate to the Content tab and Write sub-tab. Now create three articles with the following values:

  • Title: First Article
  • Article image: images/home.jpg
  • Section: article
  • Body: This is the first and only article in the article section. Because of the way the article section is setup, this article will show up on the homepage.

  • Title: About
  • Article image: images/about.jpg
  • Section: about
  • Body: This article is in the about section.

  • Title: Contact
  • Article image: images/contact.jpg
  • Section: contact
  • Body: This article is in the contact section.

Testing your Site

In order to test your website, you need a way to view the content that incompatible browsers and search-bots will see. Some mobile phone browsers will allow you to view the non-flash content. Also, the Lynx and Links text-only browsers should work.

Conclusion

The site we end up with at this point is really minimal. We’ve stopped just short of a full-featured AFW implementation. However, we have completed the basic steps to build any flash website. What we have yet to do is take full advantage of the Textpattern content management system and eliminate the duplication of content required for Flash SEO and support of incompatible browsers. Things will really start to get interesting in the next article when we focus on marrying Flash and Textpattern using XML. Taking this next step is relatively easy and will make your Flash coding life much easier.

Additional Links

SWFAddress README File

— Pickle

---

Comment

  1. I’m trying to open your demo files, and I get an Unexpected File Format error in Flash 8 when I try to open the 2 FLA files…any help?

    Josh · May 15, 05:21 AM · #

  2. Sorry about that Josh. Looks like I forgot to include the Flash 8 source files. (Only the CS3 files are included). I will upload the correct files in a couple of days. In the mean time, you can download the AFW Template or AFW Template, CASA Release For a more complete example. (fyi: CASA release is better) They should both include the Flash 8 source files.

    Pickle · May 15, 09:12 PM · #

  3. I’ve updated the archive, please re-download. Thanks!

    Pickle · May 17, 06:04 AM · #

  4. Thank you for sharing! I was looking for this!
    I am trying to find out how your code works, but one thing I don’t understand: how come you don’t need an #include statement for the separate AS files? How does Flash know it has to include this external code when compiling? I know this is a silly question, but I really don’t understand.
    Thanks again!

    Liflaf · Jun 16, 09:15 AM · #

  5. Liflaf, The import statement is not necessary when the class file being included exists in the same folder as the file that is doing the including. The compiler knows where to look because the file name is always the same as the class name (with .as appended, of course)

    Pickle · Jun 17, 09:44 PM · #

  6. Thanks for the information, Pickle!

    Liflaf · Jun 18, 08:39 AM · #

Textile Help