OpenSocial Templates Developer's Guide

Overview

OpenSocial Templates gives you an easy, fast, and secure way to build gadgets without using JavaScript to generate HTML. Use it to declaratively create templates for your gadgets by making minor modifications to standard HTML markup without using string concatenation and DOM manipulation. Because the library is part of OpenSocial, you can use it to bind to both the OpenSocial APIs and to custom variables that you define.

Hello World Gadget Example

Here is an example of a simple gadget that uses server-side OpenSocial Templates to display the text "Hello world!" in the gadget UI:

  
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
{panel}
  <ModulePrefs title="Hello World">
    <Require feature="opensocial-templates">
    </Require>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[
       <script type="text/os-template"> 
        <div style="font-size: 20px">Hello world\!</div>
       </script>    
    ]]>
  </Content>
</Module>

Setup

To use server-side OpenSocial Templates in your gadget, include the following tag in your ModulePrefs:

<Require feature="opensocial-templates">
</Require>

Creating Templates

The canonical template format is well-formed XML that contains HTML and OpenSocial Template markup. To define a template inside of your gadget file, use <script> tags of type="text/os-template", following this syntax:

<script type="text/os-template">
  <!-- Template definition --> 
</script> 

Template markup can contain both HTML and custom tags.

Data Pipelining

OpenSocial Templates become a lot more useful when you can bind data to them. The OpenSocial /wiki/spaces/a/pages/526835 spec describes a declarative syntax for defining data to process in your gadget. You can access data from an external server or an OpenSocial container.

To work with data in your template, first add <Require feature="opensocial-data" /> to your gadget's ModulePrefs. Then refer to the /wiki/spaces/a/pages/526835 spec and the examples below for the types of data that you can access.

Fetching data from OpenSocial

One tag you can use from the /wiki/spaces/a/pages/526835 spec is <os:PeopleRequest>, which returns profile information for a group or list of people. For example, if you want to access the current viewer's friend list, use the following code:

<script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
  <os:PeopleRequest key="friends" userId="@viewer" groupId="@friends"/>
</script>

Note that this example uses <os:PeopleRequest> with the following attributes:

  • key="friends": this key gives you access to the data object from within the template
  • userId="@viewer": sets the user to the current viewer
  • groupId="@friends": sets the group to the user's friend list

You can find a complete list of fields to use with <os:PeopleRequest> in the /wiki/spaces/a/pages/526835 spec.

After you fetch the data, you can render it using the following OpenSocial Template:

 <script type="text/os-template">
   <ul>
     <li repeat="${friends}">
       <span id="id${Context.Index}">${Cur.name.givenName}</span>
     </li>
   </ul>
</script>

Note that the template uses standard HTML list tags to format the friends list and sets the id attribute of each span node. It also uses the special repeat attribute to iterate over the friends object, the special variable Cur to reference the current item, and the ${} notation to de-reference data objects. You can find more detail about repeaters, special variables, and expressions in subsequent sections of this Developer Guide.

Here is the complete gadget that fetches the OpenSocial data and then renders it:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Server-side Template">
    <Require feature="opensocial-data" />
    <Require feature="opensocial-templates">
    </Require>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[      
      <script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
        <os:PeopleRequest key="friends" userId="@viewer" groupId="@friends"/>
      </script>

      <script type="text/os-template">
        <ul>
          <li repeat="${friends}">
            <span id="id${Context.Index}">${Cur.name.givenName}</span>
          </li>
        </ul>
     </script>
    ]]>
  </Content>
</Module>

See the /wiki/spaces/a/pages/526835 spec for more information about requesting other types of OpenSocial data, including viewer or owner profiles, activities, and container-specific endpoints.

Fetching data from a URL

In addition to fetching OpenSocial data to render into templates, you can also request JSON or text data from a URL using <os:HttpRequest>. Suppose you have the following friends JSON data object stored at http://myfriendsserver.com:

{
  "friends" : [
    {
      "name": "David",
      "interests": "Cooking"
    },
    {
      "name": "Charles",
      "interests": "Hiking"
    },
    {
      "name": "Mary",
      "interests": "Football"
    }
  ]
}  

You can fetch this data like this:

