Pageflakes Developer Guide

This guide is intended to assist developers with the creation of custom flakes for Pageflakes.

Developing a new flake for use in Pageflakes is as easy as writing a simple JavaScript application. Pageflakes gives developers maximum flexibility with the ability to write server-side code using any language thanks to Pageflakes' language-independent design and versatile platform. With some basic JavaScript and CSS operational skills, developers can take full advantage of the API provided by the Pageflakes framework before finally delivering content.

We welcome your questions and feedback. To contact us, please visit the Pageflakes developer web site located at http://www.pageflakes.com/developers. You can ask questions or provide feedback on this documentation by using the comments section located at the bottom of every page, or by posting in our developer forums.

To get started right away, skip to Getting Started.

Definitions

Flake A small, complete module that can be displayed on a Page.
Flake Code The set of files (script, markup, images) that fully define a Flake.
Flake Instance A processed version of Flake Code that is served by the Pageflakes framework to a browser for display.
Page A collection of Flakes. Each page appears as a “tab” in a user’s Page-Set.
Page-Set A collection of Pages. Each user owns exactly one Page-Set.
Generated XHTML Document A XHTML document that is delivered to the user’s browser and is used to display that user’s Page-Set.
Flake User Object A JavaScript class/function that is designed by the Flake developer, which contains all necessary code to implement the Flake’s functionality.
Flake System Object A JavaScript class/function that is provided by the Pageflakes framework, which is used by the Flake User Object to access the framework API.

Getting Started

This section explains the basic concepts behind Pageflakes by going through an example. It demonstrates the creation of a flake that displays the current weather for a zip code entered by the user. (Apologies to users outside the United States – the intent is to present a simple example).

In this guide, we’ll demonstrate the following concepts:

Prerequisites

To work through the following examples you’ll need knowledge of HTML and Javascript. You’ll also need access to a web server to upload your flakes.

Simple Flake

The simplest flake you can make consists only of HTML code. Create a file called Weather.html that contains the following:

<html>
<body> Weather will go here. </body>
</html>

Upload the flake to any web server.

Add the flake by going to http://www.pageflakes.com/developers and entering the URL of your flake in the "Test your flake" field.

Tip: The Pageflakes framework caches flakes that have a .html extension, making it difficult to debug flakes when you repeatedly upload the same flake. To prevent this, change your flake’s filename extension to .php (or another extension associated with a dynamic web scripting language supported by your web server, such as .jsp or .aspx). Giving your flake an extension other than .html prevents the Pageflakes server from caching your flake. Change your flake’s extension back to .html when your flake is completed to take advantage of caching, unless your flake needs to take advantage of server-side scripting.

Framework Flake Processing

Every Pageflakes user has exactly one top-level Page-Set (shown below). The Page-Set displays one or more pages, where each Page is shown as a tab. Similarly, each page can contain zero or more flake instances.

Flake Processing Hierarchy

Each flake is represented by a single HTML file (which may include references to other files, including JavaScript, CSS, etc.). Those files are collectively referred to as the “Flake Code” and they are hosted on a web server. Usually, this will be pageflakes.com, but flakes can be hosted on any web server.

Flake Processing Hierarchy

When a user visits pageflakes.com, the Pageflakes framework fetches and parses each of the flakes being used. It then generates a single XHTML document that is displayed to the user.

Flake Processing

The Flake Code is not added to the page "as-is". Instead, the Pageflakes framework looks at each part of the flake, using those parts to selectively construct the Generated XHTML Document. This conversion from "Flake Code" to "Flake Instance" is described in more detail in the following sections.

Flake Components

There are four main components of a flake:

  • HTML or XHTML Markup
  • Flake User Object (FUO) – written by the developer of the flake
  • Flake System Object (FSO) – passed by the framework
  • Flake User Object instantiation

HTML/XHTML Markup

The XHTML markup for this example contains a single element. This is a placeholder where the markup showing the current weather will be inserted.

<body>
<div id='_PAGEFLAKES_content'/>
</body>

The id attribute is prefixed with _PAGEFLAKES_. This is to prevent two instances of the same flake from having conflicting id attributes within the same generated XHTML Document. The Pageflakes framework replaces this string with a unique identifier for every flake instance on a given page-set.
For example, if this flake appears twice in a page-set, the Generated XHTML Document will look something like:

<body>
<div id='abc12345current_weather'/>
</body>

and

<body>
<div id='xyz45678current_weather' />
</body>

Flake User Object (FUO) & Flake System Objects (FSO)

The Flake User Object code is written by the flake developer and contains most of the flake functionality.

If a flake appears only once in a user’s page set, this code is called once to instantiate the flake. If the flake appears more than once, the code is called multiple times – once for every flake instance.

Here is the Flake User Object code for the example flake:

<script id='com.approver.hello' type='text/javascript'>

