WOA for developers

As advanced user, you can perform the following stuff:
  1. Extend our framework with new collectors and supporting new mechanisms for creating concept templates.
  2. Extend our framework with new concept decorators
  3. Create your own application and use our WOA library for requesting existing decorated concepts and interact with them from your code.
In the first case you just need pure javascript programming skills to manipulate the collected elements and process them. In the second case, you also have to be capable of manipulating elements by pure javascript instructions, but this time you will be also offered with the WOA library for accessing the stored decorator classes and concrete concept instances. Finally, in the third case you will need -at least- a set of front-end programming skills; you will have to create your own Web application and consume the concept instances from the WOA library.      

1. Extending collectors

Extending Collectors requires to define a new AbstractCollector subclass. Consider a scenario where you want to support the template creation from MicroData attributes embedded in the HTML elements of the current Web page. So, first we need to validate that an element has defined such attributes. Consider the following piece of code:  

<div class="review" itemscope itemtype="http://schema.org/Review"> <div class="product" itemprop="itemReviewed" itemscope itemtype="http://schema.org/Book"> <span itemprop="name">The Rabbit House</span>, by <span itemprop="author">Laura Alcoba</span>. </div> <div class="rating" itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating">             Rated with <span itemprop="ratingValue">4</span> of             <span itemprop="bestRating">5</span> </div> </div>

As you can see, you should be particularly interested in the itemscope and itemtype Microdata attributes for a MicrodataConceptTemplate, and in itemscope, itemtype and itemprop for the MicrodataPropertyTemplate. So, you should implement the analyzeDomElement behaviour as a template method of MicrodataCollector class, and override it in MicrodataPropertyTemplate:

function MicrodataCollector (lang){ AbstractCollector.call(this, lang); this.locale = { 'en': { 'from_ui_element':'from embedded Microdata', 'define_a_concept':'Define a concept', 'define_a_property':'Define a property' } }; } MicrodataCollector.prototype = new AbstractCollector(); MicrodataCollector.prototype.analyzeDomElement = function(target){ return (target.dom.hasAttribute("itemscope") && target.dom.hasAttribute("itemtype")); }

Then, you should extend the class. Let's say with a MicrodataConceptCollector subclass:

function MicrodataConceptCollector(lang){ MicrodataCollector.call(this, lang); }
MicrodataConceptCollector.prototype = new MicrodataCollector();

You need to define the renderMenuItemFrom method, for making the Collector visible for user interaction. It's as simple as calling the renderMenuItem method with an id for the item, a label (user readable string), a parent menu to be added (ui.conceptsMenu or ui.conceptsMenu), and a callback function.

MicrodataConceptCollector.prototype.renderMenuItemFrom = function(ui){
    this.renderMenuItem( ui, {
        id: 'woa-concept-from-xpath',
        label: this.getLocale('from_ui_element'),
        menu: ui.conceptsMenu,
        callback: function(){ui.sidebarWorker.port.emit('createConcept')}
    });
}

Then, you need to process the extracted data. You can use an API for interpreting the microdata attributes, you can request the referenced element in itemtype, or you can simply analyze the DOM element. In this example, for simplicity and agility, we merely interpret the name by analyzing the string. You need to implement all this related extraction mechanism when loading the concept-creation form, by implementing the loadMaterializableOptions method where you will receive a ui instance that let you easily obtain some user interface related elements. E.g. you can easily obtain the sidebar document for manipulating the existing interface (name, tag inputs, title label, xpath options) or adding new elements to it.

MicrodataConceptCollector.prototype.loadMaterializableOptions = function(ui){

    var document = ui.getSidebarWindow().document;

    var extractedTag = this.target.dom.getAttribute("itemtype");
    if( extractedTag) {
        extractedTag = extractedTag.split('/').pop().replace(/([A-Z])/g, ' $1').trim().toLowerCase();
        document.getElementById('edit-concept-tag').value = extractedTag;
    }
    ...
}

That is all you need to define, because saving a concept is the same in all cases; the only difference relies in how much of the required data we can infer instead the user. While you save a concept, as you can see in the following snippet, the collector should be capable of generating the materializable object so it can be stored in the WOA database.

