Case Study (BMW Performance Parts and Accessories)

Introduction

The task set, was to create a website that would serve as an online catalog for BMW accessories and performance parts, categorized according to car model. The client also wanted to present general information about his services, contact information and to have the ability to display news on the front page. The site needed to be easy to update, searchable and indexable by search engines. After initial planning and agreeing on a design, it took us 2 days to create a fully functional fCMSPro website starting from Adobe Photoshop mock-ups.

Website URL: http://fcmspro.com/demo/bmw/
SWF File Size: 109Kb

The full source is available to fCMSPro customers.

Planning

There are three document types that were needed:
  1. 'item' - The document type for presenting items from the catalog. Each item needs to be defined with: title, description and image. Later, if required we could add fields like price, code, etc. We also need to categorize each item by tagging it with appropriate car model.
  2. 'news' - The document type for presenting news on the front page. Title, text content and possibly date and excerpt fields are needed.
  3. 'common' - The document type for displaying general information ('About Us' and 'Contact' page)
The designer also planned different headers for each section of the site, so we also need an additional document type 'header' that will allow the client to change the image and title on top of each section. The rest of the editable content is 'static' (not belonging to any document). This includes these elements on the front page: homeHeadline(fString), homeDetail(fString), homeImage(fImage) and banner(fimage).

Implementation

First, we need to define tags for categorizing items. Tags are created in a separate administration panel (found at fCMSBackend/admin/ URL)


The main timeline looks like this:

Note, that fCMSPro is made with the timeline in mind, but the positioning of elements is flexible and timeline could look different (there are no strict limitations on template positioning )

The Actionscript on frame 1 is a standard preloading script. When preloading is finished, the playhead will jump to frame 5 where the fMaster component resides. This is where the fCMSPro is initialized, consequently most of the code is on that frame.

We will use the fMenu component for the main navigation. This component can also display dynamic data, by connecting to the fCMSBackend. The first level of the fMenu is defined by a component parameter, and the second level is dynamically built using tag information.

stop();
// set properties of mask that appears when documents are edited ( ARGB Color, Blur Amount )
fMaster.setMaskProperties( 0xff00000, 2 )

// hide page elements until fcms is initialized
logo._visible = false;
fMenu._visible = false;
search_btn._visible = false;
search_txt._visible = false;

// subscribe to fcmsInit event
fMaster.addEventListener( "fcmsInit", this );
// fcmsInit event is triggered when tag and doctype information is loaded (used when working with doc relations)
function fcmsInit( eo:Object )
{

// if first parameter of fMenu.addBranch method is number
// nodes will copy tag tree of a tag with same id
// second parameter defines position of a node in fMenu tree where branch needs to be added
fMenu.addBranch( 2, [ 1 ] );
fMenu.addBranch( 3, [ 2 ] );
fMenu.addBranch( 4, [ 3 ] );
fMenu.addBranch( 5, [ 4 ] );
fMenu.addBranch( 6, [ 5 ] );
fMenu.addBranch( 7, [ 6 ] );
fMenu.addBranch( 8, [ 7 ] );
fMenu.addBranch( [ "Mini", "Wheels & Tires", "Accessories" ], [ 8 ] );

// subscribe to click event of fMenu component
fMenu.addEventListener( "click", _root );

// unhide page elements
logo._visible = true;
fMenu._visible = true;
search_btn._visible = true;
search_txt._visible = true;

// define footer
footer_txt.htmlText = '">asfunction:_root.onFooter,About Us">About Us | ';
footer_txt.htmlText += '">asfunction:_root.onFooter,Contact">Contact | ';
footer_txt.htmlText += '">asfunction:_root.onFooter,rss">RSS | ';
footer_txt.htmlText += '">asfunction:_root.onFooter,admin">Admin';
fcms.Tools.setHover( footer_txt );

// SEOCallBack is false when fCMSPro html template does not contain information about the document.
if ( !eo.SEOCallBack ) gotoAndStop( "home" );
}

/* ########### MENU HANDLING ############## */

// fMenu.click listener
function click( eo:Object )
{
// when tag node is clicked event object has query property defined
if ( eo.query ) {
var q = eo.query;
// header documents are graphic elements different for each part of the site
// activeHeader variable will tell us which header should be active
activeHeader = eo.node.parent.label;
} else {
// otherwise, check if it is first fMenu level
// and if tag with that name exists, create query
var tagID:Number = fMaster.getTagIDByLabel( [ eo.node.label ] );
if ( tagID != undefined ) {
var q = fMaster.getQuery();
q.taggedWith( tagID, true );
q.addReturnRelation( "tagged_with" );
activeHeader = eo.node.label;
}
}
// if query is defined
if ( q ) {
//trace(q);
// if current frame is where index is, just refresh it
if ( _currentframe == 17 ) {
refreshIndex( q );
// otherwise, invoke query
} else {
fMaster.invoke({query:q,queryTarget:"fIndex"});
gotoAndStop("index");
}
// if there is no query
} else {
if ( eo.node.label == "Home" ) gotoAndStop("home");
}
}

/* ########### HEADER ############## */

// these two variables are used for displaying header for each section
var activeHeader:String = "";
var currentHeader:String = "";
// function that is called to set proper content in the header
function refreshHeader()
{
if ( currentHeader == activeHeader ) return;
header_template.query = fMaster.getQuery();
header_template.query.addFilter( "$DOCTYPE", "=", "header" );
header_template.query.addFilter( "title", "=", activeHeader );
header_template.refresh();
currentHeader = activeHeader;
}

/* ########### SEARCH ############## */

