User:Ketil3/GoogleExtensions

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search

Google Chrome is a web browser. The user can add "extensions" made by Google or others, usually published on Chrome Web Store. This is about how to make such extensions. The examples are focused on Wikipedia Commons.

Adding from Webstore[edit]

Webstore has thousands of extensions.

Choose, download, install, try[edit]

There are many. I add "Earth View" made by Google. Over 1 mill installed.

  1. Click "Add"
  2. Warning: "It can ... and ...". Click "OK"

And voila, each new tab displays an image of the earth. Nice.

Analyze it[edit]

The address bar is unchanged. Ctrl-U gives me the source URL:

 view-source:chrome-extension://bhloflhklmhfpedakmangadcdofhnnoh/index.html

So, the method "chrome-extension" is new (to me), the "bfhl...oh" path name (of the folder) seems like a random string and "index.html" is the usual default page in a folder.

By googling "Ubuntu where chrome stores extensions" I find that extensions are stored here.

 ~/.config/chromium/Default/Extensions/

(Windows should be similar, but maybe not)

And the contents is:

 mypc:~/.config/chromium/Default/Extensions$ ls
 apdfllckaahabafndbhieahigkjlhalf  djcfdncoelnlbldjfhinnjlhdjlikmph  ghbmnnjooekpmoecnnnilnnbdlolhkhi  kanbnempkjnhadplbfgdaagijdbdbjeb  mmfbcljfglbokpmkimbfghdkjmjhdgbg  Temp
 bhloflhklmhfpedakmangadcdofhnnoh  fmphfaaenbdccndfgbkdplhidhchagfk  gighmmpiobklfepjocnamgkkbiglidom  lipakennkogpodadpikgipnogamhklmk  pkedcjkdefgpdelpbcmbmeomcjbeemfm
 clgddkicplcbgjfobecebadodeggpghp  gefiaaeadjbmhjndnhedfccdjjlgjhho  hjmchndlheccnejbaamnbdmehmabemen  mbpmpbhpfcnemgcplhimlolikbljnmig  pnoffddplpippgcfjdhbmhkofpnaalpg

Seems I have 15 extensions? Each in a folder with randomized names. Recognize my new!

The contents in my new extension is just a folder (name is version number), that contains (recognize the "index.html"):

fonts  imageIds.js  images  index.html  main.css  manifest.json  _metadata  namespace.js  onInstall.js  scripts.js

I see folders for fonts and images, Javascript programs (.js, .json), HTML files (.html), CSS styling (.css).

It seems we have to use HTML, CSS, Javascript, images and (perhaps) fonts to make extensions. My guess is we can modify it by e.g. changing these files.

This extension was added from the webstore, I assume it was a .crx file.

Adding from packages (.zip)[edit]

An extension is (as shown above) one or more files. Sometimes you get it as a ZIP file, which is a packaging format.

Find examples[edit]

Google has a page with many examples, each provided in a ZIP file (.zip).

 https://developer.chrome.com/extensions/samples

I particularly like the Hello extension

 https://developer.chrome.com/extensions/examples/tutorials/hello_extensions.zip

Download[edit]

I click and the .zip is stored in my downloads, I open (the .zip) and see a folder "hello_extensions", which I mark and extract to "~/chromeExtensions", which it becomes a new folder. This is where I will be working.

 mypc:ls ~/chromeExtensions/hello_extensions/
 hello_extensions.png  hello.html  manifest.json

These three files is everything. An image (.png), a webpage (.html) and some Javascript data (.json).

Install[edit]

To install this in chrome, go to "Tools" (or similar) in chrome, then "Extensions" and "Load unpacked" (because I just unpacked the .zip). Choose (or enter) the extension area (with me it is "~/chromeExtensions").

It seems to be installed, with an "ID: kbloacoamjocjfndcjciepmnhmbnahop". Not sure what it means. Clicking "details" gives a bit more info. We can obviously "remove" it, reload it (if we have changed it), and look for errors (which will be important when we develop).

Try[edit]

Does it work? What should we expect? It does work, because I see a new icon that says "Hi" (the hello_extensions.png file). Clicking that icon opens a new window (hello.html page).

Modify for Commons[edit]

We could replace the icon with a commons logo. The existing is a 16x16 PNG file.


And we can change the HTML to say "Commons is a nice place".

Make my own extension[edit]

Make its folder[edit]

I add a folder "myExt" to my experimental area.

 mypc: cd ~/chromeExtensions/myExt