function com_pageflakes_hello(id)
{
this.id = id;
this.fso = null;

var div = $(id + "content");
div.innerHTML = "Hello world!";
}

</script>

The class containing the code is called com_pageflakes_hello. It takes a single parameter, id, which contains a unique identifier for the flake being created. This id is what the framework uses when it replaces the _PAGEFLAKES_ string.

Flake User Object Instantiation

To instantiate the Flake User Object, another script is required:

<script id='_PAGEFLAKES_FUO' type="text/javascript">
var _PAGEFLAKES_ = new com_pageflakes_hello('_PAGEFLAKES_');
</script>

This script is included once for every time the Flake exists in the page set, and it simply creates a new instance of the Flake User Object. For a given instance, here is what the actual executed code may look like:

<script id='abc12345FUO' type="text/javascript">
var abc12345 = new com_pageflakes_hello('abc12345');
</script>

Note:

  • It is important to use the _PAGEFLAKES_FUO for the id tag of the <script> element so that the Pageflakes framework creates one such script block for each instance. If the _PAGEFLAKES_ token is not specified, the framework only creates the block once. Thus, not all instances of the flake Flake User Object are created.
  • The abc12345 variable that is created here is added to the global namespace in the Generated XHTML Document and is the reference used to access the flake’s Flake User Object.

Example

This is the code for the "Hello World" example flake described in this section.

Creating a Flake that Calls a Web Service

Next we’ll create another example flake. This flake will retrieve the value of weather for a region and display it in the flake. To create this flake, we'll need to add code to call a remote web service, then add a callback function that will handle the data retrieved by the service.

Here is Flake User Object code that demonstrates the use of a callback function:

  <script id='com.pageflakes.devdocs.weatherflake' type='text/javascript'>

    function com_pageflakes_devdocs_weatherflake(id)
    {
      this.id = id;
      this.fso = null;
    }

    com_pageflakes_devdocs_weatherflake.prototype = {
      
      load : function (fso)
      {
        this.fso = fso;
        ContentProxy.GetUrl("http://xml.weather.yahoo.com/forecastrss?p=80301&u=c",
                                F(this, this._callback));  
      },

      _callback : function(result)
      {
        var xml = PF.getXmlDoc(result);
  
        var desc = PF.getFirstNode(xml, "item:description").firstChild.nodeValue;
        var title = PF.getFirstNode(xml, "title").firstChild.nodeValue;
    
        var div = $(this.id + "current_weather");
        div.innerHTML = desc;
  
        if (this.fso.title != title)
        {
          this.fso.setTitle(title);
          this.fso.save();
        }

        xml = null;
      }
    };
    </script>

In this example, the class containing the code is com_pageflakes_devdocs_weatherflake. This class takes a single parameter, id, which contains a unique identifier for the flake being created. This id is what the framework uses when it replaces the _PAGEFLAKES_ string described in the previous example.

The Flake User Object can contain as many variables and functions as your flake requires. However, there is one function that is mandatory: the load() function. The Pageflakes framework calls load() after it instantiates the Flake User Object and is ready to load the flake on the page.

The load() function takes a single parameter, fso, which holds a reference to the Flake System Object. The fso parameter is stored for future use (see next example). The Flake System Object enables the Flake User Object to interact with the Pageflakes framework and make use of the framework API.

Note:

  • The <script> block is included only once in the Generated XHTML Document. The framework does this by using the id attribute of the script. It is important to select the id attribute carefully to avoid conflicts with other flakes. One way to do this is to use a reverse domain name, as shown in the example.
  • Similarly, the Flake User Object function defined within the <script> block must also be named uniquely. You should use the same naming convention you use with script block itself, replacing the "." character with the underscore ("_").
  • All of your flake's variables and functions should be defined within its Flake User Object function. Any member defined outside the Flake User Object function may collide with the Pageflakes framework or other Flakes.

When the Pageflakes framework calls your flake's load() function, the flake:

  1. Uses the ContentProxy to fetch an XML document containing the weather for the 80301 zip code. We’re hard coding this zip code in the URL for now.
  2. When the ContentProxy retrieves the data, it calls the _callback() function with an XML string. The PF.F(this, this._callback) ensures that the callback is fired in the context of this, not in the context of the calling ContentProxy object. If the callback were set directly, then the this reference would be unusable inside _callback as it would not refer to the flake user object.
  3. The callback() function uses the Pageflakes functions to extract the <title> and <description> elements of the XML document.
  4. The "current_weather" <div> element is retrieved from the HTML markup and filled with retrieved weather content. The id attribute is prepended to ensure the correct <div> element is retrieved.
  5. The Flake System Object sets and saves the title for the flake.

Putting it all together, the weather flake looks like this:

