0 notes &

Extending the Crossrider API

Many times we are asked to add a new feature or parameter to a core Crossrider API. As much as we’d love to do make all of these additions, it is not always possible and may also take some time to implement.

Often we are busy building key roadmap features or keeping ahead of the fast-paced browser release schedule to make sure your extension just keep on working.

image

So we’d like to empower you with how to implement some of your requests yourselves. When we built our API, we had you in mind and so we developed our API in JavaScript making it easily to be extended, meaning you can supplement it with your own code to customize it to your own needs.

Let’s take the example of a recent request we received from one of the developers in our community. They asked if we could modify the appAPI.request.get onFailure callback function to also take the original Requesting URL as a parameter. (now’s a good time to review the method).

Now, it’s not particularly difficult to implement, but it is a lengthy process as we must ensure it’s worthy of release:

  1. The product team has to review and approve the feature.
  2. A spec is created and the dev team implements the code changes for all supported browsers in the dev environment, making sure it doesn’t break any existing code and maintains backward compatibility.
  3. The new method is then scheduled for QA testing, again on all supported browsers, and if necessary the extension is sent back for further changes and the second iteration begins.
  4. Only once QA has given its blessing, which is no mean task given how rigorously we test our API, the method is scheduled for inclusion in the next release cycle.

So the bottom line is that it’s not going to happen quickly! This is exactly the case for a developer to extend the core Crossrider API and to share their innovation with the rest of the community.

So what is actually involved in extending the Crossrider API to add the requesting URL to the onFailure callback?

It’s a lot simpler than you think! In the following example, we use a high order function and IIFE to create a private scope for extending the appAPI.request.get method.

// Defensive semicolon
;
appAPI.request.get = (function() {
  /* Save a reference to the original function inside
   *   a "private" scope using the IIFE closure
* / var origRequestGet = appAPI.request.get; // Return the extended request method return function(requestDetails) { /* Save a reference to the extended onFailure callback function. * Save it inside a "private" scope using the closure
*/ var origOnFailure = requestDetails.onFailure; // Redefine the referenced onFailure callback function // using the original request method parameters requestDetails.onFailure = function(httpCode) { /* When callback is invoked, call the extended * onFailure callback function adding the url * details passed to the request
*/ origOnFailure(httpCode, requestDetails.url); } /* Call original request method with the details passed * to the request
*/ origRequestGet.call(appAPI.request, requestDetails); } }());

Another, slightly more complex example is a request we received asking for a deferred promise to be added to the appAPI.db.async and appAPI.request methods. To implement this as an extension to the existing API methods, we made use of the jQuery promise feature as you can see in the following github code.

So now that you’re empowered, give it a try and see for yourself just how easy it is to extend the Crossrider API. Of course, please feel free to share your innovations with the Crossrider developers community (click Share an idea) for the benefit of others.

image

If you are not already a Crossrider developer, click the following link to join our cross-browser extension development framework.

Disclaimer: All code examples provided in this article come as-is and must be fully tested in your own extensions.

Filed under crossrider API Extensions

0 notes &

Your First Green Extension OR How to Save the World from Global Warming with a Few Lines of Code

At Crossrider, we support the initiatives for a greener and better world.

Though you might not really save the world from global warming using this extension, it does give some ideas on how the right code can actually makes electricity consumption more efficient.

Even if it is a small change, on a large scale, it does matter!

image

As you already know, the brighter a screen is, the more electricity it uses, so this is why we’ve created a simple yet effective browser extension that acts as a screensaver that you can easily incorporate into your extensions code as well. 

The screensaver monitors activity in the browser and fades the tab content when none is detected for a period of time, 10 seconds for the purpose of this demonstration.

Once activity is resumed, the screen saver is removed and the browser returns to you.

image

So let’s get started by creating a new extension (My Extensions > Create New Extension),

image

and then heading over to edit the code (Edit Code > extension.js).

For this extension, we will create a resource file to store our CSS and code in the Extension Page Scope (extension.js). First, let’s add the CSS resource file (style.css) and add the following CSS for styling the element used for fading the tab content.

