Investigate spec changes to support inline gadgets
Background
The current implementation in Apache Shindig only supports rendering content either using IFrames or Caja. In enterprise scenarios where the OpenSocial container may be rendering gadgets from other common components/products, many of these applications are considered to be trusted. In these cases the applications do not need to be sandboxed in the same manner as third-party content. In many instances, these applications share common frameworks, css, etc. A container should be able to better manage resources included , shared js and css files. When moving these scenarios over to a mobile environment where there are additional limitations with the device and bandwidth, this has an even greater impact.
While it's relatively simple to inline the content within the page itself, there are areas where additional changes in the gadget metadata would be needed to make it easier to address inlining with shared resources in mind. The goal of the proposal is to make it easier for a container to manage the inline gadgets and shared resources, while minimizing the impact to a gadget developer. The specification changes support the ability for a developer to opt in in the case where they prefer to participate in a trusted scenario. By default,the gadget will be rendered using IFrame.
Use Cases
Phillip(gadget developer) develops a gadget which can support inline rendering. If this gadget is installed in an enterprise environment where it is trusted and inlining is supported, it would be rendered inline. While if this gadget is installed in the outside environment where it is untrusted or in an environment not supporting inlining, it would be rendered in an iframe. The same gadget code/markup works with both inline and iframe rendering.
Proposed spec change
We propose to add one optional renderTypesSupported attribute to the ModulePrefs. The renderTypesSupported attribute can be multi-value if a comma separated list of values representing each supported type is provided, for example: renderTypesSupported="iframe, inline, cajoled" which indicates the types of rendering the gadget supports. If this attribute is not defined, it will be iframe by default. IFrame is a required rendering type, a gadget can't say it doesn't support being in an iframe.
1. Basic inline support: Gadget developer indicates whether the gadget supports being inlined by an attribute named "renderTypesSupported", such as:
<Module> <ModulePrefs title="hello world" renderTypesSupported="inline, iframe"> .................. </ModulePrefs> <Content type="html"> .................. </Content> </Module>
We will implement inline as a new Shindig feature, if the gadget will be rendered inline, the inline feature related libraries will be returned with the gadget rendering request.
2. Namespace solution: To support multiple inline gadget instances on one page, there are some guidelines for the gadget developer to follow:
1). Prefix all the fixed DOM id with _MODULE_ID. Although the browsers can tolerate having duplicate IDs, but from accessibility perspective, it's a violation. Based on IBM's experience with iWidgets in this area, we recommend gadget developers to prefix the DOM id with __MODULE_ID_.
2). Use scope object to encapsulate all the javascript object in gadget XML. To support scope object, a new feature called context is introduced. There are two options :
A. Gadget developer indicates the scope name directly as a ModulePrefs attribute in gadget XML, such as :
<ModulePrefs title="SampleGadgetWithScope" scope="org.apache.shindig.sampleGadget" > <Require feature="context"></Require> ............ <script type="text/javascript"> org.apache.shindig.sampleGadget = function (){ // the js code gadget will use }
This option is similar to the iWidget implementation and the scope name is unique for every gadget. The gadget developer need ensure the scope name is a valid string to be used to create a new js object.
B. Gadget developer doesn't indicate the scope name directly in gadget XML, just use a constant "_SCOPE_MODULEID_" to indicate the scope name.
<ModulePrefs title="SampleGadgetWithScope"> <Require feature="context"></Require> ............ <script type="text/javascript"> __SCOPE_MODULEID__ = function (){ // the js code gadget will use }
The container during gadget initialization will handler the constant and replace it to a real name, such as “org.apache.shindig.sampleGadget+moduleId”to avoid some unexpected scope name, and create the instance of this object for the gadget's use. This option ensures the scope name is a valid name, and doesn't introduce new attribute (scope) to the spec.
3) Instead of calling 'gadgets.util.registerOnLoadHandlers', define a 'onLoad' method to call the init function. If 'gadgets.util.registerOnLoadHanlders' is called directly in the gadget, the instance 'this' should ensure all the functions defined in the scope object can be called correctly.
4) Each gadget instance will expose a global context with the scope property . When gadget developer calls some method of the scope object, it's required to use the context as the prefix, such as '__MODULE_ID__context.scope.changeState'.