Wednesday, November 5, 2014

MakerSquare Day 50: How to Make a Chrome Extension, For Real This Time (11/2)


  1. the manifest.json: This is what makes the Google Chrome extension. This json file keeps track of everything you want to give this extension: all the permissions you give about what Chrome APIs it can access; all the files it has--background, popup, and content; and information about where the extension can run.
  2. a background file, either background.html or background.js: a background file is basically a pretend page--something the user never necessarily sees, but that helps organize all the other files; if you like visual metaphors, I think of the background as a highway interchange in my app: nothing happens there, but it's a useful nexus for talking between the other files (and also between Chrome itself--the background.js is what tells Chrome to show the little icon).
  3. your popup files, if you have any, often a standard mix of HTML, JavaScript, and CSS: many Chrome extensions have little icons and when you press that icon, you get this little popup window. That window is basically a little webpage: mine has HTML to tell what to show, some CSS to tell how to show it, and a lot of JavaScript to tell how it should behave.
  4. a content script: this is not necessary for all Chrome extensions, but is the only way you can have a Chrome extension directly affect the DOM of a particular webpage. So, I can make a new tab and go to a URL with a background file; but if I want to affect that page once I load it, I need a content script.
So if you have all these different parts, how do we get them to work together? Here's a few remarks on my Chrome extension (still available here):

Basic background: to pass messages between these elements, you need to use a pair of functions--a sendMessage and an onMessage function. So, for instance, when you go to Twitter, my content script runs--because that's what the manifest.json tells it to.

My content script includes this
  1. chrome.runtime.sendMessage({}, function(response) {
  2. storage.get('banned', function(blockedWords) {
  3. var tweets = $('li.js-stream-item');
  4. runBlockedWords(tweets, blockedWords.banned);
  5. });
  6. });
Line 2 here gets something from chrome.extension.storage.sync (which I aliased to the variable storage because I thought I might want to change it to chrome.extension.storage.local). And notice that the storage extension function here involves a callback--because almost every chrome.extension function involves a callback.

So we get an object from storage and we call that object blockedWords; but that object itself has a key named "banned"--which is why Line 4 involves blockedWords.banned, which is the value of "banned" inside blockedWords.

Also, note that this is the content script, so I can use jQuery to directly affect and access the DOM. In this case, I'm grabbing all the tweets that match li.js-stream-item--which is all the tweets currently visible.

Now, on the other side, in my background.js, I have
  1. chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
  2.   chrome.pageAction.show(sender.tab.id);
  3.   sendResponse();
  4. });
Line 3--as I understand it--sends a response message, which ends that message cycle. As you see, I don't have any actual message to send back, so I'm just sending an empty response.

Line 1 is the important part: it listens for a message. From where? From anywhere, I think. It just so happens that background.js will only hear a message when content.js sends a message--and that will only happen on Twitter.

That's important for Line 2, which is where I tell the browser to show the icon for the Chrome extension--but only on the page that sent the message (sender.tab.id).

And that's how I made (at least part of) my Chrome extension.

No comments:

Post a Comment