(no files)

Manifest[edit]

We MUST make a file called manifest.json. It is formatted as JSON which is the JavaScript Object Notation.

A JSON object is a list of key:value pairs, enclosed in a pair of curly brackets.

Use a text editor and make "manifest.json" contain this text:

  {                           
    "name": "My extension",     
    "description" : "Just a little something useful for my Chrome",  
    "version": "1.0",         
    "manifest_version": 2  
  }

Install[edit]

This can be installed as for the unpacked ZIP ("Load unpacked", choose folder). And it succeeds, but does nothing. Recognize the name, description and version:

 My extension   1.0
 Just a little something useful for my Chrome

You decide these first values in the manifest. Change e.g. the description and Reload. No errors, you see the text change in the list of extensions.

Order tolerant[edit]

The order of key/value pairs is not important:

 {
   "manifest_version": 2,
   "description" : "Just a little something useful for my Chrome",
   "name": "My extension", 
   "version": "1.0"        
 }

Reload and no errors.


Comma intolerant[edit]

Notice how the comma is ONLY between each key/value pair. Not after the last:

 {
   "manifest_version": 2,
   "description" : "Just a little something useful for my Chrome",
   "name": "My extension", 
   "version": "1.0",  
 }

Reload and you get the error:

 Manifest is not valid JSON. Line: 6, column: 4, Trailing comma not allowed.

There has to be a comma between each key/value. Removing one of these commas:

 {                        
   "name": "My extension",     
   "description" : "Just a little something useful for my Chrome",
   "version": "1.0"          
   "manifest_version": 2
 } 

gives error

 Manifest is not valid JSON. Line: 5, column: 5, Syntax error.

It reports line 5, column 5, since this is were it was surprised at seeing a " while waiting for the comma.

Whitespace tolerant[edit]

It tolerates any whitespace (space, line break, tabulators) such as this:

 {                           "name": "My extension",
"description" : "Just a little something useful for my Chrome",  
   "version": "1.0",         "manifest_version": 2
 } 

Reload. No errors. Same behavior.


String breaking[edit]

It is tempting to break long strings:

 {                           
   "name": "My extension",     
   "description" : "Just a little something 
                    useful for my Chrome",
   "version": "1.0",         
   "manifest_version": 2
 } 

Reload. No errors.


JSON missing curly brackets[edit]

You may forget the beginning curly bracket

   "name": "My extension",
   "description" : "Just a little something useful for my Chrome",
   "version": "1.0",         
   "manifest_version": 2     
 } 

Reload, and it reports:

 Manifest is not valid JSON. Line: 1, column: 11, Unexpected data after root element.

