OpenSocial Views Developer's Guide (v0.9)

Your OpenSocial gadgets have the potential to run in many different environments. At times, they may take up most of a user's browser window, or be displayed in a narrow sidebar. They may run alone on a page, or be displayed alongside other gadgets. Sometimes gadgets can only be viewed by the person that installed them, and other times they can be accessed by anyone on the internet.

This variety is a great advantage for developers who want their applications to be seen in as many places as possible, but can be difficult to design for when all of these cases have to be covered by a single file. Thankfully, OpenSocial addresses this problem through the use of gadget views, which allow your application to deliver different experiences depending on where it is rendered.

Getting started

Require the views feature

To let your gadget take advantage of views, you'll need to require the views feature. Add <Require feature="views" /> to the ModulePrefs section of your gadget's XML:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Test views gadget" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html">
    <![CDATA[
      This content section will render on all views.
    ]]>
  </Content>
</Module>

Add views to your Content section

The Content section(s) of your gadget determine what is rendered to each view. You can specify which views a Content block will render on by adding a view attribute to the Content block. The following code modifies the sample to say that the content block should render on the "default" view:

<Content type="html" view="default">
  <![CDATA\[
    This content section will render on all views.
  ]]>
</Content>

Note that adding view="default" to a Content element is a special case - "default" means that the Content block should be rendered in all views, which is the same behavior as if you had not added the view attribute at all.

By changing the value of the view attribute, you can choose where your view renders. For example, on a user's profile:

<Content type="html" view="profile">
  <![CDATA[
    This content section will render on a user's profile.
  ]]>
</Content>

or on the expanded "canvas" view:

<Content type="html" view="canvas">
  <![CDATA[
    This content section will render on a larger canvas view.
  ]]>
</Content>

Here is a list of common views supported by containers. Note that the list of the supported containers is not complete. You should consult /wiki/spaces/a/pages/526883 or developer documentation to determine what is available:

View name

Description

Available on...

default

Renders on all possible views.

Most containers except MySpace

all

Renders on all possible views.

MySpace

profile

Renders on a user's profile. Is visible to viewers of that profile.

All social network-based containers

profile.left

Renders on the left column of a user's profile. Is visible to anyone visiting the profile.

MySpace

profile.right

Renders on the right column of a user's profile. Is visible to anyone visiting the profile.

MySpace

home

Renders in a small area, possibly among several other gadgets. Is only seen by the OWNER.

iGoogle and MySpace

canvas

Renders on a large expanded view, filling most of the space on the screen. Is visible to anyone visiting the canvas page.

All OpenSocial containers

Multiple content sections

You are not limited to using a single content section for your application. By adding additional Content sections to your gadget XML spec, you can display entirely different content per view.


<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Multiple content sections" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="profile">
    <![CDATA[
      This content section will render on a smaller profile view.
    ]]>
  </Content>
  <Content type="html" view="canvas">
    <![CDATA[
      This content section will render on a larger canvas view.
    ]]>
  </Content>
</Module>

Multiple views per content section

If you have a content section that can be used in multiple views, you can specify multiple comma-separated view names in the view attribute of the Content section. The following example renders the same content on the home and profile views:


<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Multiple views" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="profile, home">
    <![CDATA[
      This content section will render on both the profile and home views.
    ]]>
  </Content>
</Module>

Redundant content sections/views

If Content sections can be repeated, and each Content section may have many views, then what happens when a view is repeated? The Gadgets Specification says:

On a <Content> block, the view names are represented as comma delimited strings which allows a particular <Content> block to be used on one or more surfaces. Surfaces with common view names have the inner XML of their <Content> blocks concatenated. Concatenation only occurs with exact matches of a view name on a <Content> block. ... Concatenation does not happen when the @href is set on a <Content> block.

So as long as each content section is type="html" and doesn't have an href attribute, Content sections will have their contents concatenated. This can be a great way to share code between multiple views, as shown in the following gadget:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Concatenation of views sample" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="home, profile, canvas, default">
    <![CDATA[
      <p><strong>This text shows up on all views</strong></p>
      <p>Elements in this content section will be rendered in all views, making it a good place to put JavaScript utility functions.</p>
    ]]>
  </Content>
  <Content type="html" view="home, profile">
    <![CDATA[
      <p><strong>This text only shows up on the profile and home views.</strong></p>
    ]]>
  </Content>
  <Content type="html" view="canvas">
    <![CDATA[
      <p><strong>This text only shows up on the canvas view.</strong></p>
    ]]>
  </Content>
</Module>

The previous gadget will display the following in profile and home views:

This text shows up on all views

Elements in this content section will be rendered in all views, making it a good place to put JavaScript utility functions.

This text only shows up on the profile and home views.

In the canvas view, the following is displayed:

This text shows up on all views

Elements in this content section will be rendered in all views, making it a good place to put JavaScript utility functions.

This text only shows up on the canvas view.

Subviews

OpenSocial version 0.9 introduces the concept of subviews. A subview is a user-defined label attached to a view that helps developers create multiple-page applications without resorting to JavaScript. For example, a gadget may have a content section defined for the canvas view, but also a view called canvas.help, which would contain help documentation for the gadget. The canvas.help content section is considered a subview and will not be rendered unless explicitly navigated to using a call to gadgets.view.requestNavigateTo('canvas.help').

