A container is a browser-based desktop-like application which brings F2 apps together onto a seamless user interface. It also can provide horsepower to its apps in the form of request-response web services or streaming data feeds.
+A container is a browser-based web application which brings F2 apps together onto a seamless user interface. It can also provide data and user context to its apps in the form of request-response web services or streaming data feeds.
+App Integration
+There are two ways of integrating apps on a container: requesting apps on-demand (via HTTP) or by linking pre-loaded apps. Requesting apps on-demand when the container loads is the traditional way of integrating apps with F2. Incorporating apps which have been pre-fetched or are otherwise already on the container when it loads is an alternative method. The following sections describe both of these methods in detail.
+The process of loading apps on a container occurs by using a method called F2.registerApps()
. The Container Developer must call this method—which accepts two arguments: one required, one optional— after F2.init()
is called. If this method isn't called, no apps can be loaded on the container.
+The two arguments provided to registerApps()
are an array of AppConfig
objects and, optionally, an array of AppManifest
objects. As F2.js parses each AppConfig
, the apps are validated, hydrated with some additional properties, and saved in browser memory on the container. Regardless of where the container's AppConfig
object is defined (hard-coded or via API), integrating apps is a simple process.
+
+AppConfigs
+Before continuing, let's discuss the AppConfig
. The container-provided app configurations are represented simply as an array of AppConfig objects. These could be configured statically or fetched from an F2 Registry API. AppConfig
objects contain app meta data—including the manifestUrl
—provided by the App Developer when an app is registered in the Developer Center.
+An example AppConfig
object from an individual app:
{
appId: "com_companyName_appName",
- description: "App description",
- height: 500,
manifestUrl: "http://www.domain.com/manifest.js",
- name: "App name"
+ name: "App name",
+ context: {
+ data: [1,2,3,4,5]
+ }
}
-Example array of AppConfig
objects for a collection of apps:
-var _appConfigs = [
+An example array of AppConfig
objects for a collection of apps:
+[
{
appId: "com_companyName_appName",
- description: "App description",
- height:500,
manifestUrl: "http://www.domain.com/manifest.js",
- name: "App name"
+ name: "App name",
+ context: {
+ data: [1,2,3,4,5]
+ }
},
{
appId: "com_companyName_appName2",
- description: "App2 description",
- height:100,
- manifestUrl: "http://www.domain2.com/manifest.js",
- name: "App2 name"
+ manifestUrl: "http://www.domain.com/manifest2.js",
+ name: "App2 name",
+ context: {
+ name: 'value'
+ }
},
{
appId: "com_companyName_appName3",
- description: "App3 description",
- height:200,
- manifestUrl: "http://www.domain3.com/manifest.js",
- name: "App3 name"
- }
+ manifestUrl: "http://www.domain.com/manifest3.js",
+ name: "App3 name",
+ context: {
+ status: 'ok'
+ }
+ },
];
-
-Container Config
-The F2.js JavaScript SDK provides an API for providers to configure their containers. Every container must be setup using ContainerConfig
and the methods available.
-In the container's $(document).ready()
, add the F2.init()
:
-$(document).ready(function(){
- F2.init({
- //define ContainerConfig properties
- appRender: function(appConfig, html){ ... },
- beforeAppRender: function(appConfig, html){ ... },
- afterAppRender: function(appConfig){ ... }
- });
+
+Requesting Apps On-Demand
+Requesting apps on-demand when the container loads is the traditional way of integrating apps with F2. For the purposes of this example, we will use an example news app from OpenF2.org.
+Let's look at some container code.
+
+Static App Configuration
+First, we define the AppConfig
in a hard-coded _appConfig
variable. This example demonstrates only a single app; if there were multiple apps, _appConfig
would be an array of objects versus an object literal. Secondly, when the document is ready, F2.init()
is called and subsequently F2.registerApps()
with the single argument.
+
+
+This javascript code will insert the example news app into the container's <body>
. Press Result in the jsfiddle above to try this demo.
+Note If more granular control is needed for app placement, use F2.AppHandlers
functionality. Read about that in AppHandlers for App Layout.
+
+
+Dynamic App Configuration
+As an alternative to static app configuration shown above, the _appConfig
variable could be assigned the result of an API call to the F2 Registry. The Registry API response is designed to match the structure of the AppConfig
for passing the JSON straight through to F2 in your code. Whether your app configuration JSON comes from the F2 Registry or your own database is irrelevant; the process is identically the same as shown in this example.
+
+
+About this jsfiddle To simulate an ajax request, this example uses jsfiddle's echo feature. Simply replace the getAppConfigs
function with your own ajax request and ignore the echoData
variable.
+
+
+
+Registering Pre-Loaded Apps
+Incorporating apps which have been pre-loaded or are otherwise already on the container when it loads is an alternative method to integrating F2 apps. This method is useful when the container is being constructed on the server-side (at run-time or on a schedule) and F2 functionality is desired. To use pre-loaded apps, the Container Developer is required to make a request to each apps' AppManifest
and its dependencies before the page is rendered.
+For the following example, let's assume you have a web page composed on the server and all of its HTML is delivered to the browser in one payload. This page also has at least one widget (or component) you'd like to register with F2.js.
+
+1. Setup Container
+To use pre-loaded apps, a web page with a placeholder element for the apps is required. This simple (and empty) web page features a div#news_app.span12
which serves as that placeholder or "root" element.
+<!DOCTYPE html>
+ <head>
+ <title>F2 Container</title>
+ <link rel="stylesheet" href="/path/to/your/bootstrap.css">
+ </head>
+ <body>
+ <div class="container">
+ <div class="row">
+ <div class="span12" id="news_app">
+ <!--app goes here-->
+ </div>
+ </div>
+ </div>
+ <script src="/path/to/your/F2.js"></script>
+ </body>
+</html>
+
+
+2. Request AppManifest
+Next, make a server-side request to the news apps' AppManifest
—the URL is found in manifestUrl
—and capture the resulting JSON. Each AppManifest
contains scripts, style sheets and HTML (more about the AppManifest
). The market news apps' AppManifest
looks like this:
+{
+ "apps":[{
+ "data":{},
+ "html": "<div data-module-name=\"MarketNewsApp\">...</div>",
+ }],
+ "scripts":[
+ "http://www.openf2.org/js/main.js"
+ ],
+ "styles":[
+ "http://www.openf2.org/css/site.css"
+ ]
+}
+Note Parts of this AppManifest
were intentionally removed for legibility, including the required JSONP function name (F2_jsonpCallback_com_openf2_examples_csharp_marketnews
). The full AppManifest
is available on OpenF2.org.
+
+
+Performance Tip
+
+
+Container Developers can use the
AppConfig
and pre-loaded
AppManifest
(from step 2 above) in conjunction with
F2.registerApps()
to speed up the loading of F2 containers. For more information, browse to
Combining AppConfig and AppManifest.
+
+
+
+
+3. Add App to Container
+You're almost there. Next, embed the news app's html
, scripts
and styles
. The F2 app is inserted into .row > .span12
following Bootstrap's scaffolding guidelines. The styles
were appended to the head
and the scripts
were appended to the body
(in this case just one URL for each).
+<!DOCTYPE html>
+ <head>
+ <title>F2 Container</title>
+ <link rel="stylesheet" href="/path/to/your/bootstrap.css">
+ <link rel="stylesheet" href="http://www.openf2.org/css/site.css">
+ </head>
+ <body>
+ <div class="container">
+ <div class="row">
+ <div class="span12" id="news_app">
+ <div data-module-name="MarketNewsApp" id="news_app">...</div>
+ </div>
+ </div>
+ </div>
+ <script src="/path/to/your/F2.js"></script>
+ <script src="http://www.openf2.org/js/main.js"></script>
+ </body>
+</html>
+The example news app is now part of the web page and everything should be functioning properly. The final step is to register the app with F2.
+
+
+4. Assign Root Element to AppConfig
+To use pre-loaded apps, an additional property is required on the AppConfig
object. It is called root
and can be either a CSS selector string or a DOM element. Regardless of type, F2 will parse the value of root
and it must return an existing in-page DOM element. Furthermore, the value of root
must represent a unique DOM element as each app needs its own containing, or root
, element.
+var _appConfig = {
+ appId: 'com_openf2_examples_csharp_marketnews',
+ description: 'Example News',
+ manifestUrl: 'http://www.openf2.org/Examples/Apps',
+ name: 'Example News',
+ root: document.getElementById('news_app')
+};
+Both of these are valid values for the root
property.
+Using JavaScript:
+{
+ root: document.getElementById('news_app')
+}
+Using a CSS selector string:
+{
+ root: '#news_app'
+}
+F2.js uses jQuery internally to parse the value of the root
property and, in turn, jQuery relies on the Sizzle javascript selector library. If a CSS selector string is assigned to root
, it must be a valid CSS 3 selector supported by Sizzle. Refer to the Sizzle documentation for more details.
+
+
+5. Register App
+Since you started with the AppConfig
and now have the AppManifest
from step 2 along with an HTML page containing the embedded app, all that remains is a simple call to F2. Registering pre-loaded apps with F2.js means passing the ammended AppConfig
as shown in the example below.
+var _appConfig = {
+ appId: 'com_openf2_examples_csharp_marketnews',
+ description: 'Example News',
+ manifestUrl: 'http://www.openf2.org/Examples/Apps',
+ name: 'Example News',
+ root: document.getElementById('news_app')
+};
+
+$(function(){
+ F2.init();
+ F2.registerApps(_appConfig);
});
-To see an more detailed example of F2.init()
, look at the sample container javascript file in the F2 repo on GitHub.
-
-AppRender
-The appRender()
method allows the container to wrap an app in extra HTML. The function should accept an F2.AppConfig
object and also a string of HTML
. The extra HTML can provide links to edit app settings and remove an app from the container. See F2.Constants.Css
for CSS classes that should be applied to elements.
-
-
-BeforeAppRender
-The beforeAppRender()
method allows the container to render HTML for an app before the AppManifest
for an app has loaded. This can be useful if the design calls for loading spinners to appear for each app before each app is loaded and rendered to the page.
-
-
-AfterAppRender
-The afterAppRender()
method allows the container to override how an app's HTML is inserted into the page. The function should accept an F2.AppConfig
object and also a string of HTML
.
-For more information on F2.ContainerConfig
, browse to the F2.js SDK docs.
-
-
-F2 UI Mask
-Container Developers have the opportunity to customize some user interface (UI) elements which propagate to the App Developers' toolkit in F2.js. One of those is F2.UI.Mask
. The Mask
object contains configuration defaults for the F2.UI.showMask()
and F2.UI.hideMask()
methods.
-An example of setting the mask in F2.init()
:
-$(document).ready(function(){
- F2.init({
- //define ContainerConfig properties
- appRender: function(appConfig, html){ ... },
- beforeAppRender: function(appConfig, html){ ... },
- afterAppRender: function(appConfig){ ... },
+The web page and pre-loaded news app is a fully F2-enabled container. Rejoice!
+
+
+
+Combining AppConfig and AppManifest
+Container Developers can use the AppConfig
and pre-loaded AppManifest
(from step 2 above) in conjunction with F2.registerApps()
to speed up the loading of F2 containers. The F2.registerApps()
API supports two arguments: appConfigs
and appManifests
. The former is an array of F2.AppConfig
objects and the latter is an array of F2.AppManifest
objects. The appManifests
array must be the same length as the appConfigs
array that is used as the first argument. This can be useful if apps are loaded on the server-side and passed down to the client.
+In the following example, the AppManifest
was pre-loaded and stored in the _appManifest
variable.
+var _appConfig = {
+ appId: 'com_openf2_examples_csharp_marketnews',
+ description: 'Example News',
+ manifestUrl: 'http://www.openf2.org/Examples/Apps',
+ name: 'Example News',
+ root: document.getElementById('news_app')
+};
- //setup UI
- UI:{
- Mask:{
- loadingIcon:'./img/spinner.gif',
- backgroundColor: '#fff',
- opacity: 0.5
- }
- }
- });
+var _appManifest = {
+ "apps":[{
+ "data":{},
+ "html": "<div data-module-name=\"MarketNewsApp\">...</div>",
+ }],
+ "scripts":[
+ "http://www.openf2.org/js/main.js"
+ ],
+ "styles":[
+ "http://www.openf2.org/css/site.css"
+ ]
+};
+
+$(function(){
+ F2.init();
+ F2.registerApps(_appConfig,_appManifest);
});
-Included in the F2.UI.Mask
configuration object are the following properties: backgroundColor
, loadingIcon
, opacity
, useClasses
, and zIndex
. Each of these F2.UI.Mask
properties is detailed in the F2.js SDK docs.
-For more information on F2.UI
, browse to the F2.js SDK docs.
+Important The F2.registerApps()
API supports both an array of objects and object literals for each argument. Internally, F2.js converts the value of each argument into an array using concatenation ([].concat()
). If arrays of objects are used (when there are more than one app on the container), the _appConfig
and _appManifest
arrays must be of equal length, and the object at each index must be a parallel reference. This means the AppConfig
and AppManifest
for the sample news app used above must be in _appConfig[0]
and _appManifest[0]
.
+
-
+
+AppHandlers for App Layout
+New functionality called F2.AppHandlers
was added in F2 1.2, and the conversation about this collection of features occurred in #38 on GitHub. The new AppHandlers
functionality provides Container Developers a higher level of control over configuring app rendering and interaction.
+
+The addition of F2.AppHandlers
replaces the previous ContainerConfig
properties beforeAppRender
, appRender
, and afterAppRender
. These methods were deprecated—but not removed—in version 1.2. They will be permanently removed in a future version of F2.
+
+
+
+Starting with F2 version 1.2, AppHandlers
is the preferred method for Container Developers to manage app layout.
+
+
+The AppHandlers
functionality provides an event-based system for Container Developers' web applications. The addition of a collection of constants in F2.Constants.AppHandlers
shows the primitive set of event types (or hooks) available to developers, including hooks such as appCreateRoot
, appRenderAfter
, appDestroyAfter
and more. (Review the complete F2.Constants.AppHandlers
collection in the F2.js SDK documentation.)
+Using AppHandlers
is as simple as attaching an event handler function to be executed at the appropriate time as determined by the order of operations in F2. To do this there are three functions available on F2.AppHandlers
: getToken
, on
, and off
. We'll review the token concept first as a token is the required first argument in on
and off
.
+
+AppHandler Tokens
+A new feature has been added to F2 as part of AppHandlers
: the event token. The token is designed to be used only by Container Developers to ensure the AppHandlers
listeners are only called by their applications, and aren't accessible to App Developers' code. Container Developers should create a variable for this token in their JavaScript and encapsulate it inside a closure as shown in the example below.
+(function(){
+ var token = F2.AppHandlers.getToken();
+ console.log(token);
+ //outputs a GUID like 'ce2e7aae-04fa-96a3-edd7-be67e99937b4'
+});
+Important The getToken()
function can only be called one-time. It self-destructs to protect the token for Container Developers and therefore Container Developers must call F2.AppHandlers.getToken()
and store its return value before any F2 apps are registered with the container.
+
+
+Default App Layout
+In the unlikely event a Container Developer wishes to append all apps to the <body>
element, no configuration is required. Simply add this code to the container:
+F2.init();
+F2.registerApps(appConfig);
+Appending apps to the <body>
is the default app rendering behavior of F2.
+
+
+Custom App Layout
+F2 AppHandlers
provide event handlers for customized app layout using F2.AppHandlers.on()
and F2.AppHandlers.off()
. The use of on
and off
require both a token and an event type as arguments. The event types, defined as constants in F2.Constants.AppHandlers
, are:
+
+appCreateRoot
+appDestroy
+appDestroyAfter
+appDestroyBefore
+appRender
+appRenderAfter
+appRenderBefore
+
+Review the complete F2.Constants.AppHandlers
collection and their purpose in the F2.js SDK documentation. The order of operations is detailed in F2.AppHandlers.
+
+Appending an App to a DOM Element
+There are many uses for AppHandlers
in Container Developers' applications and they are detailed—including plenty of examples—in the F2.js SDK documentation. Before jumping to that section of the docs, let's look at one of the more common uses for AppHandlers
: targeting the placement of an app into a specific DOM element.
+In the following example, the app will be appended to the #my_sidebar
DOM element on the container.
+var _token = F2.AppHandlers.getToken(),
+ _appConfig = {
+ appId: 'com_example_app',
+ manifestUrl: '/manifest.js'
+ };
+
+F2.init();
+F2.AppHandlers.on(_token, 'appRender', document.getElementById('my_sidebar'));
+F2.registerApps(_appConfig);
+F2 will insert html
from the AppManifest
inside the specified DOM element. The resulting HTML will look like this after registerApps
is called. Take note F2.js adds three class names to the apps' outermost element (f2-app
, f2-app-container
, and com_example_app
for the appId
).
+<div id="my_sidebar">
+ <!--HTML defined in AppManifest inserted here-->
+ <div class="f2-app f2-app-container com_example_app">
+ <div class="f2-app-view" data-f2-view="home">
+ <p>Hello World!</p>
+ </div>
+ </div>
+</div>
+Note The original html
in this example app manifest is available here.
+The jsfiddle below demonstrates a Hello World example using the appRender
event type and a DOM element as the third argument in on
.
+
+
+
+
+Placing Apps in Separate Locations
+Here is a slightly more complicated example of the appRender
event coupled with appCreateRoot
to place two apps in two separate DOM elements.
+
+
+
+
+More AppHandlers
+There are numerous examples shown on the Properties tab of F2.Constants.AppHandlers
. These demonstrate more advanced use of F2.AppHandlers
and aim to provide Container Developers demonstrable low-level control over the life-cycle of app rendering.
@@ -430,7 +708,7 @@ Container-to-App Context
F2.Events.on(
F2.Constants.Events.CONTAINER_SYMBOL_CHANGE,
function(data){
- F2.log("The symbol was changed to " + data.symbol);
+ F2.log("The symbol was changed to " + data.symbol);
}
);
The F2.Events.on()
method accepts the event name and listener function as arguments. Read the SDK for more information.
@@ -472,7 +750,7 @@ App-to-Container Context
F2.Events.on(
F2.Constants.Events.APP_SYMBOL_CHANGE,
function(data){
- F2.log("The symbol was changed to " + data.symbol);
+ F2.log("The symbol was changed to " + data.symbol);
}
);
Note For a full list of support event types, browse to the SDK for F2.Constants.Events.
@@ -495,8 +773,8 @@ App-to-App Context
F2.Events.on(
"buy_stock",
function(data){
- if (data.isAvailableToPurchase){
- F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
+ if (data.isAvailableToPurchase){
+ F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
} else {
F2.log("This stock is not available for purchase.")
}
@@ -548,7 +826,7 @@ More Complex Context
F2.Events.on(
"buy_stock",
function(data){
- F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
+ F2.log("Trade ticket order for " + data.symbol + " at $" + data.price);
//..populate the trade ticket...
//fire the callback
if (typeof data.callback === 'function'){
@@ -567,127 +845,7 @@ Universal F2 Instrument ID
-
-App Integration
-The process of loading apps on a container happens through a method called F2.registerApps()
. The Container Developer must call this method—which accepts two arguments, one required, one optional— after F2.init()
is called. If this method isn't called, no apps can be loaded on the container.
-The two arguments provided to registerApps()
are an array of AppConfig
objects and, optionally, an array of AppManifest
objects. As F2.js parses each AppConfig
, the apps are validated, hydrated with some additional properties, and saved in F2 memory on the container.
-Regardless of where the container's AppConfig comes from, integrating apps is a simple process. For the purposes of this example, we will use an Acme Corp news app.
-Let's look at some container code.
-
-Static App Configuration
-First, we define the AppConfigs
in a hard-coded _appConfigs
array. Secondly, when the document is ready, we call F2.init()
and subsequently F2.registerApps()
with the single argument.
-//define app config
-var _appConfigs = [
- {
- appId: "com_acmecorp_news",
- description: "Acme Corp News",
- manifestUrl: "http://www.acme.com/apps/news-manifest.js",
- name: "Acme News App"
- }
-];
-
-$(document).ready(function(){
-
- //init F2 container
- F2.init({
- //define ContainerConfig properties
- appRender: function(appConfig, html){ ... },
- beforeAppRender: function(appConfig, html){ ... },
- afterAppRender: function(appConfig){ ... },
-
- //setup UI
- UI:{
- Mask:{
- loadingIcon:'./img/spinner.gif',
- backgroundColor: '#fff',
- opacity: 0.5
- }
- }
- });
-
- //load apps
- F2.registerApps(_appConfigs);
-
-});
-This javascript code will insert the Acme Corp news app into the container's DOM, provided the appRender
method is configured correctly.
-
-
-Dynamic App Configuration
-Alternatively, AppConfigs
could live in a database—eventually the F2 Store—at which time container developers could provide their containers with AppManifests
instead of relying on each AppConfig.manifestUrl
property to be retrieved and parsed at run time.
-Such an implementation would require the container developer to make a HTTP call to a Store web service to retrieve AppConfigs
and AppManifests
. You are already familiar with what the AppConfig
looks like, but if you aren't sure what an AppManifest
looks like, take note of this empty manifest.
-{
- "inlineScripts":[],
- "scripts":[],
- "styles":[],
- "apps":[{
- "data":{},
- "html":"",
- "status":""
- }]
-}
-Note Read more about the AppManifest.
-An example of a container making a request to the F2 Store for AppConfigs
and AppManifests
:
-(function(){
-
- var _appConfigs = [], _appManifests = [];
-
- //make request to Store web service
- var $req = $.ajax({
- url: 'https://store.openf2.org/getApps',
- dataType: 'jsonp'
- });
-
- //parse successful response
- $req.done(function(jqxhr,txtStatus){
- jqxhr = jqxhr || {};
- if (jqxhr.status == "good"){
- _appConfigs = jqxhr.appConfigs || [];
- _appManifests = jqxhr.appManifests || [];
- //load
- loadContainer();
- } else {
- F2.log("Store web service did not do something 'good'.", jqxhr, txtStatus);
- }
- });
-
- //handle errors
- $req.fail(function(jqxhr,txtStatus){
- F2.log("Store web service failed.", jqxhr, txtStatus);
- });
-
- //wrap this up so we can call it in $req.done()
- var loadContainer = function(){
- $(document).ready(function(){
- //init F2 container
- F2.init({
- //define ContainerConfig properties
- appRender: function(appConfig, html){ ... },
- beforeAppRender: function(appConfig, html){ ... },
- afterAppRender: function(appConfig){ ... },
-
- //setup UI
- UI:{
- Mask:{
- loadingIcon:'./img/spinner.gif',
- backgroundColor: '#fff',
- opacity: 0.5
- }
- }
- });
-
- //load apps
- F2.registerApps(_appConfigs, _appManifests);
-
- });
- }//loadContainer
-
-})();
-Important The _appConfigs
and _appManifests
arrays must be of equal length, and the object at each index must be a parallel reference. This means the AppConfig
and AppManifest
for Acme Corp's news app must be in _appConfigs[0]
and _appManifests[0]
.
-There are numerous benefits to dynamic app configuration, most notably performance and security. In the dynamic model, AppManifests
have already been requested and loaded before a user opens the container reducing the overall number of outbound HTTP requests. Security is improved because Container Developers have the opportunity to parse and scrub AppManifest
contents before F2.js injects markup in the AppManifest.html
property into the container DOM.
-
-
-
-
+
Secure Apps
Security is a fundamental requirement of any F2 container and many F2 apps. With that in mind, the integration of secure apps on a container requires more attention and effort. The process of app integration remains largely the same for integrating secure apps with one significant addition: a second container.
To support a secured container environment, one of the choices made when writing this specification was the inclusion of an open-source cross-domain in-browser secure messaging library. For this, F2 relies on easyXDM. EasyXDM helps front-end developers safely work around the Same Origin Policy using browser-supported techniques without compromising the user experience. For all browsers, the easyXDM transport stack offers bi-directionality, reliability, queueing and sender-verification.
@@ -775,8 +933,8 @@ Considerations