var collector = this;
document.getElementById('save-concept').onclick = function(evt){

    var sdb = ui.getSidebarWindow().sidebar;
    if(sdb.ui.validateConcept()){
        ui.sidebarWorker.port.emit('storage.createConcept', JSON.stringify(collector.getMaterializable(ui)));
    }
};

Implementing that is as simple as returning a JSON with the values entered in the form. It is mandatory to use a JSON object because it will be serialized for communicating it through the ports of the extension. If you need a final extra processing of the data, you can override the getMaterializable method.

Finally, take into account that the allowed tags for concepts are the labels of the entities defined in http://dbpedia.org/ontology/ (see this example) and the ones for properties are the related ones (see this query example).

2. Extending decorators

A decorator is responsible for adding behavior to the concept. If you want to create your own decorator for supporting some functionality not covered by the decorators provided by WOA, you extend any of them, as the one we present below:

function GenericDecorator(concept){
    AbstractDecorator.call(this, concept);
    this.tags.push('*');   
    this.getSelectedMessages = function(){}
    this.highlight = function(){ ... }
    this.orderByName = function(){    ...    }
    ...
}
GenericDecorator.prototype = new AbstractDecorator();
GenericDecorator.getDisplayName = function(){ return "Generic"; }
GenericDecorator.getMessages = function(){
    return [
        {id:"highlight", name:"Highlight in Web page", showInUI:true },
        {id:"orderByName", name:"Order by name", showInUI:true, properties:[{"id": "name", "name": "Name"}]},
        ...
    ];
}

Suppose you want to extend the AbstractDecorator superclass. You should define a new class, as we did with GenericDecorator, and define some tags that make it possible for WOA to find and retrieve the decorator. You should also implement as a function every message you want to expose to the user, and then include each of the method names in the array that is retured by the getMessages method. The elements of such array are objects with not only the name of the method, but also an id, some required properties (if it applies) and showInUi with a boolean value, that allow WOA to know if it should be exposed to the user.

It is important to note that you can implement the class methods by using prototype, but the instance methods must not be implemented this way, because this way it is not possible to clone them through contexts (e.g. from the extension environment to the sidebar or current Web page's document).

3. Developing and importing your own application

Importing your own application is a very flexible option, since it lets you create a Web application with no restrictions on what kind of resources can be used; the same rules as the ones for a regular Web application are applied. The only requirements are:

1. to start using WOA library when the extension has sucesfully loaded the WOA object in the context of the application document, that is, defining a initWoaScript function that will be called by the extension when everything is ready.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>DR News Dashboard</title>
        <meta charset="UTF-8"/>
        <!-- ... -->
        <script type="text/javascript">
            window.addEventListener("DOMContentLoaded", function(){

                this.initWOAscript = function(){
                    WOA.initSubset();
                    WOA.filterByTag('news');
                    WOA.filterByOrigin('http://www.diarioregistrado.com/*');
                    WOA.filterByAttribute('title', 'ARSAT');
                    WOA.decorate('News');
                    var news = WOA.getInstances();

                    for (var i = 0; i < news.length; i++) {
                        drawInDashboard(news[i].getRepresentation());
                    };

                    WOA.clearFilters();
                    ...
                }
            });
        </script>
    </head>
    <body onload=""> <!-- ... --> </body>
</html>

2. to create a file in the root folder named "package.json", wich contains the manifest data for your application. The required attributes are: a) id, to be used as the namespace, b) name, to be displayed in the apps management and c) index, to specify and load the main entry file. It could look like this one:

{
    "id": "dr-dashboard@lifia.info.unlp.edu.ar",
    "name": "MashNews!",
    "version": "1.0.3",
    "description": "A dashboard that consume news from ...",
    "author": "LIFIA",
    "homepage": "http://www.lifia.info.unlp.edu.ar/lifia/es",
    "license": "MPL 2.0",
    "index": "index.html"
}

Then, you have to import the application into WOA. Follow these steps:
  1. Open the sidebar, click the "Applications" tab (at the top-right of the document). Click "Import application".
  2. Navigate to the root directory of your application and select the package.json file. Click "Open".
This will copy the application to a special directory inside your Firefox user profile. From now on, the application will be run from that location every time you run it from WOA sidebar. So, whenever you make changes to the source code, be sure to import the application again or modify the stored source in the WOA special directory.