<html>
  <head>
    
    <title>Weather Flake</title>

    <script id='com.pageflakes.devdocs.weatherflake'
        type='text/javascript'>

    function com_pageflakes_devdocs_weatherflake(id)
    {
      this.id = id;
      this.fso = null;
    }

    com_pageflakes_devdocs_weatherflake.prototype = {
      
      load : function (fso)
      {
        this.fso = fso;
        ContentProxy.GetUrl("http://xml.weather.yahoo.com/forecastrss?p=80301&u=c",
                            PF.F(this, this._callback));  
      },

      _callback : function(result)
      {
        var xml = PF.getXmlDoc(result);
  
        var desc = PF.getFirstNode(xml, "item:description").firstChild.nodeValue;
        var title = PF.getFirstNode(xml, "title").firstChild.nodeValue;
    
        var div = $(this.id + "current_weather");
        div.innerHTML = desc;
  
        if (this.fso.title != title)
        {
          this.fso.setTitle(title);
          this.fso.save();
        }

        xml = null;
      }
    };

    </script>

    <script id='_PAGEFLAKES_Instance' type="text/javascript">
      var _PAGEFLAKES_ = new com_pageflakes_devdocs_weatherflake('_PAGEFLAKES_');
    </script>

  </head>

  <body>
    <div id='_PAGEFLAKES_current_weather'/>
  </body>

</html>

Adding a Settings Tab

In the previous example, the flake was hard-coded to show weather from the 80301 zip code. In this example, we'll improve the flake by adding a settings page. In the settings page, users can select a zip code and the flake will display the weather for that zip code.

First, add a variable to hold the zip code within the com_pageflakes_devdocs_weatherflake function:

var zipcode = null;

Next, create a special

section to contain markup for the settings page:

<body>
  <div id='_PAGEFLAKES_current_weather'/>
  <div id='_PAGEFLAKES_edit' class="edit">
    <table>
      <tr>
        <td>ZIP code</td>
        <td><input id='_PAGEFLAKES_zipcode' type='text'></td>
      </tr>
      <tr>
        <td>
          <input id="_PAGEFLAKES_saveButton"
                 onclick="_PAGEFLAKES_.saveOptions();
                 type="button"
                 value="Save" /> 
        </td> 
        <td> 
          <input id="_PAGEFLAKES_cancelButton"
                 onclick="_PAGEFLAKES_.cancelOptions();"
                 type="button"
                 value="Cancel" /> 
        </td>
      </tr>
    </table>
  </div>
</body>

This markup includes a single field where the zip code can be entered, as well as Save and Cancel buttons. Each button's onclick attribute invokes saveOptions() and cancelOptions() respectively (those will be shown shortly). The _PAGEFLAKES_ prefix indicates that those functions belong to the Flake User Object.

Note:

  • This
    element must have the id attribute set to _PAGEFLAKES_edit.
  • The class attribute must be set to "edit" to ensure proper formatting.
  • The framework toggles between the flake and the flake settings when the user clicks on the "Edit" button.

Then, script is added to retrieve the zip code from storage and save it in this variable, as well as the settings page:

this.loadOptions = function()
{
  if (fso.Profiles["zip"])
    zipcode = fso.Profiles["zip"];
  else
    zipcode = "80301";

  var zipelement = $(id + "zipcode");
  zipelement.value = zipcode;
};

The loadOptions() function uses a key-value pair list in the Flake System Object to retrieve the zip code. This list can be used to store any flake data.

Note: PF.$(id + "zipcode") is used as a shortcut for document.getElementById(id + "zipcode"). For more details, see Pageflakes Functions.

The last couple of lines, are used to retrieve the <input> element from the settings page, and set the correct zip code in that element. In addition, the zip code is set it in the newly created variable.

Next, the saveOptions() function is created:

this.saveOptions = function()
{
var zipelement = $(id + "zipcode");
zipcode = zipelement.value;
fso.Profiles["zip"] = zipcode;

fso.save();
fso.hideEditArea();
_self_.getWeather();

};

this.getWeather = function()
{
var url = "http://xml.weather.yahoo.com/forecastrss?p=" + zipcode + "&u=c"
ContentProxy.GetUrl(url, callback);
};

The saveOptions() function does the following:

  1. Retrieves a reference to the <input> element containing the zip code and extracts its value.
  2. Stores the zip code in the newly created variable.
  3. Stores the zip code in a name-value pair list in the Flake System Object.
  4. Stores the name-value pair list into permanent store by calling save() on the Flake System Object
  5. Exits the “edit” mode, such that the user is returned to the normal flake view.

The getWeather() function is slightly modified to invoke the ContentProxy with a URL that reflects the correct zip code.

Finally, the cancelOptions() function:

  • Toggles back to the flake and hide the settings page using the hideEditArea() function on the Flake System Object
  • Reloads the option from permanent store, in order to discard the recent user input.

this.cancelOptions = function()
{
  fso.hideEditArea();
  _self.loadOptions();
};

Example

This example adds user settings to the Weather flake.