Or, you may forget the end curly bracket:

 {                        
   "name": "My extension",     
   "description" : "Just a little something useful for my Chrome",
   "version": "1.0",         
   "manifest_version": 2

Reload, and it reports:

 Manifest is not valid JSON. Line: 7, column: 1, Syntax error.

The file has only 5 lines, so not sure why it reports line 7.

JSON missing quotes[edit]

Both keys and strings are usually strings. A string has to be enclosed in quotes:

 {                           
   "name": "My extension   ,      
   "description" : "Just a little something useful for my Chrome",
   "version": "1.0",         
   "manifest_version": 1
 } 

results in

 Manifest is not valid JSON. Line: 2, column: 38, Syntax error.

Wrong keys[edit]

Change "description" to "descrippion"

 {
   "name": "My extension",
   "descrippion": "Just a little something useful for my Chrome",  
   "version": "1.0",         
   "manifest_version": 2  
 } 

and reload. Notice "Error" goes red. Click and it tells you

 Unrecognized manifest key 'descrippion'

So it does not tolerate unexpected keys.

Missing keys[edit]

Remove the "name" key

 {
   "description" : "Just a little something useful for my Chrome",  
   "version": "1.0",         
   "manifest_version": 2  
 } 

and it again goes red with error:

 Required value 'name' is missing or invalid

So, this is valid JSON, but wrong content

Wrong manifest[edit]

As said above, some values are up to you (the designer). But, it is picky about the manifest version:

 {                           
   "name": "My extension",     
   "description" : "Just a little something useful for my Chrome",
   "version": "1.0",         
   "manifest_version": 1
 } 

which gives error

 The 'manifest_version' key must be present and set to 2 (without quotes). See developer.chrome.com/extensions/manifestVersion.html for details

(it even gave me hints: Do not use quotes).

Your own comments[edit]

One-line comments begin in Javascript begin with // (two slashes) and can be put anywhere to explain things (to us, the readers). The interpreter ignores them.

  // manifest.json for the extension I started today (June 6, 2017)
  // must be in the myExt folder as "manifest.json"
  {                           
    "name": "My extension",     
    "description" : "Just a little something useful for my Chrome",
    "version": "1.0",         
    "manifest_version": 2 // Notice: This HAS to be 2 (not "2"). Hopefully it does not have to be changed to 3 in the next 10 years
  }

Reload. No errors.

Multiline comments are enclosed in /* and */.

  /* 
   manifest.json for the extension I started today (June 6, 2017)
   must be in the myExt folder as "manifest.json"
  */
  {                           
    "name": "My extension",     
    "description" : "Just a little something useful for my Chrome",
    "version": "1.0",         
    "manifest_version": 2 // Notice: This HAS to be 2 (not "2"). Hopefully it does not have to be changed to 3 in the next 10 years
  }

That was it for the manifest. The extension seems OK, it appears in the extension list. But it does nothing, and the user does not see anything.

Icons[edit]

Usually, an extension is "present" visually in the extension "tool bar". As of today (this changes often, it seems), Chrome has it located next to the address, i.e. where the user types in the URL, the address.

Icons are "recognizable pictures", visual representatives I would say, that Chrome may try to load in various situations.

And images are usually stored in files such as a.jpg (JPG format), a.png (PNG), a.svg (SVG).

According to

 https://developer.chrome.com/extensions/user_interface

these are stored in the "icons" of the manifest:

  • 16x16 is the favicon (favorite icon) format
  • 32x32 seems to be useful for Windows
  • 48x48 is shown on the "extension management" page (mentioned above)
  • 128x128 is used in the Chrome Webstore, should it be installed.

Google explains that any format supported by Webkit, will work:

 https://developer.chrome.com/apps/manifest/icons

Webkit? It does rendering in the Apple Safari browser, and previously, in Chrome. But not now?

 https://en.wikipedia.org/wiki/WebKit

Adding one icon[edit]

Icons are indicated in the manifest.

We begin by adding an "icons" key, and a value that is another JSON object: In this object, I add "16", and the filename "icon16.png". My guess is that size 16, will be visually presented within 16x16 pixels (such as the extension toolbar).

 {                           
       "manifest_version": 2,
       "description" : "Just a little something useful for my Chrome",
       "name": "My extension",
       "version": "1.0",
       "icons": { "16": "icon16.png" }
 } 

Icon does not exist[edit]

Reloading myExt results in

 Could not load extension icon 'icon16.png'

(since this file does not exist).

Linking to an existing icon[edit]

The idea of reuse is nice. Trying to link to an image in a different extension

       "icons": { "16":  "../hello_extensionis/icon16.png" }

results in an error. Not specifying exactly what is wrong (since the file actually exists).

Copying an existing icon[edit]

I have my eyes set on that icon file, so I just copy it to my folder and call it "icon16.png":

 mypc: cp ../hello_extension/hello_extension.png ./icon16.png
 mypc: ls 
 icon16.png  manifest.json

and reload. The icon is now visible in the extension toolbar (top right), and "greyed out" it seems. Hovering the pointer over it reveals "My extension", so it looks right.

Inspecting this image file, it is indeed a 16x16 pixel PNG file.

Copying an icon Commons[edit]

Next step is to find some image icon that looks like a Commons or Wikipedia. I search and find this:

https://commons.wikimedia.org/wiki/File:Tango_style_Wikipedia_Selection_Icon.svg

and save it in my folder

 mypc: ls 
 icon16.png  manifest.json  Tango_style_Wikipedia_Selection_Icon.svg.png

change the manifest:

 {
       "manifest_version": 2,
       "description" : "Just a little something useful for my Chrome",
       "name": "My extension",
       "version": "1.0",
       "icons": {
               "16": "Tango_style_Wikipedia_Selection_Icon.svg.png"
       }
 }

Reload, and this image is now used as icon. It is not 16x16 and not PNG, but it is keyed as "16" and Chrome uses it, apparently scaling etc.

Several icon files[edit]

Ideally, as there are man, we should provide "a variety" of icon files, for various of Chromes purposes for various end devices (PC, smartphone, etc). Such as here:

  "icons": {
    "128": "icons/ab-128.png",
     "16": "icons/ab-16.png",
     "32": "icons/ab-32.png",
     "48": "icons/ab-48.png",
     "64": "icons/ab-64.png"
  },

stating that we have (at least) five image files in a subfolder "icons". This excerpt is from the

 ~/.config/chromium/Default/Extensions/gighmmpiobklfepjocnamgkkbiglidom/3.34.0_0/manifest.json

which happens to be the hugely popular AdBlock extension ("ab" prefix).

If AdBlock think 16, 32, 48, 64 and 128 is sufficient, I think it is.

Use one file for all sizes[edit]

Just for "fun", I try:

 {
       "manifest_version": 2,
       "description" : "Just a little something useful for my Chrome",
       "name": "My extension",
       "version": "1.0",
       "icons": {
               "16":  "Tango_style_Wikipedia_Selection_Icon.svg.png",
               "32":  "Tango_style_Wikipedia_Selection_Icon.svg.png",
               "48":  "Tango_style_Wikipedia_Selection_Icon.svg.png",
              "128":  "Tango_style_Wikipedia_Selection_Icon.svg.png"
       }
 }

Reload, no errors. Chrome now has an image also in chrome://extensions/. So apparently it works. That was "fun".

Tooltip[edit]

As mentioned, hovering gives a text. This is the "tooltip", and by default is the extensions name "My extension", which is OK. We can change it by adding to the manifest

   "browser_action": { "default_title": "Commons helper" }

Reload and observe that the tooltip has changed (try by hovering), and the icon is not "greyed out" any longer. It has colors!

Confusingly (I think), this "browser action" lets us specify more icons

     "browser_action": {
         "default_icon": {                    // optional
           "16": "images/icon16.png",           // optional
           "24": "images/icon24.png",           // optional
           "32": "images/icon32.png"            // optional
         },

My guess (have not tried) is that these will override any icons from the "icons" section.

Reacting to icon click[edit]

For now, we see the icon, we see the tooltip, but a click results in nothing, unless we add

     "browser_action": {
       "default_title": "Commons helper",
       "default_popup": "popup.html"
   } 

Reload, and we get OK (no errors).

But, click and a popup window complains about file not found. So, we have to add the file "popup.html" (or whatever filename we indicated).

A first attempt:

 Good morning. Welcome to the Commons helper.

and (no need to reload the extension) the click now gives this text in a separate window.

This text can be formatted using HTML. Such as

  <b>Good morning</b> <br> Welcome to the Commons helper.

Which will add boldfacing and a line break. Anything HTML goes here.


Controlling the browser icon[edit]

Page action (only on certain pages)[edit]

Until now, the extension has been active always. Although it has not done much.

If we want the activity, add

   "page_action": {
     ... (specify conditions)
   }

and the icon will be colorized only if conditions are met. Greyed out otherwise.

And confusingly (again, to me), here is yet another icon specification (in addition to "icons" and "browser_action.default_icon":

   "page_action": {
     "default_icon": {
       "16": "extension_toolbar_icon16.png",
       "32": "extension_toolbar_icon32.png"
     }
   }

My guess, is these override (have priority) over the ones specified elsewhere.


Browser action (always)[edit]

Also here, we specify icons, tooltip and popup. Also, we can specify badge, which is text (max length 4) on top of the browser icon. Such as "63" to indicate 63 new e-mails. Or, "72" to indicate that there are 72 subcategories on this Commons page.

 n = nbrSubcats (currentPage )
 chrome.browserAction.setBadgeText ( { n }, function () { ... } )

(but how to activate)

From a background script[edit]

Let the manifest specify:

 "background": {
   "scripts": ["background.js"],
   "persistent": false
 },

And "background.js" be:

// Called when the user clicks on the browser action.
var n = 17;  
chrome.browserAction.onClicked.addListener(function(tab) {
  // No tabs or host permissions needed!
  consoloe.log (n);
/*
  console.log('Turning ' + tab.url + ' red!');
  chrome.tabs.executeScript({
    code: 'document.body.style.backgroundColor="red"'
  });
*/
});


Purpose (use cases)[edit]

Detect that we are on Commons[edit]

By "being on Commons", I mean we are surfing the Commons, which has the URL

 https://commons.wikimedia.org/wiki/Main_Page

as homepage, whose unique internet (DNS) name being

 https://commons.wikimedia.org/

|may be sufficient as determinator.

As a "page_action":


Usually, the URL reveals where we are. We may use page_action. But, also the content may be used. Page_action or content_script.