<script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
  <os:HttpRequest key="request" href="http://myfriendsserver.com"/>
</script>

Note that this example uses the <os:HttpRequest> tag with the following attributes:

  • key="request": this key gives you access to the data object from within the template
  • href="http://myfriendsserver.com": the URL where the data is stored

You can find the complete list of fields to use with the <os:HttpRequest> tag in the /wiki/spaces/a/pages/526835 spec.

After you fetch the data, you bind it to the template by setting the require attribute of the template's script tag to the data's key. Here is an example of a simple template that displays each friend's name and interests:

 <script type="text/os-template" require="request">
   <ul>
     <li repeat="${request.result.content.friends}">
       <span>Name: ${Cur.name} Hobby: ${Cur.interests}</span>
     </li>
   </ul>
</script>

Here is the complete gadget that fetches the JSON data and then renders it:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs title="Server-side Template">
    <Require feature="opensocial-data" />
    <Require feature="opensocial-templates">
    </Require>
  </ModulePrefs>
  <Content type="html">
    <![CDATA[      
      <script xmlns:os="http://ns.opensocial.org/2008/markup" type="text/os-data">
        <os:HttpRequest key="request" href="http://myfriendsserver.com"/>
      </script>
 
      <script type="text/os-template" require="request">
        <ul>
          <li repeat="${request.result.content.friends}">
            <span>Name: ${Cur.name} Hobby: ${Cur.interests}</span>
          </li>
        </ul>
     </script>
    ]]>
  </Content>
</Module>

Expressions

Use template expressions to access your data. Embed expressions into the template XML using the syntax ${Expr}. Here is an example of template content that uses an expression to evaluate and display a viewer's name:

  
<div>Hello ${Viewer.displayName}</div>

The syntax of template expressions is defined from a subset of the JSP Expression Language specification. You can use raw variable references in your expressions, as in the example above, or create more complex expressions that use operators, as in this example:

<div>Next step is ${Step + 1}</div>

JSP Expression Language allows you to use most standard operators (e.g. comparison, arithmetic, etc.) in expressions, although OpenSocial Templates provides a few XML-escaped operators for use in XML. For example, you should use ${a lt b} instead of ${a < b}, ${a gt b} instead of ${a > b}, and ${a and b} instead of ${a && b}. See the full list of XML-escaped conditional operators in Conditional Operators.

Most expressions are evaluated as strings. The only exception is if the expression is enclosed in an attribute without additional text content, in which case OpenSocial Templates processes and evaluates the object that is referenced in the expression. In the following example, the Viewer object is passed in to the os:Name template.

<os:Name person="${Viewer}"/>

By default OpenSocial Templates escapes all strings before inserting them into the HTML document. However, OpenSocial Templates may alternatively URL-encode or JavaScript-escape strings, depending on the context.

Conditional Operators

Below is a list of XML-escaped expressions and the conditional operators that they map to. You should use the XML-escaped versions of these operators to evaluate if expressions:

Conditional operator

XML-escaped expression

<

lt

>

gt

<=

lte

>=

gte

&&

and

==

eq

!=

neq

||

or

!

not

Variables

Templates have two types of variables: a set of global objects that are referenced by special variables and a set that includes all other declared JavaScript variables, including JSON data that's passed in to a template for processing and rendering.

Variables are accessed using the syntax Object.Property. For example, the notation Foo.Bar maps to getting the property Bar on the JSON object Foo. You can use this notation for arbitrarily deep nested properties, for example Foo.Bar.Baz maps to the property Baz on the JSON object Foo.Bar.

Equivalent JSON Notation

If Top and Viewer are JSON objects, then

${Top.Viewer.Name} evaluates to data['Viewer']['Name'].

Special Variables

OpenSocial Templates reserves a small set of special variables for template processing: Cur, Context, Top, and My. It also reserves the special tag{{<os:Html>}}. See below for details of how to use each variable and tag.

Cur

Use Cur to refer to the item that is currently being processed within a repeater. The example below repeats over a user's friends list and prints out each user's name:

 
<div repeat="${Top.ViewerFriends}">
  <div><strong>${Cur.Name}</strong></div>
</div>

See more information about repeaters in Repeated Elements.

Context