#x-green-saver {
  background-color:#000000;
  border:none;
  border-radius:0;
  height:100%;
  left:0;
  margin:0;
  opacity:0;
  padding:0;
  position:fixed;
  top:0;
  width:100%;
  z-index:-9999;
}

#x-green-saver.enabled {
  z-index:99999;
}

#x-green-saver p {
  color:#444;
  font-family: Rockwell, Georgia, "Times New Roman", Times, serif;
  font-size: 18px;
  position:fixed;
  right:20px;
  text-shadow: 0 1px 0 #666;
  top:20px;
}

Next, we’ll add the code that manages the screensaver functionality using the following top-level algorithm:

  1. Inject the CSS rules in style.css to the page being viewed (uses appAPI.resource.includeCSS)
  2. Inject the div used for dimming the tab content
  3. Use jQuery to add an event handler for detecting activity in the browser and resetting screen saver
  4. Add the interval check to determine whether to fade the tab content (uses appAPI.setInterval, Crossrider’s cross browser setInterval method)
  5. Add a helper function that generates the text for showing the elapsed time on the screen saver

The finished code looks like this:

appAPI.ready(function($) {
  var Timeout = 10, // default timeout before screensaver is activated
      _counter = 0, // counts elapsed inactivity in seconds
      _enabled = false; // screensaver status
  
  // Inject the CCS rules in style.css to the page being viewed
  appAPI.resources.includeCSS("style.css");
  
  // Inject the div used for dimming the tab content
  $('<div id="x-green-saver"><p>Last activity: <span></span> ago</p></div>')
    .appendTo('body');
//  Use jQuery to add an event handler for detecting activity in the browser and resetting screen saver
$(document)
    .on('click mousemove keypress', function() { // checks activity of mouse and keyboard
      _counter = 0; // resets the counter
      if (_enabled) { // resets the content fade if active
        $('#x-green-saver')
          .animate({opacity: 0}, 500)
          .removeClass('enabled');
        _enabled = false;
      }
    });
    
  // Add the interval check to determine whether to fade the tab content 
  appAPI.setInterval(function() {
    if (++_counter >= Timeout) { // If no activity is detected for Timeout seconds
      if (!_enabled) { // Activate the screensaver if it’s not currently active
        $('#x-green-saver')
          .addClass('enabled')
          .animate({opacity: 0.95}, 1000);
        _enabled = true;
      }
      $('#x-green-saver span').text(counterText(_counter));
    }
  }, 1000);
  
// Add a helper function that generates the text for showing the elapsed time on the screen saver
  function counterText(sTime) {
    var sec_num = parseInt(sTime, 10),
      hours = Math.floor(sec_num / 3600),
      minutes = Math.floor((sec_num - (hours * 3600)) / 60),
      seconds = sec_num - (hours * 3600) - (minutes * 60);
      
    return ((hours) ? hours + ((hours === 1) ? ' hour ' : ' hours ') : '') +
           ((minutes) ? minutes + ((minutes === 1) ? ' minute ' : ' minutes ') : '') +
           seconds + ((seconds === 1) ? ' second' : ' seconds');
  }
});

It’s that simple and a step forward in developing greener extensions. Give it a try, feel free to improve the code, and see for yourself just how easy it is to use our platform.

Finally, you are invited to try our Green Saver demo extension and rise to the challenge of making your own cool page action extensions. Get started quickly by cloning the demo extension.
Edit Code > image

If you are not already a Crossrider developer: click the following link to join our cross-browser extension development framework.

Filed under crossrider browser extension green energy

0 notes &

Mozilla Releases Firefox 31 - Promises Interesting New Features

Mozilla’s newest release of Firefox, version 31, promises some interesting new features that can help developers design and build extensions.

image

Here are some of the key features that can help speed up UI design and make debugging easier:

UI Design Improvements

  • CSS3 variables: You’re used to variables for coding, but now with support for CSS3 variables you can use them to enforce consistency and facilitate maintenance of your style sheets.
  • Eyedropper Tool: If you, like many other developers, have resorted to installing an eyedropper add-on, you’ll be pleased to know that it’s now provided natively. Start using this neat feature today (Developer > Eyedropper).
  • Box Model Enhancements: Firefox 30 introduced the new box model representation. With Firefox 31, you can edit the properties directly in the model and see the effects immediately.

