OpenSocial Templating Specification 2.5.0opensocial-and-gadgets-spec@googlegroups.com
General
OpenSocialsocial networkingRESTXMLExtensible Markup LanguageJSONJavaScript Object NotationAtomThe key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in
RFC2119.Domain name examples use RFC2606.OpenSocial Templating (OST) provides a declarative way for gadget
developers to create templates by copying and pasting HTML, then making
minor modifications to that HTML. Because OST is part of OpenSocial, it
also provides a means to bind to the OpenSocial APIs and custom, developer
defined variables. OST accomplishes this through tag libraries and special
markup.
OpenSocial Templating additionally makes use of the
OpenSocial Markup Language (OSML) and Expression Language (EL) to bring dynamic
processing and custom tag support to gadgets. These items are defined more
fully in the
Social Gadget
and
Core Gadget
specifications, respectively.
An OST implementation can fetch, inject, cache, and store data requests
for the application before any client side code executes. OST does not
represent a full replacement for JavaScript. OST assumes that applications
can fallback to JavaScript whenever a combination of application and
container cannot make use of a given OST feature.OST creates a new feature name for use in the Gadgets Specification:
opensocial-templates. When a Module requires OST, the Module must contain
this XML:
A common usage of the feature would be with other OpenSocial features.
The canonical template format is a well-formed XML document. This
document can include HTML tags which will be output directly when rendering
the template, and custom tags which will be evaluated when rendering the
template.
A common use case will be embedding this XML into an HTML document. The
following snippet can be embedded directly into a gadget <Content>
section or HTML document:
Templates can also define template markup libraries, which will map
to XML namespaces.
Templates can be used to define inline rendered sections or custom tags.
Custom tag templates may be defined inline in the gadget XML or in Template Libraries.
Discussion
Inline templates can be directly embedded in gadget Content blocks using
<script type='text/os-template' > sections or directly within Content
blocks having type='osml'. Custom tag templates may also be embedded inline
using os-template script blocks with a @tag attribute, inline with the
canonical <Template> syntax, embedded in a gadget XML <Templates>
element, or in an externally referenced
Template Library.
OpenSocial Templating adds a new <Templates> element as a direct
child of the <Module> root. The format of this element is the same
as that defined for Template Libraries. Custom tag templates defined in this element will be globally available to all views by default. Any individual custom tag
template may be restricted to a specific view(s) by adding a @view attribute
to the template definition. DiscussionBlocks of markup using OSML appear embedded in other markup within script
tags. The type of an OSML script is set to "text/os-template". The only
attribute that an OpenSocial OSML processor MUST understand is @tag. The
OSML processor MUST ignore any attributes it does not recognize. The
OpenSocial specification reserves the following attribute names for future
usage:
@autoRender@id@nameContainers MAY choose to experiment with these attributes to define a
consistent meaning and behavior for the attributes in a future release of
OpenSocial.Expressions can be embedded into the template XML using the syntax
${Expr}. Variable names, properties, and function names are all case-sensitive.
Expressions are honored inside text nodes and attribute values. They will
be ignored inside tag and attribute names.Expressions are defined using a subset of the
JSP Expression Language, with a couple of minor
modifications. We use a subset of the JSP Expression Language specification.
This allows for expressions that are raw variable references, as in the
example above, or expressions with operators:
JSP Expression Language allows you to use most standard operators
(comparison, arithmetic, etc.), although some operators have an alternate
name for use in XML. ${a < b} becomes ${a lt b}, ${a > b} becomes ${a
gt b}, ${a && b} becomes ${a and b}, etc.Expressions are usually evaluated as strings. The only exception is when
expressions are in attributes without additional text content, and in this
case, the value of the expression is the object referenced, and this object
is passed to the template for processing. In the following example, the
viewer is passed in to the os:Name template.
Unless an overriding Security Policy is applied, strings are escaped
before inserting into the HTML document. By default
strings are HTML escaped, which is the equivalent of setting the "el_escaping"
permission to "html" with a Security Policy.HTML specified some element attributes whose mere presence affects
browser behavior. For example, the @selected attribute of the
<option> tag. An exception is made for this small subset of
attributes: if their value contains an expression which evaluates to a
"false-like" value (that is any of, null/undefined, the boolean false, the
number 0, empty string, or the literal string "false"), the attribute will
be removed during template processing.This allows markup like the following to work as expected and cause the
Viewer option to become selected:
Some examples of tag-attribute combinations to which special processing
will apply:
@selected attribute of the <option> tag@checked attribute of the <input> tag@disabled attribute of the <input>, <button>,
<select> and <textarea> tagsVariables are accessed using Foo.Bar (or Foo.Bar.Baz) notation. .Bar
maps to getting the property Bar on the JSON object. If Top and Viewer are
JSON objects, then
evaluates to
Properties of DOM Nodes have special evaluation rules. For a given Node
object, ${Node.Param} will attempt to evaluate as follows:
First look for the @Param attribute on the node. If it exists, its
string value is returned.Next, look for child nodes with the local name "Param" (namespaces are
not supported for DOM property evaluation). If no nodes are found, return
null. If a single node is found, it is returned. Otherwise a NodeList
containing all the found nodes is returned.Evaluation of Nodes or lists of Nodes as strings results in the merged
text content of these nodes. So <Color>Red</Color> would become
the string "Red". This is mostly applicable to results of ${My} evaluation
(see below).The EL will provide a number of built-in functions. The initial
set of functions provides string escaping control. Containers MAY experiment
by adding functions of their own to the EL.
EL FunctionDescriptionhtmlEncodeEncode HTML markup entities. At minimum escape greater-than and less-than symbols and quotation marks to their encoded equivalents.htmlDecodeUnescape an HTML-encoded string.urlEncodeURL-encode the contained string. The behavior should mirror the JavaScript function encodeURIComponent.urlDecodeURL-decode the contained string. The behavior should mirror the JavaScript function decodeURIComponent.filterUrlApply rules to make the URL safe for inclusion in markup. Recommendations are to disallow javascript and apply anti-phishing mechanisms.jsStringEscapeEscape string for inclusion within JavaScript block.
Discussion
A number of root-level property names have been reserved for container-controlled values.
A container MAY override values from an external source (ex: JSON data loaded with os:HttpRequest)
if it uses any of the reserved keys at the root level of the data object.
startIndextotalResultscountitemsPerPagesortedfiltered
Much of the data available to the EL through the Data Context is generated
by Data Pipeline tags. The underlying REST endpoints that generate this data
includes meta-information in addition to the actual data. Below is an example
of the JSON response for a list of people.
Any EL statements that access this information begin evaluation from the "entry" key.
Assuming the above data was placed under a key "friends", the following EL statement
would evaluate to "Dick":
Response meta-information that exists above the "entry" key in the raw response
may be accessed from the EL key root through the reserved keys "totalResults", "startIndex", etc.
For example, to access the
value of "totalResults" from the above example, the following EL statement
would be used:
The above statement would evaluate to "100".
Data pipeline attributes from the originating request tag may be accessed via the EL
through the reserved key "Request". This key exposes the attributes of the original request
through the EL. The below example shows an originating <os:PeopleRequest> and the
EL statement to get the count of records requested.
Data items added to the data context that are not the result of a data pipeline
request are not required to expose the "Request" key. An example of this would be
data items added via the Javascript API or with the os:Var tag.
A container may attach the request attributes from original data pipeline request tag to the response
data object in the data context or may manage the originating request data in an alternate manner.
Data is used with all calls to render templates. When rendering templates
through Javascript, - i.e.:
opensocial.template.getTemplate('foo').renderInto(div, data) - data can be
passed in explicitly. When no data is supplied, such as when templates are
automatically rendered, the default application Data Context, which can be
populated declaratively via Data Pipelining, will be used. The data passed
in must be a JSON object. The templates will have two 'types' of variables.
One set is a set of global objects with reserved names. The other set
includes everything else or all other declared JavaScript variables.Template processing reserves a small set of variables. Like all variables,
special variables are case-sensitive.${Top} refers to the data context passed into the template rendering -
i.e.: for automatic rendering, ${Top} == Data Context; for programmatic
rendering via template.renderInto(div, data) -> ${Top} == data.${Context} is a holding area for additional variables generated while
processing templates. ${Context} will include the following set of
properties:
${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 "repeat" tag.${Context.Count} The count of items in the list that is being
processed via a "repeat" tag.${Cur} refers to the current data item being processed, either within a
repeater, or specified via the @cur attribute (see below). At the top of
the template rendering stack ${Cur} == ${Top}. When a custom tag is
invoked, ${Cur} will start out as null.${My} refers to data that is passed into a template via Custom Tag XML.
${My} is only available within templates invoked as Custom Tags.The ${My} variable evaluates to the XML template node that was used to
invoke the current Custom Tag, with all expressions, conditional elements
and repeated elements already processed.Properties of ${My} are evaluated as with any other DOM node (see
above), with one exception: any attribute expressions that would normally
evaluate to Objects are not converted to string by default. So, for
<foo:Bar person="${Viewer}"/>, ${My.Viewer} will resolve to an
Object whose properties can be further accessed:
${My.Viewer.name.formatted}.
Special variable names are optional for all but ${Context}. Expressions
will be evaluated against each of the other special variable contexts. The
first matching variable will be the result of expression evaluation. The
order of precedence is ${Cur}, ${My} and then ${Top}. For example,
${Top.Name} == ${Name} unless there exists ${Cur.Name} or ${My.Name}. The
following examples show why this is helpful:
"Top" refers to the data context passed in via Javascript, so ${Top}
will return the data passed in during template rendering.Variables are accessed using Foo.Bar (or Foo.Bar.Baz) notation. .Bar
maps to getting the property Bar on the JSON object. If Top and Viewer are
JSON objects, then
evaluates to
Variables may be declared in both inline and custom tag templates
with the os:Var tag.
The value of os:Var is processed as defined under os:Var Processing Rules
The <os:Var> tag allows for the declaration of literal variables.
It may be used in inline custom tag templates, inline templates, and
data-pipeline sections.
When os:Var is used in inline templates it will not be available until after processing
the os:Var tag in the render pass.
Within custom tag templates, <os:Var> defines a new
variable that will be available anywhere within the custom tag template
instance. When an os:Var tag appears in the
template definition, it will be created after the instance
parameters are attached to ${My}.
In the template definition it will therefore
have access to other custom tag instance parameters and be
able to reference them through the ${My} variable.
Templates can be rendered automatically, or via a Javascript API
available under the opensocial.template namespace (see below). An
implementing container may disable the Javascript API for some or all
application Views. In this case templates will only be renderable
automatically when the application loads.Templates embedded into the application markup via <script>
elements will be processed automatically when the application loads. By
default, templates will be rendered into the application content in the
place where they appear in the markup.
Automatic rendering is done against the application Data Context which
can be populated declaratively via Data Pipelining, or programmatically via
opensocial.data.DataContext.putDataSet().Automatic rendering can be prevented by setting the
"disableAutoProcessing" parameter of the opensocial-templates feature in
the gadget spec
Data required for rendering of inline templates can be specified using
the @require attribute. The attribute value must be a comma-separated list
of top-level variable names required to render this template. If the
application Data Context does not have all of these variables set,
automatic rendering of the template will be deferred until the time they
become available.
It is possible to request that the template be re-rendered when any of
its required data changes. This is done by setting @autoUpdate attribute to
"true". When this is set, the template will re-render any time any of its
required data is modified via opensocial.data.DataContext.putDataSet(key,
data).
During rendering templates can call other templates via Custom Tags. You
can add a @tag attribute to any template (both on the <Template>
element or on the <script> tag for embedded templates). This allows
the template to be called by using an XML element of the same name.The value of the @tag attribute must be a namespaced string. Creating
custom tags in the default (HTML) namespace is not allowed.Templates defined via inline <script> elements that also specify a
@tag attribute do not get rendered in place automatically.
Parameters can be passed into templates as XML attributes or elements.
These parameters are accessed using the special variable ${My}:
Custom tag template parameters are resolved prior to invoking the template, much as
a function call resolves parameters prior to passing them to the function.
Parameters are resolved using the rules below to determine behavior.
All examples assume the myapp:HelloWorld custom tag has already been defined.
Custom tag instance parameter keys are case-sensitive, regardless of if they
are registered as attributes or elements.
When the same parameter name appears as both an element and an
attribute, the attribute-defined parameter will take final precedence.
Element parameters that contain attributes will result in an object that has the
attribute values placed as property values of the root object.
If parameters contain repeated elements with the same name, the
custom tag instance will treat them as a node list and construct an array
with the element contents as the values of each node.
A namespaced parameter where the namespace matches the namespace of the
defined tag will have the parameter value placed in the ${My} variable under the local name.
A namespaced parameter where the namespace does not match the namespace of the defined tag will be discarded and not registered with the ${My} variable.
The scope of data to evaluate (${Cur}) can be explicitly set with the
@cur attribute. For example, to repeat over Interests of the first object
in Friends, you can use this expression:
Content can be displayed conditionally based on evaluation of an
expression. Elements with an @if attribute will only be displayed if the @if
attribute evaluates to true. For example, the following will only be
displayed if Top.YourScore == Top.HighScore:
The contents of an <os:If> element are only displayed if the
@condition attribute evaluates to true.
Note: The @if attribute, and the @condition attribute of <os:If/>
will be evaluated as a boolean. This means null or empty string values will
evaluate to "false". A Node, NodeList or non-empty string will evaluate to
"true".The use of @if and @repeat attributes on <os:If/> is not
supported.The @if attribute can be used on any element within a template other than
<os:If/> and <os:Repeat/>. Some examples are as follows:
Tags can be rendered multiple times based on evaluation of an
expression.Tags with a @repeat attribute are displayed once for each item in
evaluating the expression in the repeat attribute. The current item in the
repeated list will be put into the ${Cur} variable.The value of the @repeat attribute will be evaluated as a list. If the
result is a scalar value, (including mixed content which evaluates to a
string) it will be treated as a list of one element.
The contents of an <os:Repeat> element is displayed once for
each item in evaluating the expression in the @expression attribute. The
current item in the repeated list will be put into the ${Cur} variable, and
a @var attribute can also be used to rename the iteration variable.
and
The use of @if and @repeat attributes on <os:Repeat/> is not
supported.Repeating over an expression that evaluates to a NodeList or a single
Node (such as the result of ${My.tag}) will result in one iteration
rendering for each Node found. In this case, the ${Cur} variable will be set
to the current node for each successive iteration.Repeaters are evaluated before conditionals on the same element. This
allows a conditional to apply to each iteration of a repeater. The following
template, for example, would list all the viewer's friends with a profile
URL:
The ${Context} special variables can be used during repeater processing
to access repeater state. Its properties are ${Context.Count} which holds
the total number of elements in the repeater list, and ${Context.Index}
which is the number of the current iteration, a value from 0 to
${Context.Count} - 1.
To support nested repeaters, custom names can be specified for the
current item variable and the current context variable via the @var and
@context attributes respectively. The values are then made available as
variables specified, as well as with their default names. (So when
@var="Foo" is used, each item is made available in ${Cur} and in ${Foo}.)
As stated above, all expression evaluation results will be treated as a
String, and escaped in a context-appropriate manner. However, there are
cases where HTML markup from trusted sources needs to be injected into the
template from the DataContext. For such use cases, the built-in
<os:Html> tag may be used.The <os:Html> tag will evaluate its @code attribute as a string,
and render the resulting code as HTML.
Containers may chose to define what subset of HTML will be honored
by the <os:Html> tag, and what will be sanitized away. Containers
should allow minimal functionality such as making text bold or changing its
color, as well as creating links and inserting images.A template may also define locations to render custom blocks of content.
This is done using the <os:Render> tag and the content block is always
identified by the @content attribute. The @content attribute names an
immediate child node of the template instance or current repeater item if it
is a DOM element. The contents of the designated node will be rendered in
place of the <os:Render> tag. If multiple child elements match, the
container MUST merge the results of all matches into one, concatenated
element. If 2 or more <os:Render> elements have the same value for
@content, then the resulting evaluation appears once per <os:Render>
element. A container MUST ignore any XML elements or other content within
the <os:Render> tag. The container MAY emit a diagnostic error to
gadgets.log indicating the content being ignored. The container MUST ignore
any namespace prefixes on the value of the @content attribute.
@content="foo" will match "foo" elements in the same namespace as the
template.For example, consider the following template:
The preceding example declares two os:Render elements: title and
body. When evaluating a usage of this template, the container will look for
two elements at the following paths, ignoring any XML namespace on the
elements (
XPath) :
/myapp:BoxWithTitle/child::(local-name() = title)/myapp:BoxWithTitle/child::(local-name() = body)Because of the existing processing rules, the contents of the
elements will have already been processed by the container. The results of
that evaluation are copied into the template in place of the
<os:Render> element. Returning to the previous example, a developer
may write:
When evaluating the above content, a container follows these steps:
Evaluate the content of the myapp:BoxWithTitle tag. The result nodes
will be used to fullfill os:Render directives.Begin evaluation of the myapp:BoxWithTitle template.For each os:Render tag encountered, find the appropriate tags from step
(1) that match os:Render's @content.Replace the os:Render tag with child nodes of all the tags found in step
(3).Replace the entire myapp:BoxWithTitle tag with the result of rendering
the m:BWT template.The nature of this feature allows for templates to nest within os:Render
tags. Given the evaluation rules, the myapp:BoxWithTitle example could also
be used as this:
While inline templates can be useful for visualizing data, eventually you
may want to create standalone, reusable templates. A template library can
define one or more template custom tags, but all of them must be in a single
namespace. Template libraries are packaged into a sandalone XML file of the
following format:
Syntax:
<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 to the OpenSocial
Templates API. 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.Containers should load the <os:*> template tags by default, and
it is not required that they be defined as a standalone XML file. Other tag
libraries can be loaded by default in a container - for example, Example.com
might have a set of <example:*> tags available.If an application requires a template library to work, it can request
the library be loaded before any template processing takes place. This can
be done via a <Param name="requireLibrary"> tag placed inside the
<Require feature="opensocial-templates"> tag:
The Param content must be a URL pointing to a valid Template
library XML file. Relative URLs are interpreted in relation to the location
of the Gadget Spec XML file.Multiple libraries may be requested by repeated occurrences of the
requireLibrary Param:
The container will trim all whitespace around each URL. For URLs
that legitimately contain whitespace, it must be properly encoded.NOTE: Implementing containers may disallow loading third party template
libraries on some or all gadget Views. Additionally, containers may
disallow template libraries to inject Javascript code on some or all of the
Views.Templates will have the ability to substitute localized text content on a
per-language basis.Gadgets already have a facility for defining localized messages. In the
gadget prefs, you can specify the URL for localized message bundles on a
per-language basis:
Each bundle is a list of <msg> elements with localized
content inside:
Also note that in OpenSocial API 0.9, you will be able to inline
<msg> elements into the gadget directly without creating separate
files for each locale.Localized messages will be accessible via the ${Msg} variable:
Any ${} markup in the message body will be honored - in the above
example, the ${song.title} reference in the message will be evaluated at the
time of template rendering. Repeaters and conditionals in messages will not
be processed. Variable markup will be evaluated in the context in which the
message is placed. (Note how the message in the example references the
${song} variable available at the point of message inclusion.)It's important to realize that this sets ${Msg} apart from other variable
inclusion markup - variable references will NOT be processed in any other
output.If a particular message is undefined for a locale and missing from the
default bundle (prefs.getMsg(key) returns null in these cases), an error
message should be rendered in its place for easy debugging.Template-related Javascript API may be exposed by implementing containers
for some or all views. Such API will allow developers to render templates
programmatically.Template-related functionality will be exposed via the
opensocial.template namespace object.<static> Type: {opensocial.template.Template}
opensocial.template.getTemplate(tag)Description: Returns the Template object (see below) registered with
"tag", or null if it doesn't exist.Parameters:
NameTypeDescriptiontagStringThe tag used to identify the template.Returns:
TypeDescriptionopensocial.template.TemplateThe Template object registered with the specified tag, or null if no
such template exists<static> Type: {void} opensocial.template.process()Description: (Re)processes the application templates, rendering ones
that are ready.<static> Type: {void}
opensocial.template.disableAutoProcessing()Description: Prevent automatic template processing. Equivalent to
setting the "disableAutoProcessing" Param. If processing has already
happened, this will throw an exception. After automatic processing is
disabled, the templates can be processed by calling
opensocial.template.process() manually.The result of calling opensocial.template.getTemplate(name) is a
Template object that can be rendered programmatically.Type: {Element} opensocial.template.Template.render(data)Description: Renders the template with supplied JSON data, and returns
the DOM Node containing the result.Parameters:
NameTypeDescriptiondataObjectThe JSON data to use for rendering. This becomes ${Top} in variable
evaluation. If this is omitted, opensocial.data.DataContext will be used
by defaultReturns:
TypeDescriptionElementThe Element containing DOM created by rendering the template.Type: {void} opensocial.template.Template.renderInto(element,
data)Description: Renders the template with supplied JSON data and inserts
the result into the specified DOM element, replacing any previous
contentParameters:
NameTypeDescriptionelementElementThe DOM element to host the render result. Any current content in
this element will be cleared by this methoddataObjectThe JSON data to use for rendering. This becomes ${Top} in variable
evaluation. If this is omitted, opensocial.data.DataContext will be used
by defaultSimple Gadget FormatRemoval of 'os:' prefix as it contains illegal function name charactersMove security policy to core gadgetsKey words for use in RFCs to Indicate Requirement LevelsHarvard UniversityReserved Top Level DNS NamesIBMJava Server Pages Expression Language