226 Chapter 10 OSML, Gadgets, and the Data Pipeline Table 10.8 OSML Markup Tags os:Name The specified person’s display name, hyperlinked to the person’s Profile hyperlinked to the perso
Trang 1224 Chapter 10 OSML, Gadgets, and the Data Pipeline
Table 10.6 os:ActivitiesRequest Attributes
Key Required A string value used to identify this data within
the DataContext The key value must be unique within the app across all data tags.
userId Required A comma-delimited list of IDs to use in
conjunction with the groupId attribute Valid values are
@viewer
@owner
a specific user ID groupId Optional The group of users to get, relative to the value
defined in the userId attribute If this is not fied, it defaults to @self, which means the person object(s) corresponding to the value of the userId attribute Valid values are
speci-@self
@friends The value @self means the records specified in the userId attribute The value @friends means friends
of the user(s) specified in the userId attribute.
Fields Optional A comma-delimited list of OpenSocial activity
fields to return with each record.
startIndex Optional In a paged list of records, this specifies the
starting index for results.
number of records to return.
Table 10.7 os:DataRequest Attributes
Key Required A string value used to identify this data within
the DataContext The key value must be unique within the app across all data tags.
Currently, only GET requests are allowed Valid requests are
people.get (equivalent to os:PeopleRequest) activities.get (equivalent to
os:ActivitiesRequest) More endpoints are being added all the time, so check the MySpace developer site for the latest information.
Trang 2JavaScript Blocks in OSML Apps
WarningGadget XML and OSML must be a well-formed XML document To prevent surprise parsing errors stemming from your JavaScript code, always make use of CDATA tags in your JavaScript blocks.
All apps that make use of OSML or Data Pipelining must be in gadget XMLformat and consist of well-formed XHTML content only If your Contentblockswrap their innards in CDATA tags as is suggested in some of the older GadgetXML documentation, none of the OSML or Data Pipeline tags will be evaluated
As a result, your app code must consist of well-formed XHTML content only AnyJavaScript code containing a “less-than” or “greater-than” test will violate thisrequirement
//]]>
</script>
Wrapping the client script block contents with CDATA sections instructs the OSMLparser to ignore things that might otherwise look like tags inside Even though tags arenot evaluated, expression language statements will be.Therefore, the following statementwill still work:
var greeting = "Welcome to my app, ${vwr.displayName}";
OpenSocial Markup Language The OpenSocial Markup Language, or OSML, is a tag-based markup language foradding and defining reusable user interface components, easily displaying content from
an external server, and managing simple control flow.When OSML is coupled with DataPipelining, it becomes a formidable new way of writing apps
In this section we introduce some of the basic tags available in the initial version ofOSML
OpenSocial Markup Language 225
Trang 3Basic Display Tags
There are a limited number of convenience tags defined within OSML.These tags allowsimple and common UI elements to be easily rendered.The tag set is currently small, butlook for more complex UI elements to be added over time.Table 10.8 identifies the cur-rent built-in OSML markup tags
Remote Content Display Tags
HTML partial fragment rendering has become a common Ajax technique OSMLprovides a simple tag for displaying inline content from remote servers via a GETrequest MySpace also provides a more general-purpose display extension tag.Table 10.9identifies these two tags
Control Flow Tags
There are two basic mechanisms provided for display control flow:os:Ifandos:Repeat Additionally, MySpace provides an extension to os:Ifto give it an “else”
syntax as well.Table 10.10 identifies the control flow tags available in OSMLPutting It Together: OSML Tic-Tac-ToeOur previous “Hello World” gadget app gave a light introduction to using Data Pipelinetags along with the general gadget structure Now we’re going to take what we’ve seen
so far and apply it to our existing Tic-Tac-Toe app to see what happens
226 Chapter 10 OSML, Gadgets, and the Data Pipeline
Table 10.8 OSML Markup Tags
os:Name The specified person’s display name, hyperlinked to the
person’s Profile
hyperlinked to the person’s Profile os:PeopleSelector Displays a FriendPicker, scoped to the identified group
Table 10.9 Remote Content Display Tags
GET request and displays it inline at the tag location myspace:RenderRequest Fetches the markup using any HTTP method supported
by gadgets.io.makeRequest Contents may be displayed inline or in a specified element.
Trang 4Setting Up the Gadget
Our first step is to move the existing code as is into the gadget XML format For this
step we’ll make use of our desktop code editor to paste all three of the existing appsurfaces into an empty gadget XML file.The OpenSocial Sandbox tool will be our bestfriend for validating our work in this initial stage
Creating the Initial Gadget File from Existing CodeHere we will construct the initial app gadget XML source file from the code blocks wehave already developed using the app Surface Editor At the end of these steps we willhave our same app in the gadget XML format
1 Navigate to the Sandbox by clicking Tools → OSTool/Harness from the developersite and clicking the Try the Beta OpenSocial Sandbox Editor link to open theSandbox Editor (shown in Figure 10.1)
2 Copy the contents of the Blank Sample Gadget and paste it into a new code file
in your code editor (Aptana for us)
3 Change the value of the “title” attribute of the <ModulePrefs>element from
“Hello World” to “OpenSocial Tic-Tac-Toe.”
4 Save your file as OpenSocialTTTGadget.xml
5 Open the source for the Home Tic-Tac-Toe surface in your code editor
6 Copy the entire contents of the Profile code file and paste it into your new gadget
in the Profile view template script.The surrounding code will look like this:
<Content type="html" view="home">
Putting It Together: OSML Tic-Tac-Toe 227
Table 10.10 OSML Control Flow Tags
os:If A conditional block that is shown if the expression
statement evaluates to true osx:Else Inverse conditional support for os:If This is a
MySpace extension to the OSML specification The osx:Else tag must appear immediately adjacent to
an os:If tag.
os:Repeat Iterates over an array of data items and displays the
contents of the repeat tag, evaluated for each data item
Trang 58 Select the Home view from the Views drop-down and click Render.You will see
an error similar to the following:
An error occurred while parsing EntityName Line 210, position 43.
// First check if there was an error back from the proxy if(!response || (response.errors && response.errors.length > 0)
|| response.errorCode){
retryRequest();
}
We need to fix these parsing errors before we can get any further
Fix Parsing ErrorsThe error we encountered was caused by a greater-than comparison occurring within aJavaScript block.To get around this, we’ll wrap all client JavaScript script tag contents inCDATA sections:
1 Go back to the gadget code in your source editor
2 Search for all the <script>tags that do not have a type attribute of
text/os-templateortext/os-data
228 Chapter 10 OSML, Gadgets, and the Data Pipeline
Figure 10.1 OpenSocial Sandbox Editor.
Trang 63 Add an opening CDATA tag immediately after the script tag and a closingCDATA tag immediately before the closing </script>tag.These tags should bepreceded by JavaScript inline comment characters Here is an example of what theupdated script block will look like:
Adding Other SurfacesThe other two surfaces must also be added to the gadget file Paste the Profile andCanvas code into the templates in the appropriate Contentblocks of your gadget file
Make sure you add CDATA sections to all JavaScript blocks until the Sandbox Editorcan render all three surfaces without any parsing errors
There is one more issue that will surface when reconciling the existing JavaScript appwith the gadget/OSML format Activity templates make use of an expression marker intheir templates that’s similar to one found in the Data Pipelining expression language
Both use the format ${SOME_VAR} to define an expression.The OSML renderer, findingthe embedded activity templates, will attempt to resolve the contained tokens as
Putting It Together: OSML Tic-Tac-Toe 229
Figure 10.2 Sandbox rendering of Home.
Trang 7expressions and hiccup.The resolution is to build up the activity template strings in away that does not look like an expression to the server-side OSML processor
Search the gadget code for "${"and make the following changes:
// Version using the default template function rsmNotification(recipient, game_id){
// Set up all the data we'll need var body = "$"
body += "{sender} has finished their move ";
body += "in $"
body += "{app}, it's your turn!";
This splits the activity template expression up so the server doesn’t recognize it, but thetemplate still looks the same to the client code
Reusing Common Content
We have now created a single-source-file behemoth for our app, weighing in at almost
2500 lines of code It’s nice to have a single source file for storage and tracking purposes,but it can be a bit ungainly to manage from a code maintenance standpoint.The AptanaIDE does a nice job of allowing you to expand and collapse nodes for easier visibility,but that’s no substitute for cleaning up our code.We need to DRY things out a bit
230 Chapter 10 OSML, Gadgets, and the Data Pipeline
The DRY PrincipleThe acronym DRY stands for Don’t Repeat Yourself It’s a clever catchphrase to remind developers to reuse code as much as possible One of the failings of using the Surface Editor for writing apps is that you will find yourself repeating the same code over and over again With an OSML gadget an app can reuse parts of the code through the use of shared Content blocks.
If we look at our code, we’ll see a lot of repeated lines across the three surfaces Infact, putting the original Home and Profile source files in a diff tool (we usedWinMerge), we find that there are only five differences, consisting of an additional style
on Profile, some slightly different text on the button between the two, and a trailing div
on Profile.Through the use of shared Contentblocks, we can almost immediatelyremove 98% of the code associated with one of these surfaces
Merging Home and Profile with Shared Content BlocksGadgets and, by extension, OSML define their different surfaces with <Content>blocks
Theviewattribute of a Contentblock identifies the surface for which the enclosedcontent is valid During rendering of the OSML gadget, any and all Contentblocks that
Trang 8have a view value matching the current surface are rendered in the order in which theyare encountered in the gadget XML file If a particular block of content is valid on morethan one surface, it may be identified as such by using a comma-delimited list of surfacenames for which it is to be rendered.This is in contrast to the app Surface Editor, whichallows one and only one discrete view per surface
Our diff of the Home and Profile sources showed that there are relatively few ences between the two Since Profile seems to be a superset of the Home view, withsome small textual changes, we’ll use that as the basis for both surfaces
differ-Creating Shared Style Content BlocksOne of the powers of the gadget XML format is the ability to stream shared code blocksacross multiple surface views In this section we use the notion of specifying multiplevalid viewvalues in a single Contentblock in order to share common markup, styles,and JavaScript between the Home and Profile surfaces
1 Edit your app’s gadget XML file to completely delete the home Contentblock
2 Change the profile Contentblock to also include the Home view, like this:
<Content type="html" view="profile, home">
3 Save your changes and view them using the Sandbox tool.The Home and Profilesurfaces should now match
4 Add three new Contentblocks with template script tags above the existing bined Home and Profile block.The first block will be used to hold the commonstyles.The second two will hold view-specific styles.The code should look likethis:
com-<Content type="html" view="profile, home">
5 Add the complete <style>block to the first shared Contentblock
Putting It Together: OSML Tic-Tac-Toe 231
Trang 96 Create new style elements in both the subsequent blocks and cut and paste thesubtitle-style class definition out of the shared style area and into each privatestyle block Modify the Home surface’s version to be display:none; the two private style blocks should appear as shown here:
<Content type="html" view="profile">
<script type="text/os-template">
<style>
.subtitle {
Customizing the Button Text Between ViewsThere are supposed to be some minor differences between the Home and Profile views
of our app In this section we add some subtle changes in a Contentblock specific tothe Home view that fixes the button to show appropriate text whether on the Homeview or the Profile view
1 Find the button element in the shared Profile/Home content template It shouldlook like this:
<button onclick="rNT(gadgets.views.ViewType.CANVAS);">
Click here to challenge me!</button>
2 Modify the element to add an attribute of id="playButton"to the buttonelement
232 Chapter 10 OSML, Gadgets, and the Data Pipeline
Trang 103 Add a new Contentblock after the shared Profile/Home Contentblock that isspecific to the Home view Include the template script tags and client-sideJavaScript script tags
<Content type="html" view="home">
"Click here to play now!";
5 Save and view the results.The Home view should now show the proper buttontext Here is an abbreviated code listing of the updated Home/Profile contentblocks:
<Content type="html" view="profile, home">
<script type="text/os-template">
<style>
body { background-color:#1E4C9F;
color:#fff;
margin:0;
padding:0;
} img { border:0;
}
Trang 11<style>
.subtitle {
Trang 12Working with Data
Having shared display code among the surfaces is great Having shared data is even moreawesome.The next step is to start migrating some of our data calls and our display tomake use of the Data Pipeline
We’ll start by changing the Viewer request to an os:ViewerRequestand use theexpression language to display the Viewer info
Getting Viewer Information with os:ViewerRequest
1 Edit the canvas Contentblock to add a new os-datasection above the os-templatesection.The modified code section will look like this:
<Content type="html" view="home">
<os:ViewerRequest key="viewer" fields="@all" />
3 Edit the contents of the myinfodiv to pull the Viewer image and name from ournew pipelined data stored under the viewerkey in the DataContext An expres-sion language statement is used to set the name and image URL:
<div id="myinfo" class="player_info right_column">
<img class="profile_image" src="${viewer.thumbnailUrl}" />
Trang 13Updating the Player Bio Lightbox to Use Client-Side DataContext
In this section we make some minor refactors to the existing JavaScript function thatcontrols the display of the opponent box At this point we only swap out some ofthe data calls with calls to the DataContext and leave most of the code intact
Moving to using a template will be introduced in the next chapter: Chapter 11,Advanced OSML
1 Add a new div below the myinfodiv with the ID of playerBioWrapperand setthe style equal to display:none
2 Search for the printPersonfunction Notice all of the HTML being built later
in the function In the original version of this function the div element for thelightbox is created dynamically.We’re going to code the lightbox content containerdirectly on the page
3 Copy out the wrapping divs and close button divs Add these to the div created instep 1.Your markup should appear like this:
<div id="playerBioWrapper" style="display:none;">
<div id='player_bio'><div id='player_bio_title'>Player Bio</div>
<div id="bio_contents"></div>
<div class='clear'></div>
<div id='bio_close'><a href='javascript:TTT.LightBox.hide();'>close </a></div>
Trang 14str += vwr.thumbnailUrl str += "' /></div><div>\n";
var tryAppendLine = function(val){
if(val && val != ""){
return val + "<br />\n";
} } str += tryAppendLine (vwr.DisplayName);
str += tryAppendLine (vwr.DateOfBirth);
7 Assign the contents of your string to the innerHTMLof the element internal tothe player bio div and assign the entire bio contents to the lightbox:
var bioElem = document.getElementById("playerBioWrapper");
var bioContents = document.getElementById("bio_contents");
bioContents.innerHTML = str;
//Add to lightbox TTT.LightBox.setContent(bioElem.innerHTML);
//Now show TTT.LightBox.show();
8 Update the More link to fire the new showViewerBiofunction instead of directlyinvoking the lightbox.Your code should properly show the lightbox again
Displaying Data Lists
The next operation is to display a list of friends.This is done by combining the results of
anos:PeopleRequesttag with an os:Repeatcontrol.We’re going to update theInvite tab to use OSML and the Data Pipeline instead of client XHR requests
Displaying Friends with a Repeater
A repeater allows your app to apply the same display content to multiple items in a list
The most common use case is to display a list of friends In this section we’ll use arepeater to display the friends in the Invite tab of our app instead of the previouslydesigned JavaScript function for manually outputting this code
1 Add an os:PeopleRequesttag to the Data Pipeline script (text/os-data) for ourCanvas view.We’ll place it under the key "friends"and get the Viewer’s friendswith it.The following tag states that “I’m going to get a group of friends”—denoted
by the special value "@friends"in the groupIdattribute—”and these friends will
be friends of the Viewer”—denoted by the special value "@viewer"in the userIdattribute:
<os:PeopleRequest key="friends" userId="@viewer" groupId="@friends" />
Putting It Together: OSML Tic-Tac-Toe 237
Trang 152 Find the invite_containerdiv.We’re going to modify this div to add a repeattag to iterate over friends Ahead of the last closing div on this element, add thefollowing:
The astute reader will also notice that as we ported over our Tic-Tac-Toe app to useOSML, we were not cleaning out the retired JavaScript.With the exception of com-menting out some clashing client JavaScript calls, the now unused script code is still inplace A partial listing of the retired JavaScript functions includes
n getInitialData
n getDataCallback
n printPersonSince proper refactoring and cleanup of old code can be an arduous process, we willleave the code in place for now.We leave it to the reader to fully identify supersededcode blocks and clean them out of the app
What we’ve seen so far are some of the most common operations in OSML
Remember, OSML is a late addition to the OpenSocial spec and supported starting only
in version 0.9 At the time of this writing, OSML and Data Pipelining are not even fullyreleased and aren’t recognized by previous versions, whereas the OpenSocial JavaScriptAPI has more than a year under its belt and is fairly stable.We encourage you to pushthe limits with OSML, though, and give your feedback both to MySpace and to theOpenSocial community so that we may continue to improve things
NoteCode listings and/or code examples for this chapter can be found on our Google Code page under http://opensocialtictactoe.googlecode.com
238 Chapter 10 OSML, Gadgets, and the Data Pipeline
Trang 16OSML provides significant features beyond simple markup reuse and tag-based data declaration In this chapter we’re going to explore some of the more advanced features
of OSML.These features include defining custom tags, translating your app to differentcultures and languages, and direct rendering from your external server
In the preceding chapter we covered some different ways of solving the same lems we’ve previously solved, but using OSML In this chapter we’ll do a little more ofthat, plus introduce some new features that open even more doors to our app
prob-Remember, though, OSML is a very late addition to the OpenSocial spec, and it issupported beginning only with version 0.9 of the OpenSocial specification; previousversions do not recognize OSML
Inline Tag TemplatesInline tag templates are reusable components that are declared directly inside the maingadget XML.They look very similar to standard inline templates with one exception:
the presence of a tagattribute in the declaring template scripttag.Templates defined
in this manner are not rendered in place but are instead registered as custom tags for uselater in the app
Trang 17Defining and Using a Tag Template
Tag templates are an easy and convenient way to create reusable display elements For theTic-Tac-Toe app, we’re going to convert the Player Info box (shown in Figure 11.1) to acustom tag.This element is used for the current Viewer as well as an opponent Our custom tag will display based on the person object passed in as a parameter
Creating the Custom Tag Template DefinitionThe first step is to create our custom tag definition In the following steps we’ll convertthe existing Player Info box into a custom tag template for use in our app.We’llgeneralize it so that it can be used for both the Viewer and the opponent
1 Create a new template script element in the Contentblock of your Canvas code
This element should appear at the top of the block, before any other templatescripts In addition to the normal template script tags, it has an additional attribute
oftag="my:PlayerInfo"
<Content type="html" view="canvas">
<script type="text/os-template" tag="my:PlayerInfo">
</script>
2 Find the Player Info box markup in our existing app gadget It can be found bysearching for the div with an ID of myinfo Copy and paste the contents of themyinfodiv into our new tag:
<script type="text/os-template" tag="my:PlayerInfo">
<div id="myinfo" class="player_info right_column">
<div class="left"><a href="javascript:openProfile();">
<img class="profile_image" src="${viewer.thumbnailUrl}" /></a>
<div class="record" id="myrecord"></div></div>
240 Chapter 11 Advanced OSML: Templates, Internationalization, and View Navigation
Figure 11.1 Player Info box.
Trang 18Inline Tag Templates 241
3 Now we’re going to clean out the hard-coded data and change the tag template touse parameters Parameters are local values passed in from a tag instance.They areaccessible through the reserved variable ${My} Our tag requires that a personobject be passed into the tag instance in the Playerelement Replace all the
${viewer.X}statements with ${My.Player.X}statements:
<script type="text/os-template" tag="my:PlayerInfo">
<div id="myinfo" class="player_info right_column">
<div class="left"><a href="javascript:openProfile();">
<img class="profile_image" src="${My.Player.thumbnailUrl}" /></a>
<div class="record" id="myrecord"></div></div>
6 Modify the styles to accommodate the blue/pink (male/female) background colors
on this element It would be a little tedious to do an "if"test within this markupfor male/female on the My.Playerobject, so we’ll accommodate this feature byusing style class names instead.The player_infostyle definition will have a bluebackground (default), and an additional player_info_FEMALEstyle will bedefined to override the background to pink:
.player_info {
border:solid 2px black;
padding:5px;
background-color:#09f;
} player_info_FEMALE {
background-color:#fcf;
}
Trang 19<div style="border:2px solid ${My.borderColor};"
class="player_info right_column player_info_${My.Player.gender.key}">
Using the Custom TagNow that we’ve defined our template, the next step is to use it.We’re going to addinstances of the custom tag for both the current Viewer and for the opponent, if present
1 Search again in the code for the div with an ID of myinfo Delete this entire divand all contained elements
2 Add in place of the myinfodiv an instance of our my:PlayerInfotag with theid="myinfo":
<my:PlayerInfo id="myinfo" >
</my:PlayerInfo>
3 Add in parameter elements for PlayerandborderColor.The Player valueshould be ${viewer}and the borderColorcan be any valid CSS color string orcolor hex.We chose the color green
Using Client-Side Templates
Custom templates are also available for use in client-side code All your custom templatesare available for use on the client side via the new opensocial.template namespace
This allows your app to create and render new template instances on the client.The callsequence looks something like this:
var templateInst = opensocial.template.getTemplate("my:CustomTag");
var tdata = {}
tdata["background"] = "red";
242 Chapter 11 Advanced OSML: Templates, Internationalization, and View Navigation
Trang 20To avoid client-side template-rendering issues, use only complete DOM element blocks
as a template—for example, div elements, fully enclosed tables, and the like Avoid ing your templates with elements that are typically nested in other elements, such as list items ( LI ) and table rows ( TR ) Tables in particular are problematic because many browsers introduce a multitude of new elements, such as TBODY , THEAD , and TFOOT , without telling you Favor styled div blocks in these instances The same problem also exists with client-side repeaters and tables If you wish to repeat a table row ( TR ) element, you must make use of attribute-based repeaters, not the os:Repeat element in your template.
start-We’re going to use client templates to render the opponent’s display block using ourmy:PlayerInfocustom tag template
Client-Side Rendering with Custom TagsBecause apps are dynamic, the information that is needed doesn’t always exist at serverrender time User interactions affect the app In our case, the opponent is selected afterthe initial app load.To address this, we use the templating JavaScript methods todynamically render our custom tag after the opponent has been selected
In the following steps we will convert the opponentinfodiv element from markupthat required tedious editing in JavaScript code to a second implementation of ourcustommy:PlayerInfotemplate
1 Edit the div element with an ID of opponentinfo and delete all the contents
Also remove the style class attribute so that we are left with an empty div element
<div id="opponentinfo" >
</div>
2 Add an os:PeopleSelectortag element immediately above the opponentinfodiv defined in step 1 It should specify the group as the contents of our friendsdata item and a var= "selectedOpponent"to have the selected friend placed in
Trang 21the DataContext under that key.We’ll also tie its select behavior into our existingselectOpponentmethod.This replaces the client-side FriendPicker we added inChapter 7, Flushing and Fleshing
<os:PeopleSelector group="${friends}" var="selectedOpponent"
onselect="selectOpponent()" />
</div>
3 Remove the div with an ID of opponentPickerand comment out the call toloadFriendPickersince this is now being handled by the os:PeopleSelector.You may skip this step if you did not implement app data person-to-person play(discussed and outlined in Chapter 7)
4 Define a new function to trigger the client-side rendering of a new templateinstance in the opponentinfo div named updateOpponentTemplate.Thisfunction gets a template instance using the opensocial.template.getTemplatefunction and then calls renderInto to render the template into our
opponentinfodiv.The function looks like this:
//Construct the data to pass into the template var data = {};
244 Chapter 11 Advanced OSML: Templates, Internationalization, and View Navigation
Trang 22Working with Subviews 245
Working with SubviewsSubviews are a new concept introduced with OSML So, yes, that means they work onlystarting with version 0.9 of the OpenSocial spec If you’re writing or editing an app for alower version, you won’t be able to use subviews
In addition to the main surface views (Home, Profile, and Canvas), subviews allow formultiple views or view parts to be defined on a particular surface.The app can then
“navigate” to these subviews without forcing a page reload
Using subviews is quite simple All you have to do is name the subview in a Contentblock’s viewattribute, then use the following call:
gadgets.views.requestNavigateTo(<target_view_name>);
This call causes the target subview to show, and all other subviews are hidden
Subviews are useful, but they do have some design and behavior characteristics youshould be aware of:
n Subview Contentblocks must consist of coherent, well-formed XHTML
n Adjacent non-subview Contentblocks must also be well formed (this means nopartial nesting of elements)
n By default, activating one subview turns off all other subviews
n On initial load, all subviews are hidden
Converting Tabs to Subviews
We’re going to reimplement our tab interface (shown in Figure 11.2) by making use ofsubviews Changing the interface in this way allows us to make use of the built-in viewnavigation call gadgets.views.requestNavigateToinstead of manually manipulatingCSS classes or styles on the elements It gives us the added benefit of not having to writeloops to manage turning off other elements that should be hidden; it’s all handled by thesubview processing
Figure 11.2 Tab interface in app.
Trang 23246 Chapter 11 Advanced OSML: Templates, Internationalization, and View Navigation
Editing the Markup to Use Subviews for Tab ContentTabs are currently defined as div blocks.We need to modify the markup so that theheader is a Contentblock, the footer is a Contentblock, and each subview is aContentblock.This allows our app to control the display of the tabs as subviews but stilldisplay the header and footer in a consistent manner
1 Find the location of the first tab content container by searching for the div with
<Content type="html" view="canvas.play">
of the Contentblock element)
5 Edit each tab content element’s CSS class attribute to remove the hideclass:
<div id="invite_container" class="container">
Table 11.1 New Subview Names
Trang 241 Edit the TTT.Tabobject to simplify its representation It will now hold the view name instead of a reference to the tab container DOM element.
sub-TTT.Tab = function(tab_dom, view, action){
if(tab){
gadgets.views.requestNavigateTo(tab.view);
} else{
return;
}
}
Working with Subviews 247
Trang 25The well-formedness constraint can be a problem in some interfaces with tag nesting.
As a result, subviews tend to lend themselves best to absolutely positioned elements (forexample,<div style="position:absolute;">xxx</div>) or root children DOMelements of the view In this way the subviews do not interfere with layout flow whenbeing enabled or disabled
HTML Fragment RenderingOne of the most common paradigms we have found with OpenSocial apps is that ofcontent rewriting Many apps perform an initial load of a Bootstrap page, then call back
to their external servers for the actual app content and perform a wholesale innerHTMLrewrite of the app.While this is very flexible, it is also a very slow user experience As wepreviously mentioned, OSML brings a number of new options to the table for fine-grained content rewriting
In our app we’re going to add a tab to view one of our favorite sites and then render
a banner ad from a pretend ad server URL (actually, a historic Web site)
Adding Content with os:Get
In this section we’ll create a new tab that displays content from an external site.We’ll usetheos:Gettag to pull content directly from the external site and display it inline on asubview
1 Add a new tab to our series of tabs Search for the div with an ID of tab3 Create
a copy of this immediately after as tab4and adjust the text to be “Laugh.” Alsoadjust the CSS class definitions as shown here:
<div id="tab3" class="left tab" onclick="TTT.Tabs.selectTab(3);">