OpenSocial Templates uses the Context variable as a holding area for additional variables that you might need when processing templates. You can use the following properties of Context:

  • ${Context.UniqueId}: A unique ID of the template being rendered. This value is useful for generating HTML IDs.
  • ${Context.Index}: The index of the current item in the list that is being processed via a repeater.
  • ${Context.Count}: The count of items in the list that is being processed via a repeater.

Here is an example of using the Context variable to keep track of items that are used in a repeater element:

 
<div repeat="${Top.ViewerFriends}">
  Showing friend ${Context.Index} of ${Context.Count}: 
  Your friend's name is ${Cur.Name}
</div>

Top

The variable Top refers to all of the data that's available by key.

My

Use My to reference data that is passed into a template via the tag that calls the template. If you use the expression ${My.foo}, OpenSocial Templates first looks for an attribute named foo in the tag that called the template. If it does not find the attribute, it then looks for an element named foo.

Msg

Use Msg to access localized messages in templates and evaluate expressions within the message body.

For example, suppose you had a message bundle that included the following localized message:

<messagebundle> 
  <msg name="PLAY_SONG">Click here to play Love song #15</msg> 
</messagebundle>

In your template, you can use this markup to directly access and evaluate the localized message:

<a href="${song.url}">${Msg.PLAY_SONG}</a>

You can even also use the $ expression syntax to include an expression in the message bundle. For example:

<messagebundle> 
  <msg name="PLAY_SONG">Click here to play ${song.title}</msg> 
</messagebundle>

