Go back to the main page

Modify an existing page with a Chrome extension built using Angular and Yeoman Part 1

 

 


Code from screencast and tutorial is available on Github The screencast has more detail and explanation then this tutorial.

Page altering

We have all seen Chrome extensions like Yesware that modify an existing web page. In the case of Yesware it add features to Gmail like tracking and email templates. This tutorial covers how to make an extension, like Yesware, that alters an existing web page. At the end of this two part series we would have made an extension that adds a 'Search on Bing' button to the Google home page. To aid this endeavor, Angular and Yeoman are going to be leveraged.

Chrome extension, Yesware, gets injected into Gmail adding tracking and templates.

Our goal is to write an Chrome extension that adds a 'Search on Bing' to the Google search page.

  1. Make sure you have latest Node, NPM, and Yeoman installed.
  2. Install the Yeoman generator, generator-chrome-extension
  3. $ mkdir ~/chrome-extensions/binged && $_
    $ npm install -g generator-chrome-extension
    
  4. Have Yeoman create scaffolding for a Chrome extension
  5. $ yo chrome-extension
    
    After running the yo chrome-extension fill out the wizard like so.
    After finishing the wizard a npm && bower install will kickoff. Your directory structure after a successful install should be like this.
  6. Install Binged icon.
  7. curl https://d38ux1iykvusrb.cloudfront.net/articles/111/icon-128.png > app/images/icon-128.png
    
  8. Install Angular
  9. bower install angular --save
    
    After installing Angular with Bower it will show up in app->bower_components->angular
  10. Edit the app/manifest.json to match the below code. You may also delete the background scripts section as they will not be needed.
  11. {
        "name": "__MSG_appName__",
        "version": "0.0.1",
        "manifest_version": 2,
        "description": "__MSG_appDescription__",
        "icons": {
            "16": "images/icon-16.png",
            "128": "images/icon-128.png"
        },
        "default_locale": "en",
      "content_scripts": [
        {
          "matches": [
            "http://*/*",
            "https://*/*"
          ],
          "css": [
            "bower_components/angular/angular-csp.css",
            "styles/main.css"
          ],
          "js": [
            "bower_components/angular/angular.min.js",
            "scripts/contentscript.js"
          ],
          "run_at": "document_end",
          "all_frames": false
        }
      ],
      "content_security_policy": "script-src 'self'; object-src 'self'",
    "web_accessible_resources": [
      "bower_components/angular/*"
    ]
    }
    
  12. Load the extension.
  13. Click 'Load unpacked extension' and navigate to ~/chrome-extensions/binged/app directory.
  14. Bootstrap Angular within app/scripts/contentscript.js
  15. 'use strict';
    
    window.addEventListener("load", function() {
      var app = angular.module('Binged', []);
    
      var html = document.querySelector('html');
      html.setAttribute('ng-app', '');
      html.setAttribute('ng-csp', '');
    
      angular.bootstrap(html, ['Binged'], []);
    });
    
    Since Angular is being added after the page is loaded it will have to be bootstraped. In addition, the ng-csp attribute or the extension will not work.
  16. Add a basic controller. Go the Google search page and open Chrome web inspector in order to find a good element to stick a ng-controller.
  17. The viewport id looks like a good place for an Angular controller.
  18. Go back to app/scripts/contentscript.js and wire up a dummy controller.
  19. window.addEventListener("load", function() {
      var app = angular.module('Binged', []);
    
      var html = document.querySelector('html');
      html.setAttribute('ng-app', '');
      html.setAttribute('ng-csp', '');
    
      var viewport = document.getElementById('viewport');  
      viewport.setAttribute('ng-controller', 'MainController');
      app.controller('MainController', function ($scope) {});
    
      angular.bootstrap(html, ['Binged'], []);
    });
    
  20. Next, let's add a very basic directive.
  21. window.addEventListener("load", function() {
      var app = angular.module('Binged', []);
    
      var html = document.querySelector('html');
      html.setAttribute('ng-app', '');
      html.setAttribute('ng-csp', '');
    
      var viewport = document.getElementById('viewport');  
      viewport.setAttribute('ng-controller', 'MainController');
      app.controller('MainController', function ($scope) {});
    
      var myDirective = document.createElement('div');
      myDirective.setAttribute('my-directive', '');
      viewport.appendChild(myDirective);
    
      app.directive('myDirective', function() {
        return {
          restrict: 'EA', 
          replace: true,
          template: 'Search with Bing'
        };
      });
    
      angular.bootstrap(html, ['Binged'], []);
    });
    
  22. Go back to chrome://extensions and reload.
  23. Every time you make a change to the extension code you must reload.
  24. Go to the Google search page and reload.
  25. After reloading we can see that the basic directive worked fine.

End of Part 1

That is a good place to take a breather. In part 2, I will finish the extension to match the screenshot in the beginning of the article. Again, if you want more detail and explanation make sure to view the screencast.

  • Pushed on 02/17/2014 by Christian