Coding Improvements

  • Error Messages with Stack Trace: Firefox 31 introduces console error logs that display a full stack trace, making console.error() a more useful debugging tool.
  • Styling Messages: Firefox 31 is catching up with some of Chrome’s long standing features and this is one were particularly fond of. Using the “%c” format specifier, you can add style to you console messages.
  • New JS Array Fill Method: Starting with Firefox 31, you can use the nifty fill() method to auto-fill array elements with a static value.

Of course, we at Crossrider have been working hard to ensure your existing extensions will continue to work on this latest release and are already preparing for the next.

0 notes &

Why Microsoft’s launch of IE Developer Channel Matters

Microsoft’s announcement of the launch of the Internet Explorer Developer Channel is important for the entire web development community.

You can access it from here: http://devchannel.modern.ie

This is great news for IE developers and developers in general who can now look forward to getting an early peek at new features.

image

But it is much more than that. It is a change in Microsoft’s mindset which until now has neglected their browser and was lagging behind the other leading browsers such as Chrome (Canary) and Firefox (Aurora).

This indicates that Microsoft now understands that their browser must keep up with the pace set by others in order to survive.

We hope that this is a new direction for Microsoft, paying more attention to developers in general and to their browser specifically, will eventually also lead to a faster release cycles.

What does this mean for Crossrider developers? It means that we, at Crossrider, will be better able to prepare for future IE releases and ensure that our APIs and features work for you when new IE versions are released.

 

Filed under internet-explorer ie microsoft crossrider browser extension browsers developers web developers cross-platform

0 notes &

Enhancing Your Browser Extension with Crossrider’s Page Action API

Ever noticed the cool icons that appear by the URL and thought hey, I want one of those? Look no further than Page Actions, the handy icon that appears inside the address bar on selected web pages.

image

In this post, we will demonstrate how you can add page actions to your extensions and configure their tooltips, icon, and popup/click event handlers. There are various page action methods for doing this, but for the purpose of this blog, we will demonstrate two ways of setting up and configuring page actions.

The idea is for the extension to add a tweet page action to all pages other than twitter.com. On twitter.com, the extension adds a page action to display a random quote.

Note: Currently, page actions are only available on Chrome and Firefox.

So let’s get started by creating a new extension (My Extensions > Create New Extension),image

