I was reading an article on accessible dialogs in web pages, and the author discussed the desirability for screen readers to have the focus trapped in confirm type dialogs until the dialog disappears. The article shows a method for keeping the keyboard focus. It won’t prevent clicking elsewhere, but screen readers navigate by the keyboard rather than the mouse.

1

2

3

4

5

6

7

8

9

10

document.addEventListener("focus",function(event){

vardialog=document.getElementById("my-dialog");

if(dialogOpen&&!dialog.contains(event.target)){

event.stopPropagation();

dialog.focus();

}

},true);

That’s fine, but it relies on event capturing rather than bubbling and applies to mouse clicks as well as keyboard navigation.

Here’s a jQuery plugin that will handle tab and shift+tab events, is keyboard specific and uses event bubbling. It is dependent on jQuery and jQuery UI (for “:focusable”). You could implement “:focusable” yourself to get get rid of the jQuery UI dependency.

Features can be divided into code that runs in the container and code that runs in the gadget. For Apache Shindig (the reference implementation of the OpenSocial container spec), the code that runs in the gadget will be automatically injected by a Shindig servlet when it serves the gadget to the browser. Gadgets tell the container which features they need or support in their ModulePrefs. The Shindig container page will need to request the container specific feature code by including the feature name in its call to the Shindig JS servlet.

Defining features

XML files describing features are used by the OpenSocial server to know where to look for features’ gadget and container code. These XML files also let the server know what dependencies the features have.

Create a single JavaScript file if a feature needs the same code to run in the container and the gadget. If different code is to run in the gadget and container, then separate the feature code into different JavaScript files. For example, my-feature-gadget.js and my-feature-container.js. The JavAscript files can be named anything. The XML will tell the server what the file names are. The XML file containing the feature XML is generally placed into a feature specific folder along with the feature’s JavaScript files.

Feature XML

1

2

3

4

5

6

7

8

9

10

11

12

<feature>

<name>my-feature</name>

<dependency>globals</dependency>

<gadget>

<!-- This code will run in the gadget -->

<script src="my-feature-gadget.js"/>

</gadget>

<container>

<!-- This code will run in the container -->

<script src="my-feature-container.js"/>

</container>

</feature>

The same file can be referenced in both the gadget and container elements if the gadget code is not specific to the gadget or container.

Script tags in the XML could have JavaScript in them rather than referencing a source file.

Shindig and feature XML

Shindig has a features.txt file in its classpath that contains a line for each feature.

features.txt

1

2

3

4

5

6

7

8

9

10

features/globals/feature.xml

features/analytics/feature.xml

features/auth-refresh/feature.xml

features/caja/feature.xml

features/container/feature.xml

features/content-rewrite/feature.xml

features/core.config/feature.xml

features/core.io/feature.xml

features/core.json/feature.xml

...

This file is a list of XML files that Shindig will reference when it needs to locate a feature’s source files. By convention, most features name their XML file feature.xml, but that is not necessary. It can be anything as long as the features.txt file references it. Add a line to features.txt for the new feature, and ensure the folder containing the XML and JavaScript files are where they should be within the features folder.

Feature Code

There is no defined way that a feature must be coded. The code placed in the JavaScript files is just like any other JavaScript. It is executed as is. Unless there is a good reason not to, a good convention to follow is to make feature code available on the “gadgets” global object. The sample code below could be used in either the gadget or container JavaScript.

Feature code

1

2

3

4

5

6

7

8

9

10

11

gadgets.myfeature=(function(){

// Private code

var_x=0,

_getX=function(){return_x;};

// Public interface

return{

"getX":_getX

};

})();

The feature code will then be executed using gadgets.myfeature.getX().

Feature Parameters

Sometimes a gadget will need to provide parameters to a feature. This is done in the ModulePrefs.

Passing a parameter to a feature

1

2

3

4

5

<ModulePrefs>

<Require feature="my-feature">

<Param name="x">10</Param>

</Require>

</ModulePrefs>

Get the parameter in the gadget

Shindig has a method called “gadgets.util.getFeatureParameters(featureName)” which seems like the method to use to get the value of “x”. It won’t work, however, because gadget.util.init never gets called with the gadget metadata. Shindig does call gadgets.config.init with the gadget metadata though, so the config feature can be used to extract the custom feature parameters.

Finding feature parameters from within a gadget

1

2

3

4

5

6

7

8

9

10

11

12

13

varfeatureConfig={

// This is a validator that makes sure the value provided by the gadget is valid

"x":newgadgets.config.RegExValidator(newRegExp("^\d+$"))// Used to validate the param value (positive integers in this case)

},

onConfigReady=function(allFeatureConfig){

varmyfeatureConfig=allFeatureConfig["my-feature"];// You may need to inspect allFeatureConfig to find exactly where the custom feature is

if(!myfeatureConfig||typeof(myfeatureConfig["x"])==="undefined"){

_x=parseInt(myfeatureConfig["x"],10);

}

};

// Register to get notified when we have feature config data available

gadgets.config.register("my-feature",featureConfig,onConfigReady);

The location of the feature parameters within allFeatureConfig could vary depending on the dependencies of the feature. Inspect allFeatureConfig in a debugger to figure out where the parameters is.

Get the parameter in the container

Shindig has a metadata servlet that returns gadget metadata so that the container can load the gadgets as it sees fit. The gadget metadata returned is a JSON object that has the feature parameters in it. It can be accessed as metadata.gadgets[<index of gadget>].featureDetails[“x”].

Shindig Caching

Shindig does not have a way to turn off feature caching, so any additions or changes to files within the feature folder will require a Shindig restart.