The following example gadget demonstrates navigating between views and subviews. The profile view of this gadget contains a button which navigates to the standard canvas view. The canvas view contains a button which navigates to the page2 subview of the canvas view. When the button on the profile view is pressed, the entire gadget changes to canvas view. However, when the button on the canvas view is pressed, the gadget remains in the canvas view, but renders the content contained in the canvas.page2 Content section:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Test subviews" author="api.kurrik@google.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="profile,home">
    <![CDATA[
      <h1>Profile view</h1>
      <button onclick="gadgets.views.requestNavigateTo('canvas');">Click to go to canvas.</button>
    ]]>
  </Content>
  <Content type="html" view="canvas">
    <![CDATA[
      <h1>Canvas view</h1>
      <button onclick="gadgets.views.requestNavigateTo('canvas.page2');">Click to go to page 2.</button>
    ]]>
  </Content>
  <Content type="html" view="canvas.page2">
    <![CDATA[
      <h1>Canvas view, page 2</h1>
      <p>This is another page of content for the home view.</p>
    ]]>
  </Content>
</Module>

Using the gadgets.views JavaScript functions

The following sections illustrate some JavaScript methods which help your gadgets take advantage of the full functionality of views.

Determining available views

The gadgets.view.getSupportedViews JavaScript method gives your application the ability to query a container to find out which views it supports. The return value of this call is an array of key/value pairs where the keys are view names and the values are View objects. The following gadget demonstrates a simple way to list the supported views of the current container:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="getSupportedViews" author="api.kurrik@google.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="default">
    <![CDATA[
      <h1>Available views</h1>
      <div id="view-output"></div>
      <script type="text/javascript">
        var views = gadgets.views.getSupportedViews();
        var dom = document.getElementById("view-output");
        for (var view in views) {
          if (views.hasOwnProperty(view)) {
            dom.innerHTML \+= "<div>" + view + "</div>";
         }
        }
        gadgets.log(views);
      </script>
    ]]>
  </Content>
</Module>

On iGoogle, this currently prints:

CANVAS
canvas
FULL_PAGE
HOME
home
default

Note that many of these views are aliases to the same object. For example, CANVAS, canvas, and FULL_PAGE all point to the same view.

Navigating between views

Most containers offer the users of your application buttons or links to view your gadget in a different view (usually in the form of "maximize" and "restore" buttons). However, your gadget may wish to expand or contract itself automatically in response to a user's action.

You can initiate such a switch from JavaScript by using the gadgets.view.requestNavigateTo function. In versions of OpenSocial prior to 0.9, this function needed a gadgets.view.View object as an argument, but on containers which support 0.9 and above, navigating to the desired view (for example, the canvas) is as simple as calling gadgets.views.requestNavigateTo('canvas');. If you like, you can easily create HTML links which will navigate to the desired view:

<a href="javascript:void(0);" onclick="gadgets.views.requestNavigateTo('canvas');">Go to the canvas</a>

Here is a full gadget example that displays buttons which cause the gadget to navigate between views. Note that this gadget was written for iGoogle, which uses the home and canvas views. If you were writing this gadget on orkut, you would use profile and canvas.

<?xml version="1.0" encoding="UTF-8"?>
  <Module>
    <ModulePrefs title="requestNavigateTo" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="home">
    <![CDATA[
      <h1>Home view</h1>
      <button onclick="gadgets.views.requestNavigateTo('canvas');">Click to go to the canvas.</button>
    ]]>
  </Content>
  <Content type="html" view="canvas">
    <![CDATA[
      <h1>Canvas view</h1>
      <button onclick="gadgets.views.requestNavigateTo('home');">Click to go to the home view.</button>
    ]]>
  </Content>
</Module>

Passing data between views

In many cases, your application will want to change view due to direct interaction by the user. In this case, it is useful to be able to pass data from the source view to the destination view, for the purposes of saving the user's state as the gadget refreshes.

For this purpose, the gadgets.views.requestNavigateTo method accepts a second, optional parameter. Any data object passed in this parameter will be available in the destination view by calling the gadgets.view.getParams method.

The following example shows how to pass additional data to a gadgets.views.requestNavigateTo call, and how to retrieve that data in the destination view, using the gadgets.views.getParams function:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="requestNavigateTo with data" author="sample.testington@example.com">
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="home, profile">
    <![CDATA[
      <h1>Home/profile view</h1>
      <p>Type some text into the box below and click the button to send it to the canvas view.</p>
      <input type="text" id="input-data" />

      <script type="text/javascript">
        function getData() {
          return document.getElementById('input-data').value;
        };
      </script>

      <button onclick="gadgets.views.requestNavigateTo('canvas', getData());">Click to go to the canvas.</button>
    ]]>
  </Content>
  <Content type="html" view="canvas, default">
    <![CDATA[
      <h1>Canvas view</h1>
      <div id="output"></div>
      <script type="text/javascript">
        var data = gadgets.views.getParams();
        document.getElementById('output').innerHTML = "<strong>Got:</strong> " + data;
      </script>
    ]]>
  </Content>
</Module>

The requestNavigateTo call can accept a string, a number, an array, or an object as the data argument.