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

1 note &

From Bookmarklet to Extension in just 5 Minutes

Bookmarklets are short unobtrusive JavaScript commands stored as a bookmark that extend a browser’s functionality. They are great for performing one-click tasks such as posting information to Tumblr, Facebook, Twitter, or querying a search engine, changing the appearance of a page, and much more (see Our favorite bookmarklets).

Have you ever wanted to take the one-click concept a step further and access the same bookmarklets in other ways? In this post, I will demonstrate how you can create cross-browser extensions that install a bookmarklet (Share on Tumblr) that can be activated in any or all of the following ways:

  • Using a browser button
  • Using a bookmark (default)
  • Using the context menu
  • Using a keyboard shortcut

In general, bookmarklet scripts are either short self-contained scripts or they inject a script tag to download code from a remote location. Tumblr uses the first variety, so let’s navigate to their bookmarklet installation page, inspect the Share on Tumblr link element, and grab the code.

image

Notes:

  • When extracting the bookmarklet code, make sure to copy only the actual bookmarklet code since only bookmarks require the javascript: prefix and void(0) suffix.
  • When the bookmark is of the second variety (downloads script from remote location), you simply need to take note of the remote URL.

Now that we have the bookmarklet code, let’s head over to crossrider.com and prepare the building blocks for our extension. We’ll start by (1) creating a new extension, (2) adding the browser buttons feature, (3) uploading the button icon to the resources of the extension, (4) adding the bookmarklet.js resource, (5) pasting the bookmarklet code, and (6) adding the bookmarks plugin.

(1) My Extensions > Create New Extension

image

(2) Settings > Browser Buttons [Turn on Chrome, Firefox, and IE]

image

(3) Edit Code > Resources > Create > Upload [Upload button icon]

image

(4) Edit Code > Resources > Create > Javascript [Create bookmarklet.js file]

image

(5) Edit Code > bookmarklet.js [Add bookmarklet code]

image

(6) Edit Code > Plugins > Add Plugins > Bookmarks [Add bookmarks plugin]

image

Now that the building blocks are in place, let’s concentrate on the code. In our extension we have two types of actions we perform, extending the browser (adding buttons, context menus, and bookmarks) and interacting with the page. The code for these actions must run in their respective scopes, the background scope for extending the browser and the extension page scope for interacting with the page.

Let’s start with the background scope code by adding the title variable that will be used for button tooltips, context menu and bookmarks.

var title = 'Share on Tumblr';

We’ll use the appAPI.browserAction API is used to configure the button:

appAPI.browserAction.setResourceIcon('icon.png'); // Set the button icon
appAPI.browserAction.setTitle(title); // Add the button tooltip
appAPI.browserAction.onClick(runBookmarklet); // Add the onclick event handler

the appAPI.contextMenu API to add a command to the context menu:

appAPI.contextMenu.add('inject-bookmaklet', title, runBookmarklet);

and the appAPI.bookmarks API to add a bookmark if one doesn’t already exist:

appAPI.bookmarks.searchByTitle(title, function(nodes) { // Search for existing bookmark
  if (nodes && nodes.length === 0) { // If existing bookmark not found
    appAPI.bookmarks.getToolbarFolder(function(node) { // Get the bookmarks toolbar
      appAPI.bookmarks.create({ // Create a new bookmark
        title: title, // The bookmark label
        url: urlBookmarklet(), // Returns the bookmarklet as a URL
        parentFolder: node
      });
    });
  }
});

Now, Since the bookmarklet code must run in the page scope and the browser buttons / context menus must be defined in the background scope, we define their callback functions using the appAPI.message API to pass a message to the extension scope requesting that it runs the bookmarklet code.

function runBookmarklet() {
  appAPI.message.toActiveTab({action: 'runBookmarklet'}); // Send message to active tab
}

Lastly for the background scope, the urlBookmarklet function loads the bookmarklet code from the resources file and returns the code wrapped in the javascript: prefix and void(0) suffix required to run as a URL.

function urlBookmarklet() {
  return 'javascript:BOOKMARKLET;void(0);' // Wrap the bookmarklet code
    .replace('BOOKMARKLET', appAPI.resources.get('bookmarklet.js'));
}

Putting it all together, our background code looks like this:

appAPI.ready(function() {
  var title = 'Share on Tumblr';

  appAPI.browserAction.setResourceIcon('icon.png');
  appAPI.browserAction.setTitle(title);
  appAPI.browserAction.onClick(runBookmarklet);

  appAPI.contextMenu.add('inject-bookmaklet', title, runBookmarklet);

  appAPI.bookmarks.searchByTitle(title, function(nodes) {
    if (nodes && nodes.length === 0) {
      appAPI.bookmarks.getToolbarFolder(function(node) {
        appAPI.bookmarks.create({
          title: title,
          url: urlBookmarklet(),
          parentFolder: node
        });
      });
    }
  });

  function runBookmarklet() {
    appAPI.message.toActiveTab({action: 'runBookmarklet'});
  }

  function urlBookmarklet() {
    return 'javascript:BOOKMARKLET;void(0);'
     .replace('BOOKMARKLET', appAPI.resources.get('bookmarklet.js'));
  }
});

Moving on to the extension code, we’ll start by adding a listener to handle requests to run the bookmarklet. When a request is received, the handler calls the runBookmarklet function.

appAPI.message.addListener(function(msg) { // msg is the received data
  if (msg.action === 'runBookmarklet') { // Request to run the bookmarklet
    runBookmarklet(); // Call function to run the bookmarklet
  }
});

Next, we’ll use the appAPI.shortcut API to add the code to run the bookmarklet using a keyboard shortcut (Ctrl+Alt+B):

appAPI.shortcut.add("Ctrl+Alt+B", runBookmarklet, {
  'type':'keydown',
  'propagate':true,
  'disable_in_input':true,
  'target': document
});

And lastly for the extension page scope, the runBookmarklet function loads the bookmarklet code from the resources file and runs it in the extension scope.

Note: The behavior of Bookmarklets that open popups depends on browser implementation.

function runBookmarklet() {
  appAPI.resources.includeJS('bookmarklet.js'); // Load and run bookmarklet
}

Putting it all together, our extension page code looks like this:

appAPI.ready(function($) {
  appAPI.message.addListener(function(msg) {
    if (msg.action === 'runBookmarklet') {
      runBookmarklet();
    }
  });

  appAPI.shortcut.add("Ctrl+Alt+B", runBookmarklet, {
    'type':'keydown',
    'propagate':true,
    'disable_in_input':true,
    'target': document
  });

  function runBookmarklet() {
    appAPI.resources.includeJS('bookmarklet.js');
  }
});

All that’s left to do is to save and install the extension. Now you a free to use the bookmarklet in the following ways:

Using a browser button
image

Using a bookmark (default)

image

Using the context menu

image

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

Finally, you are invited to try our Tumblr bookmarklets demo extension and rise to the challenge of making extensions of our favorite bookmarklets. 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.

Our favorite bookmarklets

  1. Pinterest
  2. Evernote
  3. Tweet this
  4. Facebook share
  5. Posterous
  6. Xray
  7. Firebug Lite
  8. Gmail this
  9. Readability
  10. Printliminator
  11. PageZipper