turning on the Page Actions feature for the extension (Settings > Page Actionsimage

and then heading over to edit the code (Edit Code > extension.js).

The code, written in the Extension Page Scope (extension.js), determines which page is being viewed using appAPI.isMatchPages and adds the relevant page action using appAPI.pageAction methods.

We’ll start by adding the page action logic and code to the extension.js file:

appAPI.ready(function($) {
  // Determine if page being viewed is on twitter.com
  if (appAPI.isMatchPages("*twitter.com*")) {
    // Set the page action’s icon and hover text
    appAPI.pageAction.setResourceIcon({resourcePath: 'images/quote.png'});
    appAPI.pageAction.setTitle({title: 'Show quote'});
    // Clicking page action opens a popup with displays quote
    // using resource file popup.html
    appAPI.pageAction.setPopup({
      resourcePath:'popup.html',
      height: 300,
      width: 500
    });
  } else { // We are not on twitter.com
    // Use consolidated page action method that sets all the parameters
    appAPI.pageAction.setPages({
      // pages property: Only show on pages other than twitter.com
      // For demonstration purposes only. This is not needed since the
      // code block is only called when not on twitter.com
      pages: [/^((?!twitter\.com).)*$/],
      iconResourcePath:'images/twitter.png',
      title: 'Tweet this page',
      callback: function() { // onClick action
        // Open twitter dialog in a new window
        appAPI.openURL({
          url: 'http://twitter.com/intent/tweet?url='+encodeURIComponent(location.href),
          where: 'window',
          left: 100,
          top: 100,
          height: 200,
          width: 500
        });
      }
    });
  }
});

Next, we’ll add the add the random quote code to the popup.html file using appAPI.request.get to retrieve the quote and jQuery to display the quote in the popup body:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
function crossriderMain($) {
  // Get the quote from a remote site
  appAPI.request.get({
    url: 'http://iheartquotes.com/api/v1/random?format=html',
    onSuccess: function(response) {
      // inject the HTML response into the popup body
      $(response).appendTo('#quote-wrapper');
    }
  });
}
</script>
</head>
<body>
<div id='quote-wrapper'></div>
</body>
</html>

It’s a simple as that!

Now, watch the following video to see page actions at work:

Give it a try and see for yourself why our platform is so popular!

Finally, you are invited to try our Twitter Page Action demo extension and rise to the challenge of making your own cool page action extensions. Get started quickly by cloning the demo extension.

Edit Code > 

If you are not already a Crossrider developer: click the following link to join our cross-browser extension development framework.

Filed under browser extension crossrider browser chrome firefox addons

0 notes &

Tracking your Crossrider Extension usage using the Google Analytics Universal API

Crossrider extensions are renowned for their ease of development and cross browser compatibility. Google Analytics is synonymous with gathering essential monitoring data for determining the success of a project. By combining them you can gain a real insight into how your extension is being used and measuring user activity.

Google’s Universal Analytics API (UA) allows us to measure unique user activity that was not previously possible using Google’s Classic Analytics API as it was based on cookies that are not natively available in the extension scope.

In this post, we will demonstrate how you can add UA to your extensions and track unique user activity. For the purpose of this demonstration, we will show you how to add Page View and Event Tracking data to pages on which your extension runs.

So let’s get started by creating a new extension (My Extensions > Create New Extension) …

image

and heading over to edit the code page (Edit Code > extension.js).

image

Before we start coding, let’s identify the key requirements for working with the UA API :

1. The API uses either the HTTP (http://www.google-analytics.com/collect ) or HTTPS (https://ssl.google-analytics.com/collect) protocol.

2. The API uses the POST method to send user interaction data (payload).

3. The data collected for UA is sent as a payload object that requires the following parameters in every post:

  • Protocol Version (v) : The protocol version

  • Tracking ID (tid): The tracking ID that distinguishes to which Google Analytics property to send data

  • Client ID (cid): An ID unique to a particular visitor / user. For this demonstration we use the browser specific id of the user who installed the extension (appAPI.appInfo.userId).

  • Hit Type (t): The type of interaction collected for a particular user

For information about payload parameters, see Measurement Protocol Parameter Reference.

Since we will be posting to UA multiple times, for this demo we decided to implement a simple Analytics object that contains the required parameters and a post method. The post method takes an object that describes just the hit data part of the payload (intelligently filling in the required parameters) and uses our appAPI.request.post method to send the data. Additionally, we decided to automatically detect the current page protocol to determine which UA URL to use for posting.

The following code shows how the Analytics object is implemented:

var Analytics = (function () {
  var _internal = {
    // Automatically set the URL according to the page protocol
    url: window.location.protocol +
      ((window.location.protocol.indexOf('https:') === -1) ?
      'www' : 'ssl') + '.google-analytics.com/collect'
    }, _config = {
      // Required UA payload parameters
      trackingId: 'XX-NNNNNNNN-N', // <-- Change to your tracking Id
      clientId: appAPI.appInfo.userId,
      version: 1
    };

  // Methods
  return {
    // Method to post hit to UA
    post: function(payload) {
      // Intelligently fill on required parameters
      payload.tid = payload.tid || _config.trackingId;
      payload.cid = payload.cid || _config.clientId;
      payload.v = payload.v || _config.version;

      // Post payload to UA using our request API
      appAPI.request.post({
        url: _internal.url,
        postData: payload
      });
    }
  };
}());

The rest is simply a matter of using the post method of the Analytics object we created (Analytics.post) at the appropriate times and with the appropriate data. For example, to implement the page view data, just add the following code:

// Post Page View data to UA
Analytics.post({
  t: 'pageview', // <-- Hit Type
  dh: window.location.hostname, // <-- Document Host Name
  dp: window.location.pathname, // <-- Document Path
  dt: $('title').text() // <-- Document Title
});

Similarly, to track when the user clicks the button injected by the extension we use Analytics.post in the button’s click event handler, as follows:

// Make some space for the button
$('body').css({'margin-top': '26px'});
// Inject a button to the page
$('<button id="bua-button">Tracking Event</button>')
  .css({position:'fixed', top:0, left:0})
  .click(function() {
    // Post Event Tracking data to UA
    Analytics.post({
      t: 'event', // <-- Hit Type
      ec: 'click', // <-- Event Category
      ea: $(this).attr('id'), // <-- Event Action -- Button Id
      el: window.location.href, // <-- Event Label
      ev: 1 // <-- Event Value
    });
  })
  .appendTo('body');

Putting it all together, the extension.js file looks like this:

appAPI.ready(function($) {
  var Analytics = (function () {
    var _internal = {
      url: window.location.protocol +
        ((window.location.protocol.indexOf('https:') === -1) ?
          'www' : 'ssl') +
        '.google-analytics.com/collect'
    }, _config = {
      trackingId: 'XX-NNNNNNNN-N', // <-- Change to your tracking Id
      clientId: appAPI.appInfo.userId,
      version: 1
    };
    
    return {
      post: function(payload) {
        payload.tid = payload.tid || _config.trackingId;
        payload.cid = payload.cid || _config.clientId;
        payload.v = payload.v || _config.version;

        appAPI.request.post({
          url: _internal.url,
          postData: payload
        });
      }
    };
  }());
  
  // Post Page View data to UA
  Analytics.post({
    t: 'pageview', // <-- Hit Type
    dh: window.location.hostname, // <-- Document Host Name
    dp: window.location.pathname, // <-- Document Path
    dt: $('title').text() // <-- Document Title
  });
  
  // Make some space for the button
  $('body').css({'margin-top': '26px'});
  // Inject a button to the page
  $('<button id="bua-button">Tracking Event</button>')
    .css({position:'fixed', top:0, left:0})
    .click(function() {
      // Post Event Tracking data to UA
      Analytics.post({
        t: 'event', // <-- Hit Type
        ec: 'click', // <-- Event Category
        ea: $(this).attr('id'), // <-- Event Action -- Button Id
        el: window.location.href, // <-- Event Label
        ev: 1 // <-- Event Value
      });
    })
    .appendTo('body');
});

That’s pretty much all there is to it which, of course, is why using UA with Crossrider is such a winning combination ☺

All that’s left to do is view the data in Google Universal Analytics. For testing purposes, we recommend installing the extension and viewing the generated anaytics in real time. After installing the extension, log in to your Anaytics account and navigate to the real time events monitoring page (Reporting > Real Time > Events). You should see a page with the extension’s injected button on the top left, and as you click the button you can see the results immediately appear in the graph, something like the following:

image

Looking at the event breakdown we can see data organised by the payload posted. Hence it is important to spend time choosing meaningful values to send as this can give you a greater insight into how your customers are using the extension and enable you to make informed business/product development decisions.

image

Finally, you are invited to try our Basic Universal Analytics demo extension and rise to the challenge of making the most of your extensions. Get started quickly by cloning the demo extension.

Edit Code > image

If you are not already a member: click the following link to join our cross-browser extension development framework.

0 notes &

Introducing Crossrider Developer Marketplace powered by oDesk

image

We are excited to announce the Crossrider Developer Marketplace (powered by oDesk) and the Crossrider Group on oDesk!

Our new service provides a dedicated marketplace where businesses and individuals requiring Crossrider extensions can post jobs for pre-screened Crossrider Developers to apply for.

So why are we partnering with oDesk? It’s simple really, it worked for us when we started growing rapidly and we had to concentrate on scaling our business; we therefore occasionally sent people to oDesk to find skilled developers to work on their extensions built on our development framework. oDesk helped in this respect, by matching people who wanted to build extensions with skilled web developers with JavaScript experience. It worked so well that we now want to make this service available to everyone, and hence the Crossrider-oDesk partnership is born!

If you are a Crossrider developer, head over to oDesk and join our group to market your Crossrider skills and access exclusive job opportunities. Don’t forget to display the Crossrider group in your oDesk profile, so go ahead and add the Crossrider tag to your skills on oDesk.

If you are a business in need of a cross browser extension, go to oDesk today and post a job for free using the Crossrider skill tag as a criteria.

Crossrider Marketplace

You can also head over to the Crossrider Developer Marketplace for a convenient oDesk interface to find your perfect match integrated directly into our site. To get to Crossrider Marketplace, click the Development Center menu and select Marketplace.

image

Here you can comfortably search for oDesk jobs/developers using the provided filtering criteria such as feedback scores, hourly rate, location, etc.

So start now and realize the benefits of using the Marketplace today!

image

Finally, if you don’t already have a Crossrider developer account, sign-up now and open up a world of possibilities in cross browser extension development. 

If you are an experienced Crossrider developer, join our oDesk group, to add Crossrider to your skills and access exclusive job opportunities.

0 notes &

IE11 and Windows 8.1 Update

As you already might know today (October 17, 2013) Microsoft is releasing their first big update for Win8, simply titled as Win8.1. This update will also include an automatic update for Internet Explorer, bringing the latest version of IE to 11.

Besides presenting improvements such as: WebGL support, faster page rendering, better development and debug console etc. IE11 had some internal extension related changes that required modifications to our platform.

As Crossrider strives to always be several steps ahead of these browser version changes, we had already released the required fixes and updates for all the known issues deriving from that change.

image

Helping our developers sleep better at night and not worry about browser version updates is one of our main goals here at Crossrider.

The only change you need to be aware of is regarding specifically the WebRequest API that will not be supported on IE11/Win8.1. (We are working on a solution for this and we will update soon with more news)

Besides this, all your extensions will keep working as usual and there is no further action required on your end.

If for some reason you do encounter any issue with this latest update or if you have any further questions about this change then please don’t hesitate to contact support@crossrider.com.

The Crossrider Team

Filed under crossrider ie11 win8.1 microsoft internet-explorer

0 notes &

Developing Crossrider Extensions using Sublime Text

image

Today, we are going to introduce to our developers a new and very cool Crossrider API snippets created to make coding extensions using Sublime Text 2 a breeze.

Have you ever wanted to develop Crossrider extensions using your preferred IDE? Missing the Crossrider IDE’s intellisense technology that simplifies coding using our API methods and remembering method parameters? If Sublime is your preferred IDE, there’s no reason to miss out any more.

Our amazing team has put together Sublime snippets, smart templates that insert text for you saving yourself tedious typing and remembering all those parameters. And they couldn’t be simpler to use, simply install the snippets and follow the instructions for using them.

Give it a try and see for yourself how easy and useful they are. If you like them, why not create some for your preferred IDE, send them to us, and we’ll share them with the Crossrider community.

Using the Snippets

Using our snippets is natural and convenient. They automatically appear (like intellisense) as you type our API methods in JavaScript (.js) files.

image

Let’s see it in action. Open a file (e.g. test.js) and start typing our snippet keyword for appAPI.ready (ready). Notice the keyword-sensitive dropdown that appears as you type the keyword, and press Enter or Tab to insert the snippet.

image

Now let’s take a look at how we can speed up keyword searches using a neat Sublime feature that enables you to search snippets by typing ahead. For example, to speed up searching for particularly long keywords such as dbSetFromRemote that can be laborious to type, you can speed up the search by typing significant letters from the keyword such as dbsr.

Note: Keyword searches must always start with the first letter of the keyword.

image

Finally, once the snippet is inserted, you can use Tab to jump between predefined placeholders in the snippet code making it easy for you to customize the code.

Installing Snippets

For your convenience we uploaded the snippets to GitHub, so feel free to use it, tailor it, fork it and contribute back to the project.

On with the installation instructions. First, clone (git clone) or download the project, then locate your Sublime user packages folder, copy the downloaded CrossriderSnippets folder to the user packages folder, and restart Sublime for the changes to take effect.

Tip: The easiest way to find the location of the user packages folder is to create a new snippet (Tools -> New Snippet), attempt to save it making note of the save folder (by default, the user packages folder), and then cancelling the save.

image

Happy coding :)

Filed under crossrider sublime ide developers

0 notes &

Creating a Facebook Notifier Extension in Minutes using Crossrider [SCREENCAST]

Today, we are going to show you how fast and easy it is to create a cross-browser extension using the Crossrider platform and API. In this screencast, we will build a Facebook Notifier in matter of minutes.

The extensions basic functionality is to monitor a user’s Facebook notifications and to display new notifications whenever they are received regardless of which page the user is viewing.

The extension works by obtaining the notifications URL feed and periodically monitoring it by checking for new items. When new items are detected, the extension’s button is updated to indicate the number of new messages and display a notification with the latest message.

Watch the following video to see how easy it is to take the concept and build a fully functioning extension quickly and easily: (You can find the screencast’s full code after the video)

Give it a try and see for yourself why our platform is so popular amongst extension developers!

Finally, you are invited to check our Facebook Notifier Demo Extension and extend it to do more cool things. (Get started quickly by cloning the demo extension from the IDE).

Extension Code

extension.js:

appAPI.ready(function($) {
  // Check that we are on the correct page to extract the feed URL
  if (appAPI.isMatchPages('facebook.com/notifications')) {
    // Check that we haven't already saved the URL
    if (appAPI.db.get('notificationsRss') === null) {
      // Extract the URL and save it to the local database
      appAPI.db.set('notificationsRss',
        'http://www.facebook.com' +
        $('a:contains("RSS")').attr('href')
      );
    }
    // Send message to background to reset button
    appAPI.message.toBackground({ action: 'resetButton' });
  }
  
  // Message listener to receive request to display a notification
  appAPI.message.addListener(function(msg) {
    // If the message is to display the notification
    if (msg.action === 'notify') {
      // Display notification
      appAPI.notifier.show({
        'name':'Facebook-Notifications',
        'title':'Facebook Notifications',
        'body':msg.item,
        'link':msg.link,
        'theme':'facebook',
        'position':'bottom-left',
        'close':false,
        'sticky':false,
        'fadeAfter':5,
        'width':'200px',
        'closeWhenClicked':true
      });
    }
  });
});

background.js:

appAPI.ready(function($) {
      // Set the button icon
      appAPI.browserAction.setResourceIcon('icon.png');
      // Set the the button click event handler
      appAPI.browserAction.onClick(function() {
        // Open the notification page
        appAPI.openURL('http://www.facebook.com/notifications', 'tab');
      });
      
      // Message listener to receive request to reset button
      appAPI.message.addListener(function(msg) {
        // If the message is to reset the button
        if (msg.action === 'resetButton') {
          // Reset the button counter
          appAPI.db.set('badgRssCount', 0);
          // Reset the button badge
          appAPI.browserAction.removeBadge();
        }
      });
      
      // Define and get the RSS URL from the local database
      var notificationsRss = appAPI.db.get('notificationsRss');
      // Periodically perform the callback function, every 5 seconds
      setInterval(function() {
        // Get current RSS URL from local database
        notificationsRss = notificationsRss || appAPI.db.get('notificationsRss');
        
        // Process the notitications feed to find new content
        if (notificationsRss) {
          // Get the feed content (XML)
          appAPI.request.get({
            url: notificationsRss,
            onSuccess: function(response) {
              // Define local variables
              //   items: Extract array of items from response
              //   rssCount: Notification counters from response
              //        and local database
              var items = $('item', $(response)),
                rssCount = {
                  curr: items.length,
                  badg: appAPI.db.get('badgRssCount') || 0,
                  prev: appAPI.db.get('prevRssCount') || items.length
                };
              
              // If there are more items in the response than previously
              if (rssCount.curr > rssCount.prev) {
                // Update badge counter
                rssCount.badg = rssCount.curr - rssCount.prev + rssCount.badg;
                // Update button badge
                appAPI.browserAction.setBadgeText(rssCount.badg + '', [255,0,0,255]);
                // Save updated badge count to local database
                appAPI.db.set('badgRssCount', rssCount.badg);
                // Extract text of latest notification
                var itemText = items.html().match(/<\!\-\-\[CDATA\[<a href\S+?-->(.+?)\]\]>/)[1];
                // Send a message to the active tab with the details
                // of the latest ticket to display a notification
                appAPI.message.toActiveTab({
                  action: 'notify',
                  item: itemText,
                  link: itemText.match(/.*?href="(.+?)".*/)[1]
                });
              }
              // Save updated previous count to local database
              appAPI.db.set('prevRssCount', rssCount.curr);
            }
          });
        }
      }, 5 * 1000);
    });

Filed under crossrider javascript api extensions browser extension