// see search tutorial for more info
search_txt.backgroundColor = 0x464646;
search_btn.onRelease = function()
{
if ( search_txt.text != "" ) {
var q = fMaster.getQuery();
q.addFilter( "$DOCTYPE", "=", "item" );
q.addFilter( "*", "FULL_TEXT", search_txt.text );

activeHeader = "Search Results";
if ( _currentframe == 17 ) refreshIndex( q );
else {
fMaster.invoke( {
query:q,
queryTarget:"fIndex"
});
gotoAndStop( "index" );
}
}
}

/* ########### FOOTER ############## */

// runs when text in the footer is clicked
function onFooter( str:String )
{
switch ( str ) {
case "About Us":
activeHeader = "About Us";
if ( _currentframe == 24 ) refreshCommon();
else gotoAndStop("common");
break;
case "Contact":
activeHeader = "Contact";
if ( _currentframe == 24 ) refreshCommon();
else gotoAndStop("common");
break;
case "rss":

break;
case "admin":
fMaster.start();
break;
default:
break;
}
}


The front page also contains 4 _STATIC fields (see 'Getting Started ->
Different ways of presenting content' for more info). Two are plain text so we will create 2 text fields and control them with the fString component. The other 2 (homeImage and homeBanner) are controlled by the fImage component.

The front page also needs 2 fIndex components for displaying lists of news and a list of the most recently added items.
See 'Using fCMSPro -> Understanding Queries' for more info.
Front Page

1
fMenu
2
_STATIC fields are not controlled by any fTemplate
3
fIndex displaying latest 'news' records
4
fIndex displaying latest 'item' records


Note that every section is 'decorated' with different images and titles which are part of the 'header' template on top of the section. See the code above ('refreshHeader' function) that deals with the content of the 'header' template. The activeCategory variable is defined when changing the section. The number of 'header' documents is fixed, because the number of sections is limited. After creating all the necessary header documents, we will set the 'allowNewRecords' parameter of 'header' fTemplate to false. That way, administrators will not be able to add new headers. Additionally, because we are relying on a title field to build the query, we will set the 'editable' parameter of the fString component controlling the 'title' field to false.

The fIndex component is built according to the query. See 'Using fCMSPro -> Building Indexes' for more info:

var indexListener:Object = {};
fIndex.addEventListener( "recordInit", indexListener );
// see 'Working with Indexes' tutorial
indexListener.recordInit = function( eo:Object )
{
if ( typeof eo.data == "string" ) eo.mc.removeMovieClip();
eo.mc.title_txt.text = eo.data.title;
eo.mc.description_txt.htmlText = eo.data.description[ 0 ]
eo.mc.description_txt.htmlText = fcms.Tools.truncate( eo.mc.description_txt.text, 160, "...", false );
eo.mc.image_mc.loadMovie( fMaster.filePathPrefix + fcms.Tools.getThumb( eo.data.image.src ) );
// when item in the index is clicked
eo.mc._btn.onRelease = function()
{
// use invoke to run same query on template that will display record
fMaster.invoke({query:fIndex.query.copy()});
gotoAndStop("item");
// remember index position to jump to same item as selected
_global.itemIndexPosition = eo.num;
}
// add fancy fx
fcms.Tools.tween( eo.mc, {
prop: "_y",
init:eo.mc._y + 550,
end:eo.mc._y,
duration: 500,
easing:mx.transitions.easing.Strong.easeInOut
});
}
function refreshIndex( q )
{
fIndex.query = q;
fIndex.refresh();
refreshHeader();
}
refreshHeader();


Index Section
1
fTemplate controlled movieclip displaying 'header' document type, containing fields: title, description and image
2
fIndex displaying items
3
fPaging controlling fIndex



Next we need to build the main content section. The editable fields are controlled by the fTemplate for 'item', 'news' and 'common' document types. The screenshot below shows the 'item' template in the administration mode. The fTag component allows each document to be tagged (categorized). That way, we can build queries that will return all documents with the same tag, which is what the fMenu.click event handler is doing.
Actionscript on this frame:
// set currently displayed item as one clicked in the fIndex
item_template.current = _global.itemIndexPosition;
// no header here
delete( currentHeader );


Item Page(admin mode)
1
fString defining 'title' field
2
fImage defining 'image' field
3
fText defining 'description' field
4
fTag defining tags of current document

Another two templates ( 'common' and 'news' are created in a similar way )

To discuss any of the code from above, please visit the Flashloaded support forums.

Installing BMW Case Study source files

    1. Locate 'CaseStudy1' archive and unzip it
    2. Follow instructions for installing fCMSBackend (same procedure as explained in Installation part of the userguide)
    3. When editing config.xml file, be sure to use a table prefix the same or similar to the default 'fcmscase1_' prefix.

fcms
fff
localhost
fCMS
_prefix>fcmscase1_

    4. Note that fCMSBackend/config/thumbs.xml file exists and that thumbnails will be created automatically for every uploaded image.

<thumbs version="1.0">
    <thumb width="70" height="55" type="jpg" />
</thumbs>

    5. CaseStudy1 contains images inside 'fCMSBackend/imgRoot/' folder. To be able to upload / delete images, proper permissions should be set for each folder inside the 'imgRoot' folder as well (see installation for more help on changing folder permissions).
    6. To use the source .fla file inside Flash IDE, choose any sans-serif font (Arial for example) instead of 'UB-HelveticaCond'. Then set the fMaster parameter 'fCMS Server Path' to the URL where the fCMSBackend is installed. Image paths are relative, so the 'filePathPrefix' parameter of fMaster should also be set (for example http://www.mysite.com/ if the fCMSBackend is on the root of www.mysite.com)