In this example, the expression ${song.title in the message body is evaluated at the time of template rendering. Note that you cannot use repeaters and conditionals in messages and variable markup is evaluated in the context in which the message is placed.

See /wiki/spaces/a/pages/527271 for specific instructions on setting up your gadget for localization.

Tags

<os:Html>

Use the <os:Html> tag to include dynamic content that you want to be treated as HTML (and not escaped) in your template.

For example, if you had an expression ${Cur.someText} whose value was <b>Bold</b>,

Then if you evaluated the expression:

${Cur.someText}

The result would be: <b>Bold</b>

However, if you pass the expression to the os:Html tag using the code attribute, like this:

<os:Html code="${Cur.someText}"/>

Then the result would be: Bold (the word "Bold" in bolded font).

Note: Be careful when using this tag! You must properly sanitize the HTML content that you pass in, or else you can introduce XSS attacks.

<os:If>

Use the <os:If> tag to conditionally display content based on the evaluation of an expression. Use this syntax for <os:If>:

<os:If condition="${Expr}">
  <!-- conditional content -->
</os:If>

For example, the content between the div tag below is rendered only if the expression ${Top.YourScore == Top.HighScore} evaluates to true:

<os:If condition="$\{Top.YourScore h1. Top.HighScore\}">
<div>You have the high score of $\{Top.YourScore\}\!</div>
</os:If>

<os:Repeat>

Use <os:Repeat> to render a tag multiple times based on the evaluation of an expression. Use this syntax for the <os:Repeat> tag

<os:Repeat expression="${Expr}">
  <!-- content to apply to each item in the expression that evaluates to true -->
</os:Repeat>

For example, you can use the template below to display a list of friends' names:

<os:Repeat expression="${Top.ViewerFriends}">
  <div>
    Your friend's name is ${Cur.Name}
  </div>
</os:Repeat>

You can also use the var attribute to set a variable name of your choice for the repeater, for example:

<os:Repeat expression="${Top.ViewerFriends}" var="Friend">
  <div>
    Your friend's name is ${Friend.Name}
  </div>
</os:Repeat>

Custom Tags

In addition to using built-in OpenSocial Templates tags, you can also define custom tags to use in your gadget. You can create custom tags inline in your gadget, or refer to tags that are defined in an external template library.

Defining a Namespace

You must register all of your custom tags in a unique namespace. You cannot use the default (HTML) namespace.

Typically the best way to uniquely create a namespace is to use the URL of your domain. However, full URLs tend to be long and unwieldly to insert into tag names, so you can create a prefix instead. For example, if you want to register the namespace example.com/myapp, you can choose the prefix myapp and all of your custom tags will take the form <myApp:TagName>.

Inline Tags

You can create a custom tag out of any inline template by adding the tag attribute to the <script> tag and using xmlns to declare your namespace.

Use this syntax to create a custom inline tag:

<script type="text/os-template" xmlns:yourNamespace="yourURL" tag="yourNamespace:tagName">
  <!-- template markup -->
</script>

Note: You must declare your namespace in the script block for each custom inline tag you create.

Here is an example of creating a custom Hello World tag:

<script type="text/os-template" xmlns:myapp="http://example.com/myapp" tag="myapp:HelloWorld">
  <div style="font-size: 40px">Hello World</div>
</script>

Here is an example of using the tag that you just created:

<script type="text/os-template">
  <myapp:HelloWorld/>
</script>

You can pass parameters into custom tags as XML attributes or elements, and access the parameters using the special variable ${My}.

Here is an example of passing in a color parameter to the custom Hello World template:

<script type="text/os-template" xmlns:myapp="http://example.com/myapp" tag="myapp:HelloWorld">
  <div style="color: ${My.MessageStyle.color\}">Your message is: ${My.message\}</div>
</script>
 
<script type="text/os-template">
  <myapp:HelloWorld message="Hello World">
    <MessageStyle color="blue"/>
  </myapp:HelloWorld>
</script>

External Tag Libraries

It is good practice to gather your template definitions into a single custom library, rather than defining them in all in the same file as your gadget.

Create your custom template library in a well-formed, valid XML file and fill in template definitions according to this structure:

<Templates xmlns:foo="http://foo.com/">
  <Namespace prefix="foo" url="http://foo.com/"/>

  <Style>
    <!-- Set global CSS for your library here -->    
    .warning \{ color: red; \}
  </Style>

  <JavaScript>
    <!-- Define global functions for your library here -->  
    function usedByAllTemplates() \{ ... \};
  </JavaScript>

  <!-- Simple declarative tag foo:bar -->
  <Template tag="foo:bar">
    <!-- Define markup for foo:bar here -->
  </Template>
  
  <!-- Complex tag foo:baz with local CSS and JavaScript -->
  <TemplateDef tag="foo:baz">
    <Template> <!-- Define markup for foo:baz here --> </Template>
    <Style> <!-- Set CSS for foo:baz here --> </Style>
    <JavaScript>
      <!-- Define functions for the foo:baz template here -->
      function usedByFooBaz() { ... };
    </JavaScript>
  </TemplateDef>
 
</Templates>

Note: Use <Template> and <TemplateDef> tags to define templates in a library rather than <script> tags of type="text/os-template".

Refer to the table below for a list of tags to use when defining your template library:

Tag

Usage

<Templates>

Declares all the namespaces used in this library to the XML parser. You must put this tag at the outer-most level of your XML file and list all the custom and pre-defined namespaces that you use in this library. Use the syntax xmlns:namespace_prefix="namespace_URL" for each namespace. For example, if you use any tags in the OpenSocial namespace via the OpenSocial Templates library, you must include xmlns:os="http://www.opensocial.org/".

<Namespace>

Declares your custom namespace. You should only create one namespace per library file. Set the values of your namespace's prefix and URL using the syntax prefix="namespace_prefix" url="namespace_URL".

<Style>

Defines style settings in CSS for your library (at the top-level of the XML file) or individual templates (within <TemplateDef/> tags).

<JavaScript>

Defines JavaScript functions for your library (at the top-level of the XML file) or individual templates (within <TemplateDef/> tags).

<Template>

Sets declarative markup for a template.

<TemplateDef>

Defines a more complex template, which can enclose its own local <Template/>, <Style/>, and <JavaScript/> tags.

For example:

<?xml version="1.0" encoding="UTF-8"?>
<Templates xmlns:os="http://opensocial.org/templates">
  <Namespace prefix="os" url="http://opensocial.org/templates">
  <Style>
    large-font: {
      font-size: 20px;
    }
  </Style>
  <Template tag="os:HelloWorld">
    <div style="large-font">Hello World!</div>
  </Template>
  <TemplateDef tag="os:ShowPerson">
    <Style>
      profile-image: {
        padding-right: 5px;
        width: 32px;
        height: 32px;
      }
    </Style>
    <Template>
      <img if="${My.person.ThumbnailUrl}" src="${My.person.ThumbnailUrl}"
          class="profile-image"/>
      <a href="${My.person.ProfileUrl}" target="_top">${My.person.Name}</a>
    </Template>
  </TemplateDef>
</Templates>

To load this template library into your gadget, add the <Param name="requireLibrary"> tag to the <Require feature="opensocial-templates"> tag in your gadget. The content of the <Param> tag must be a valid Template library XML file. If you use a relative URL path, it is interpreted in relation to the location of the Gadget Spec XML file.

For example:

<Require feature="opensocial-templates">
<Param name="requireLibrary">http://www.example.com/templates.xml</Param>
</Require>   

Use multiple <Param> tags to load multiple libraries. For example:

<Require feature="opensocial-templates">
  <Param name="requireLibrary">http://www.example.com/templates.xml</Param>
  <Param name="requireLibrary">http://www.example.com/moretemplates.xml</Param>
</Require>

Attributes

if

Set the if attribute of an element to an expression and OpenSocial Templates only displays the element if the expression evaluates to true. For example, the text between the <div> tags below is only displayed if Top.YourScore == Top.HighScore:

<div if="${Top.YourScore Top.HighScore}">
  You have the high score of ${Top.YourScore}!
</div>

You can set the if attribute for any element within a template, as in the examples below:

<!-- Custom tags -->
<os:ShowPerson person="${Top.Owner}" if="${Top.HasOwner}"/>
 
<!-- Repeated elements (see below) -->
<div repeat="${Top.ViewerFriends}" if="${Cur.profileUrl}">
  Link to: <a href="${Cur.profileUrl}">${Name}</a>
</div>

repeat

You can set the repeat attribute of a tag to an expression and OpenSocial Templates renders the tag against each of the results. Use the special variable Cur to reference the current item being evaluated in the repeated list.

The following example iterates over all items of the array Top.ViewerFriends and displays each friend object's name:

<div repeat="${Top.ViewerFriends}">
  Your friend's name is ${Cur.Name}
</div>

You can also use nested repeats with the

Cur

keyword when iterating over multi-dimensional arrays of data. For example:

<!--
table: [
  ['A', 'B'],
  ['C', 'D']
]
--> 
<script type="text/os-template">
  <div repeat="${table}">
    <div repeat="${Cur}">
      Element: ${Cur}<br/>
    </div>
  </div>
</script>

index, var

As a convenience, you can rename the Cur variable and specify an index variable by adding var and index attributes, respectively:

<!-- Renaming variable Cur -->
<div repeat="${Top.ViewerFriends}" var="${Friend}">
  Your friend's name is ${Friend.Name}
</div>
 
<!-- Specifying an Index variable -->
<div repeat="${rows}" index="x">
  <div repeat="${cols}" index="y">
    <span> row="${x}" col="${y}"</span>
  </div>
</div>

context

You can explicitly set the scope of data to evaluate using the context attribute. For example, to repeat over Interests of the first object in the data Friends, you can use this expression:

<div context="${Friends[0]}">
  <div repeat="${Interests}">
    ${Title}
  </div>
</div>

require

Use the require attribute to specify all data that's required for rendering your inline template. The value of require should be a comma-separated list of top-level variable names for the required data. If you list more than one variable, the template only renders when all of the variables are set.

For example, the message below is only rendered when both $Viewer and $Owner are set (i.e. non-null):

<script type="text/os-template" require="Viewer, Owner">
  Hello, <os:Name person="${Viewer}"/>, welcome to <os:Name person="${Owner}"/>'s application 
</script>

autoUpdate

Set the autoUpdate attribute to true in your template definition if you want the template to be re-rendered automatically when any of its required data changes.

For example, the content of the template below is automatically re-rendered whenever the Friend data is modified via the function opensocial.data.DataContext.putDataSet("Friend", friend):

<script type="text/os-template" require="Friend" autoUpdate="true">
  You have selected, <os:Name person="${Friend}"/>. 
</script>
<script type="text/javascript">
  function setFriend(friend) {
    opensocial.data.DataContext.putDataSet("Friend", friend);
  }
</script>