├── .gitignore
├── README.md
└── examples
├── browsingdata_api
├── icon.png
├── manifest.json
├── popup.css
├── popup.html
└── popup.js
├── commands
├── background.js
├── browser_action.html
└── manifest.json
├── context_menu
├── manifest.json
└── sample.js
├── desktop_capture
├── app.js
├── background.js
├── icon.png
├── index.html
└── manifest.json
├── event_page
├── background.js
├── content.js
├── icon.png
└── manifest.json
├── make_page_red
├── background.js
└── manifest.json
├── my_bookmarks
├── icon.png
├── manifest.json
├── popup.html
└── popup.js
├── my_devices
├── icon.png
├── manifest.json
├── popup.html
└── popup.js
├── notifications
├── 128.png
├── 16.png
├── 48.png
├── 64.png
├── background.js
├── manifest.json
├── options.html
├── options.js
└── style.css
└── set_icon_path
├── background.js
├── icon1.png
├── icon2.png
├── icon3.png
├── icon4.png
├── icon5.png
└── manifest.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learn How to Build Chrome Extensions
2 |
3 | ## Why?
4 |
5 | Chrome Extensions are a *whole other* ***world of opportunity***
6 | to build web-enabled tools!
7 |
8 | ### Quick Facts
9 |
10 | + Almost ***53% of people use Chrome*** to access the Internet on desktop devices.
11 | see: http://gs.statcounter.com/#desktop-browser-ww-monthly-201506-201506-bar
12 | + **Chromebooks** are the ***fastest growing*** segment of the PC market.
13 | In 2014 Chromebooks accounted for 14 percent of all laptop sales for both
14 | the commercial and retail channels; up 85 percent from 2013.
15 | http://betanews.com/2015/02/24/2015-is-year-of-the-chromebook/
16 | Chrome extensions can be build out to be full-blown apps that run in *every*
17 | chrome enviroment.
18 | + Because your Chrome Extensions are
19 | ***written in Standard Web Technologies: HTML+CSS+JavaScript***
20 | you are able to re-use code your Web UI with minimal modification
21 | (*provided its already modular*).
22 |
23 |
24 | ## What?
25 |
26 | Extensions are small programs that can modify and enhance the functionality
27 | of the Chrome browser. You write them using web standard web technologies
28 | (HTML, JavaScript, and CSS).
29 |
30 | Chrome Extensions (*or "Apps"*) allow you to create in-browser tools
31 | which add functionality to the browsing experience.
32 | In our case we want to let the person
33 |
34 |
35 | ## *How*?
36 |
37 |
38 | ## Permissions
39 |
40 | + What are the permissions? https://developer.chrome.com/extensions/permissions
41 |
42 |
43 | ## *Examples*
44 |
45 | ### Browser Action (When the person clicks on the Extension Icon)
46 |
47 | Browser Actions allow you to add an icon to the browser e.g:
48 | 
49 | See: https://developer.chrome.com/extensions/browserAction
50 |
51 | Example of a simple Browser Action is an icon which, when clicked
52 | alters the page background.
53 | See: examples/make_page_red
54 |
55 | ### Display list of Bookmarks
56 |
57 | Uses the bookmarks API to show a list of the person's bookmarks
58 | when they click on the icon (`browser_action`)
59 |
60 | 
61 |
62 | See: examples/my_bookmarks
63 |
64 | ### Change the `src` of Icon when clicked
65 |
66 | Imagine your app wants to change the icon in response to an event or a notification:
67 | That's quite easy with the following line:
68 | ```js
69 | chrome.browserAction.setIcon({path:"icon-notification.png"});
70 | ```
71 |
72 | see: examples/set_icon_path
73 |
74 | ### Access Browser Data (*Delete History*)
75 |
76 | Use the `chrome.browsingData` API to remove browsing data from a user's local profile.
77 |
78 | 
79 |
80 | The API only allows you to `erase` history, so its only useful for a *limited*
81 | set of applications.
82 |
83 | see: https://developer.chrome.com/extensions/browsingData
84 |
85 | ### Using Keyboad Shortcuts in your Extensions
86 |
87 | Using the `commands.onCommand` we can issue keyboard commands to trigger events in our extension.
88 |
89 | The commands are defined in the `manifest.json` file as:
90 |
91 | ```js
92 | "commands": {
93 | "toggle-feature": {
94 | "suggested_key": { "default": "Ctrl+Shift+Y" },
95 | "description": "Send a 'toggle-feature' event to the extension"
96 | },
97 | "_execute_browser_action": {
98 | "suggested_key": {
99 | "default": "Ctrl+Shift+F",
100 | "mac": "MacCtrl+Shift+F"
101 | }
102 | }
103 | }
104 | ```
105 | This can be useful for opening a background page (popup) to read content,
106 | e.g: imaging if your extension provided an instant messaging facility
107 | and you could see the latest messages from any page without needing
108 | to have the messenger open.
109 |
110 | see: https://developer.chrome.com/extensions/commands
111 |
112 | ### Using desktopCapture to Get a Snapshot of the Screen
113 |
114 | `desktopCapture` allows you to capture the client's screen.
115 |
116 | 
117 |
118 | see: examples/desktop_capture
119 | and: https://developer.chrome.com/extensions/desktopCapture
120 |
121 |
122 | ### Get the List of Signed in devices
123 |
124 | The `signedInDevices` API gives you a list of all the devices the
125 | person has signed into using their Google account:
126 |
127 | 
128 |
129 | see: examples/my_devices
130 | API: https://developer.chrome.com/extensions/signedInDevices
131 |
132 | ### Notifications!
133 |
134 | So you want to show people notifications in Chrome...?
135 |
136 | 
137 |
138 | see: examples/notifications for "toast" notifier.
139 | API: https://developer.chrome.com/apps/notifications
140 |
141 |
142 | ### Event Page > Alarms
143 |
144 | > 'declarativeWebRequest' requires Google Chrome beta channel or newer
145 |
146 | See:
147 | + https://developer.chrome.com/extensions/event_pages
148 | + https://developer.chrome.com/extensions/alarms#method-create
149 |
150 | ### History
151 |
152 | Get the page visit history:
153 | https://developer.chrome.com/extensions/history#method-getVisits
154 |
155 |
156 |
157 |
158 |
159 |
160 | ## Questions?
161 |
162 | **Q**: Can we have ***both*** `page_action` ***and*** `browser_action` ?
163 | **A**: No. But you can create multiple extensions and have them inter-communicate
164 | see: http://stackoverflow.com/questions/14519458/google-chrome-extension-browser-page-action
165 | and: https://developer.chrome.com/extensions/extension#event-onMessageExternal
166 |
167 | **Q**: How can we check when the Tab/Page has finished loading?
168 | **A**: Add an event listener:
169 | ```js
170 | chrome.tabs.onUpdated.addListener(function(tabId , info) {
171 | if (info.status == "complete") {
172 | // your code ...
173 | }
174 | });
175 | ```
176 | http://stackoverflow.com/questions/2149917/chrome-extensions-how-to-know-when-a-tab-has-finished-loading-from-the-backgr
177 |
178 | ## Background Reading / Watching
179 |
180 |
181 | ### Videos
182 |
183 | + Google Chrome Extensions: How to build an extension
184 | (Google Developers official):
185 | https://www.youtube.com/watch?v=e3McMaHvlBY
186 | (from 2009 but all the info is still valid)
187 | + Building Your First Chrome Extension:
188 | https://www.youtube.com/watch?v=pT-b2SpFIWo
189 |
190 | ### Guides
191 |
192 | + Getting Started: Building a Chrome Extension:
193 | https://developer.chrome.com/extensions/getstarted
194 | + How to Create a Chrome Extension in 10 Minutes Flat:
195 | http://www.sitepoint.com/create-chrome-extension-10-minutes-flat/
196 | + How to Build a Chrome Extension:
197 | http://lifehacker.com/5857721/how-to-build-a-chrome-extension
198 | + Developing Google Chrome Extensions:
199 | http://code.tutsplus.com/tutorials/developing-google-chrome-extensions--net-33076
200 | + Publishing Your App: https://developer.chrome.com/webstore/publish
201 |
202 | ### Articles
203 |
204 | + Everything You Need To Know About Browser Extensions:
205 | http://www.howtogeek.com/169080/beginner-geek-everything-you-need-to-know-about-browser-extensions/
206 | + What percentage of Internet users use browser extensions?
207 | https://www.quora.com/What-percentage-of-Internet-users-use-browser-extensions
208 | in 2010 33% of Chrome Users had extensions.
209 | I was unable to find more recent data...
210 | (please update if you find recent stats)
211 | + Publishing a Chrome Extension? 7 Tips to Get More Downloads:
212 | http://ecquire.com/blog/how-to-get-more-chrome-extension-downloads/
213 | + Your Chrome Extensions May Be Stealing Your Personal Info: Here's How to Stop Them:
214 | http://digiwonk.wonderhowto.com/how-to/your-chrome-extensions-may-be-stealing-your-personal-info-heres-stop-them-0150766/
215 | (*Privacy ... the reason I don't use any extensions...*)
216 | + Warning: Your Browser Extensions Are Spying On You:
217 | http://www.howtogeek.com/180175/warning-your-browser-extensions-are-spying-on-you/
218 | + Google Chrome Privacy Whitepaper:
219 | https://www.google.co.uk/chrome/browser/privacy/whitepaper.html
220 | + So you want to build a chrome extension:
221 | https://blog.hartleybrody.com/chrome-extension/ (*BuzzKill example* by @hartleybrody)
222 | + What are Chrome Apps? https://developer.chrome.com/apps/about_apps (*they're awesome*!)
223 | + ***Package Chrome Apps for iOS & Android using Cordova***:
224 | https://github.com/MobileChromeApps/mobile-chrome-apps
225 | curious? see: [issues/598](https://github.com/MobileChromeApps/mobile-chrome-apps/issues/598)
226 | + Sadly, the Chrome Android team are not iplementing Chrome Extensions for Mobile.
227 | see: https://www.reddit.com/r/Android/comments/35v8gi/we_are_the_chrome_for_android_team_ama/cr8alzk
228 | (*probably because it would allow ad-blocking*...)
229 |
--------------------------------------------------------------------------------
/examples/browsingdata_api/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/browsingdata_api/icon.png
--------------------------------------------------------------------------------
/examples/browsingdata_api/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "BrowsingData API: Basics",
3 | "version" : "1.1",
4 | "description" : "A trivial usage example.",
5 | "permissions": [
6 | "browsingData"
7 | ],
8 | "browser_action": {
9 | "default_icon": "icon.png",
10 | "default_popup": "popup.html"
11 | },
12 | "manifest_version": 2
13 | }
14 |
--------------------------------------------------------------------------------
/examples/browsingdata_api/popup.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 | * Use of this source code is governed by a BSD-style license that can be
4 | * found in the LICENSE file.
5 | */
6 |
7 | body {
8 | margin: 5px 10px 10px;
9 | }
10 |
11 | h1 {
12 | color: #53637D;
13 | font: 26px/1.2 Helvetica, sans-serif;
14 | font-size: 200%;
15 | margin: 0;
16 | padding-bottom: 4px;
17 | text-shadow: white 0 1px 2px;
18 | }
19 |
20 | label {
21 | color: #222;
22 | font: 18px/1.4 Helvetica, sans-serif;
23 | margin: 0.5em 0;
24 | display: inline-block;
25 | }
26 |
27 | form {
28 | width: 563px;
29 | -webkit-transition: -webkit-transform 0.25s ease;
30 | }
31 |
32 | button {
33 | display: block;
34 | border-radius: 2px;
35 | box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
36 | -webkit-user-select: none;
37 | background: -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5);
38 | border: 1px solid #AAA;
39 | color: #444;
40 | margin-bottom: 0;
41 | min-width: 4em;
42 | padding: 3px 12px;
43 | margin-top: 0;
44 | font-size: 1.1em;
45 | }
46 |
47 | .overlay {
48 | display: block;
49 | text-align: center;
50 | position: absolute;
51 | left: 50%;
52 | top: 50%;
53 | width: 500px;
54 | padding: 20px;
55 | margin: -40px 0 0 -270px;
56 | opacity: 0;
57 | background: rgba(0, 0, 0, 0.75);
58 | border-radius: 5px;
59 | color: #FFF;
60 | font: 1.5em/1.2 Helvetica Neue, sans-serif;
61 | -webkit-transition: all 1.0s ease;
62 | -webkit-transform: scale(0);
63 | }
64 |
65 | .overlay a {
66 | color: #FFF;
67 | }
68 |
69 | .overlay.visible {
70 | opacity: 1;
71 | -webkit-transform: scale(1);
72 | }
73 |
--------------------------------------------------------------------------------
/examples/browsingdata_api/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Popup
5 |
6 |
7 |
8 |
9 | BrowsingData API Sample
10 |
11 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/examples/browsingdata_api/popup.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /**
6 | * This class wraps the popup's form, and performs the proper clearing of data
7 | * based on the user's selections. It depends on the form containing a single
8 | * select element with an id of 'timeframe', and a single button with an id of
9 | * 'button'. When you write actual code you should probably be a little more
10 | * accepting of variance, but this is just a sample app. :)
11 | *
12 | * Most of this is boilerplate binding the controller to the UI. The bits that
13 | * specifically will be useful when using the BrowsingData API are contained in
14 | * `parseMilliseconds_`, `handleCallback_`, and `handleClick_`.
15 | *
16 | * @constructor
17 | */
18 | var PopupController = function () {
19 | this.button_ = document.getElementById('button');
20 | this.timeframe_ = document.getElementById('timeframe');
21 | this.addListeners_();
22 | };
23 |
24 | PopupController.prototype = {
25 | /**
26 | * A cached reference to the button element.
27 | *
28 | * @type {Element}
29 | * @private
30 | */
31 | button_: null,
32 |
33 | /**
34 | * A cached reference to the select element.
35 | *
36 | * @type {Element}
37 | * @private
38 | */
39 | timeframe_: null,
40 |
41 | /**
42 | * Adds event listeners to the button in order to capture a user's click, and
43 | * perform some action in response.
44 | *
45 | * @private
46 | */
47 | addListeners_: function () {
48 | this.button_.addEventListener('click', this.handleClick_.bind(this));
49 | },
50 |
51 | /**
52 | * Given a string, return milliseconds since epoch. If the string isn't
53 | * valid, returns undefined.
54 | *
55 | * @param {string} timeframe One of 'hour', 'day', 'week', '4weeks', or
56 | * 'forever'.
57 | * @returns {number} Milliseconds since epoch.
58 | * @private
59 | */
60 | parseMilliseconds_: function (timeframe) {
61 | var now = new Date().getTime();
62 | var milliseconds = {
63 | 'hour': 60 * 60 * 1000,
64 | 'day': 24 * 60 * 60 * 1000,
65 | 'week': 7 * 24 * 60 * 60 * 1000,
66 | '4weeks': 4 * 7 * 24 * 60 * 60 * 1000
67 | };
68 |
69 | if (milliseconds[timeframe])
70 | return now - milliseconds[timeframe];
71 |
72 | if (timeframe === 'forever')
73 | return 0;
74 |
75 | return null;
76 | },
77 |
78 | /**
79 | * Handle a success/failure callback from the `browsingData` API methods,
80 | * updating the UI appropriately.
81 | *
82 | * @private
83 | */
84 | handleCallback_: function () {
85 | var success = document.createElement('div');
86 | success.classList.add('overlay');
87 | success.setAttribute('role', 'alert');
88 | success.textContent = 'Data has been cleared.';
89 | document.body.appendChild(success);
90 |
91 | setTimeout(function() { success.classList.add('visible'); }, 10);
92 | setTimeout(function() {
93 | if (close === false)
94 | success.classList.remove('visible');
95 | else
96 | window.close();
97 | }, 4000);
98 | },
99 |
100 | /**
101 | * When a user clicks the button, this method is called: it reads the current
102 | * state of `timeframe_` in order to pull a timeframe, then calls the clearing
103 | * method with appropriate arguments.
104 | *
105 | * @private
106 | */
107 | handleClick_: function () {
108 | var removal_start = this.parseMilliseconds_(this.timeframe_.value);
109 | if (removal_start !== undefined) {
110 | this.button_.setAttribute('disabled', 'disabled');
111 | this.button_.innerText = 'Clearing...';
112 | chrome.browsingData.remove({ "since" : removal_start }, {
113 | "appcache": true,
114 | "cache": true,
115 | "cookies": true,
116 | "downloads": true,
117 | "fileSystems": true,
118 | "formData": true,
119 | "history": true,
120 | "indexedDB": true,
121 | "localStorage": true,
122 | "serverBoundCertificates": true,
123 | "pluginData": true,
124 | "passwords": true,
125 | "webSQL": true
126 | }, this.handleCallback_.bind(this));
127 | }
128 | }
129 | };
130 |
131 | document.addEventListener('DOMContentLoaded', function () {
132 | window.PC = new PopupController();
133 | });
134 |
--------------------------------------------------------------------------------
/examples/commands/background.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | chrome.commands.onCommand.addListener(function(command) {
6 | console.log('onCommand event received for message: ', command);
7 | });
8 |
--------------------------------------------------------------------------------
/examples/commands/browser_action.html:
--------------------------------------------------------------------------------
1 | This is a sample browser action popup.
--------------------------------------------------------------------------------
/examples/commands/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Sample Extension Commands extension",
3 | "description": "Press Ctrl+Shift+F (Command+Shift+F on a Mac) to open the browser action popup, press Ctrl+Shift+Y to send an event (Command+Shift+Y on a Mac).",
4 | "version": "1.0",
5 | "manifest_version": 2,
6 | "background": {
7 | "scripts": ["background.js"],
8 | "persistent": false
9 | },
10 | "browser_action": {
11 | "default_popup": "browser_action.html"
12 | },
13 | "commands": {
14 | "toggle-feature": {
15 | "suggested_key": { "default": "Ctrl+Shift+Y" },
16 | "description": "Send a 'toggle-feature' event to the extension"
17 | },
18 | "_execute_browser_action": {
19 | "suggested_key": {
20 | "default": "Ctrl+Shift+F",
21 | "mac": "MacCtrl+Shift+F"
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/examples/context_menu/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Context Menus Sample",
3 | "description": "Shows some of the features of the Context Menus API",
4 | "version": "0.6",
5 | "permissions": ["contextMenus"],
6 | "background": {
7 | "scripts": ["sample.js"]
8 | },
9 | "manifest_version": 2
10 | }
11 |
--------------------------------------------------------------------------------
/examples/context_menu/sample.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // A generic onclick callback function.
6 | function genericOnClick(info, tab) {
7 | console.log("item " + info.menuItemId + " was clicked");
8 | console.log("info: " + JSON.stringify(info));
9 | console.log("tab: " + JSON.stringify(tab));
10 | }
11 |
12 | // Create one test item for each context type.
13 | var contexts = ["page","selection","link","editable","image","video",
14 | "audio"];
15 | for (var i = 0; i < contexts.length; i++) {
16 | var context = contexts[i];
17 | var title = "Test '" + context + "' menu item";
18 | var id = chrome.contextMenus.create({"title": title, "contexts":[context],
19 | "onclick": genericOnClick});
20 | console.log("'" + context + "' item:" + id);
21 | }
22 |
23 |
24 | // Create a parent item and two children.
25 | var parent = chrome.contextMenus.create({"title": "Test parent item"});
26 | var child1 = chrome.contextMenus.create(
27 | {"title": "Child 1", "parentId": parent, "onclick": genericOnClick});
28 | var child2 = chrome.contextMenus.create(
29 | {"title": "Child 2", "parentId": parent, "onclick": genericOnClick});
30 | console.log("parent:" + parent + " child1:" + child1 + " child2:" + child2);
31 |
32 |
33 | // Create some radio items.
34 | function radioOnClick(info, tab) {
35 | console.log("radio item " + info.menuItemId +
36 | " was clicked (previous checked state was " +
37 | info.wasChecked + ")");
38 | }
39 | var radio1 = chrome.contextMenus.create({"title": "Radio 1", "type": "radio",
40 | "onclick":radioOnClick});
41 | var radio2 = chrome.contextMenus.create({"title": "Radio 2", "type": "radio",
42 | "onclick":radioOnClick});
43 | console.log("radio1:" + radio1 + " radio2:" + radio2);
44 |
45 |
46 | // Create some checkbox items.
47 | function checkboxOnClick(info, tab) {
48 | console.log(JSON.stringify(info));
49 | console.log("checkbox item " + info.menuItemId +
50 | " was clicked, state is now: " + info.checked +
51 | "(previous state was " + info.wasChecked + ")");
52 |
53 | }
54 | var checkbox1 = chrome.contextMenus.create(
55 | {"title": "Checkbox1", "type": "checkbox", "onclick":checkboxOnClick});
56 | var checkbox2 = chrome.contextMenus.create(
57 | {"title": "Checkbox2", "type": "checkbox", "onclick":checkboxOnClick});
58 | console.log("checkbox1:" + checkbox1 + " checkbox2:" + checkbox2);
59 |
60 |
61 | // Intentionally create an invalid item, to show off error checking in the
62 | // create callback.
63 | console.log("About to try creating an invalid item - an error about " +
64 | "item 999 should show up");
65 | chrome.contextMenus.create({"title": "Oops", "parentId":999}, function() {
66 | if (chrome.extension.lastError) {
67 | console.log("Got expected error: " + chrome.extension.lastError.message);
68 | }
69 | });
70 |
--------------------------------------------------------------------------------
/examples/desktop_capture/app.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | function gotStream(stream) {
6 | console.log("Received local stream");
7 | var video = document.querySelector("video");
8 | video.src = URL.createObjectURL(stream);
9 | localstream = stream;
10 | stream.onended = function() { console.log("Ended"); };
11 | }
12 |
13 | function getUserMediaError() {
14 | console.log("getUserMedia() failed.");
15 | }
16 |
17 | function onAccessApproved(id) {
18 | if (!id) {
19 | console.log("Access rejected.");
20 | return;
21 | }
22 |
23 | navigator.webkitGetUserMedia({
24 | audio:false,
25 | video: {
26 | mandatory: {
27 | chromeMediaSource: "desktop",
28 | chromeMediaSourceId: id,
29 | maxWidth:screen.width,
30 | maxHeight:screen.height} }
31 | }, gotStream, getUserMediaError);
32 | }
33 |
34 | var pending_request_id = null;
35 |
36 | document.querySelector('#start').addEventListener('click', function(e) {
37 | pending_request_id = chrome.desktopCapture.chooseDesktopMedia(
38 | ["screen", "window"], onAccessApproved);
39 | });
40 |
41 | document.querySelector('#cancel').addEventListener('click', function(e) {
42 | if (pending_request_id != null) {
43 | chrome.desktopCapture.cancelChooseDesktopMedia(pending_request_id);
44 | }
45 | });
46 |
47 | document.querySelector('#startFromBackgroundPage')
48 | .addEventListener('click', function(e) {
49 | chrome.runtime.sendMessage(
50 | {}, function(response) { console.log(response.farewell); });
51 | });
52 |
--------------------------------------------------------------------------------
/examples/desktop_capture/background.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | chrome.app.runtime.onLaunched.addListener(function() {
6 | chrome.app.window.create('index.html', {
7 | bounds: {
8 | width: 700,
9 | height: 600
10 | }
11 | });
12 | });
13 |
14 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
15 | chrome.desktopCapture.chooseDesktopMedia(
16 | ["screen", "window"],
17 | function(id) {
18 | sendResponse({"id": id});
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/examples/desktop_capture/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/desktop_capture/icon.png
--------------------------------------------------------------------------------
/examples/desktop_capture/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/examples/desktop_capture/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Desktop Capture Example",
3 | "description": "Show desktop media picker UI",
4 | "version": "1",
5 | "manifest_version": 2,
6 | "icons": {
7 | "16": "icon.png",
8 | "128": "icon.png"
9 | },
10 | "app": {
11 | "background": {
12 | "scripts": ["background.js"]
13 | }
14 | },
15 | "permissions": [
16 | "desktopCapture"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/examples/event_page/background.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // Global variables only exist for the life of the page, so they get reset
6 | // each time the page is unloaded.
7 | var counter = 1;
8 |
9 | var lastTabId = -1;
10 | function sendMessage() {
11 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
12 | lastTabId = tabs[0].id;
13 | chrome.tabs.sendMessage(lastTabId, "Background page started.");
14 | });
15 | }
16 |
17 | sendMessage();
18 | chrome.browserAction.setBadgeText({text: "ON"});
19 | console.log("Loaded.");
20 |
21 | chrome.runtime.onInstalled.addListener(function() {
22 | console.log("Installed.");
23 |
24 | // localStorage is persisted, so it's a good place to keep state that you
25 | // need to persist across page reloads.
26 | localStorage.counter = 1;
27 |
28 | // Register a webRequest rule to redirect bing to google.
29 | var wr = chrome.declarativeWebRequest;
30 | chrome.declarativeWebRequest.onRequest.addRules([{
31 | id: "0",
32 | conditions: [new wr.RequestMatcher({url: {hostSuffix: "bing.com"}})],
33 | actions: [new wr.RedirectRequest({redirectUrl: "http://google.com"})]
34 | }]);
35 | });
36 |
37 | chrome.bookmarks.onRemoved.addListener(function(id, info) {
38 | alert("I never liked that site anyway.");
39 | });
40 |
41 | chrome.browserAction.onClicked.addListener(function() {
42 | // The event page will unload after handling this event (assuming nothing
43 | // else is keeping it awake). The content script will become the main way to
44 | // interact with us.
45 | chrome.tabs.create({url: "http://google.com"}, function(tab) {
46 | chrome.tabs.executeScript(tab.id, {file: "content.js"}, function() {
47 | // Note: we also sent a message above, upon loading the event page,
48 | // but the content script will not be loaded at that point, so we send
49 | // another here.
50 | sendMessage();
51 | });
52 | });
53 | });
54 |
55 | chrome.commands.onCommand.addListener(function(command) {
56 | chrome.tabs.create({url: "http://www.google.com/"});
57 | });
58 |
59 | chrome.runtime.onMessage.addListener(function(msg, _, sendResponse) {
60 | if (msg.setAlarm) {
61 | // For testing only. delayInMinutes will be rounded up to at least 1 in a
62 | // packed or released extension.
63 | chrome.alarms.create({delayInMinutes: 0.1});
64 | } else if (msg.delayedResponse) {
65 | // Note: setTimeout itself does NOT keep the page awake. We return true
66 | // from the onMessage event handler, which keeps the message channel open -
67 | // in turn keeping the event page awake - until we call sendResponse.
68 | setTimeout(function() {
69 | sendResponse("Got your message.");
70 | }, 5000);
71 | return true;
72 | } else if (msg.getCounters) {
73 | sendResponse({counter: counter++,
74 | persistentCounter: localStorage.counter++});
75 | }
76 | // If we don't return anything, the message channel will close, regardless
77 | // of whether we called sendResponse.
78 | });
79 |
80 | chrome.alarms.onAlarm.addListener(function() {
81 | alert("Time's up!");
82 | });
83 |
84 | chrome.runtime.onSuspend.addListener(function() {
85 | chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
86 | // After the unload event listener runs, the page will unload, so any
87 | // asynchronous callbacks will not fire.
88 | alert("This does not show up.");
89 | });
90 | console.log("Unloading.");
91 | chrome.browserAction.setBadgeText({text: ""});
92 | chrome.tabs.sendMessage(lastTabId, "Background page unloaded.");
93 | });
94 |
--------------------------------------------------------------------------------
/examples/event_page/content.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | document.body.innerHTML = "";
6 |
7 | function addButton(name, cb) {
8 | var a = document.createElement("button");
9 | a.innerText = name;
10 | a.onclick = cb;
11 | document.body.appendChild(document.createElement("br"));
12 | document.body.appendChild(a);
13 | }
14 |
15 | function log(str) {
16 | console.log(str);
17 | logDiv.innerHTML += str + "
";
18 | }
19 |
20 | addButton("Clear logs", function() {
21 | logDiv.innerHTML = "";
22 | });
23 |
24 | addButton("Send message with delayed response", function() {
25 | chrome.runtime.sendMessage({delayedResponse: true}, function(response) {
26 | log("Background page responded: " + response);
27 | });
28 | });
29 |
30 | addButton("Show counters", function() {
31 | chrome.runtime.sendMessage({getCounters: true}, function(response) {
32 | log("In-memory counter is: " + response.counter);
33 | log("Persisted counter is: " + response.persistentCounter);
34 | });
35 | });
36 |
37 | addButton("Set an alarm", function() {
38 | chrome.runtime.sendMessage({setAlarm: true});
39 | });
40 |
41 | chrome.runtime.onMessage.addListener(function(msg, _, sendResponse) {
42 | log("Got message from background page: " + msg);
43 | });
44 |
45 | var logDiv = document.createElement("div");
46 | logDiv.style.border = "1px dashed black";
47 | document.body.appendChild(document.createElement("br"));
48 | document.body.appendChild(logDiv);
49 |
50 | log("Ready.");
51 |
--------------------------------------------------------------------------------
/examples/event_page/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/event_page/icon.png
--------------------------------------------------------------------------------
/examples/event_page/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Event Page Example",
3 | "description": "Demonstrates usage and features of the event page",
4 | "version": "1.0",
5 | "manifest_version": 2,
6 | "permissions": ["alarms", "tabs", "bookmarks", "declarativeWebRequest", "*://*/*"],
7 | "background": {
8 | "scripts": ["background.js"],
9 | "persistent": false
10 | },
11 | "browser_action": {
12 | "default_icon" : "icon.png",
13 | "default_title": "Start Event Page"
14 | },
15 | "commands": {
16 | "open-google": {
17 | "description": "Open a tab to google.com",
18 | "suggested_key": { "default": "Ctrl+Shift+L" }
19 | },
20 | "_execute_browser_action": {
21 | "suggested_key": { "default": "Ctrl+Shift+K" }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/make_page_red/background.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // Called when the user clicks on the browser action (icon)
6 | chrome.browserAction.onClicked.addListener(function(tab) {
7 | // No tabs or host permissions needed!
8 | console.log('Turning ' + tab.url + ' red!');
9 | chrome.tabs.executeScript({
10 | code: 'document.body.style.backgroundColor="red"'
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/examples/make_page_red/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Page Redder",
3 | "description": "Make the current page red",
4 | "version": "2.0",
5 | "permissions": [
6 | "activeTab"
7 | ],
8 | "background": {
9 | "scripts": ["background.js"],
10 | "persistent": false
11 | },
12 | "browser_action": {
13 | "default_title": "Make this page red"
14 | },
15 | "manifest_version": 2
16 | }
17 |
--------------------------------------------------------------------------------
/examples/my_bookmarks/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/my_bookmarks/icon.png
--------------------------------------------------------------------------------
/examples/my_bookmarks/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "My Bookmarks",
3 | "version": "1.1",
4 | "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.",
5 | "permissions": [
6 | "bookmarks"
7 | ],
8 | "browser_action": {
9 | "default_title": "My Bookmarks",
10 | "default_icon": "icon.png",
11 | "default_popup": "popup.html"
12 | },
13 | "manifest_version": 2,
14 | "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/my_bookmarks/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Search Bookmarks:
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/my_bookmarks/popup.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | // Search the bookmarks when entering the search keyword.
6 | $(function() {
7 | $('#search').change(function() {
8 | $('#bookmarks').empty();
9 | dumpBookmarks($('#search').val());
10 | });
11 | });
12 | // Traverse the bookmark tree, and print the folder and nodes.
13 | function dumpBookmarks(query) {
14 | var bookmarkTreeNodes = chrome.bookmarks.getTree(
15 | function(bookmarkTreeNodes) {
16 | $('#bookmarks').append(dumpTreeNodes(bookmarkTreeNodes, query));
17 | });
18 | }
19 | function dumpTreeNodes(bookmarkNodes, query) {
20 | var list = $('');
21 | var i;
22 | for (i = 0; i < bookmarkNodes.length; i++) {
23 | list.append(dumpNode(bookmarkNodes[i], query));
24 | }
25 | return list;
26 | }
27 | function dumpNode(bookmarkNode, query) {
28 | if (bookmarkNode.title) {
29 | if (query && !bookmarkNode.children) {
30 | if (String(bookmarkNode.title).indexOf(query) == -1) {
31 | return $('');
32 | }
33 | }
34 | var anchor = $('');
35 | anchor.attr('href', bookmarkNode.url);
36 | anchor.text(bookmarkNode.title);
37 | /*
38 | * When clicking on a bookmark in the extension, a new tab is fired with
39 | * the bookmark url.
40 | */
41 | anchor.click(function() {
42 | chrome.tabs.create({url: bookmarkNode.url});
43 | });
44 | var span = $('');
45 | var options = bookmarkNode.children ?
46 | $('[Add]') :
47 | $('[Edit Delete]');
49 | var edit = bookmarkNode.children ? $('') : $('');
52 | // Show add and edit links when hover over.
53 | span.hover(function() {
54 | span.append(options);
55 | $('#deletelink').click(function() {
56 | $('#deletedialog').empty().dialog({
57 | autoOpen: false,
58 | title: 'Confirm Deletion',
59 | resizable: false,
60 | height: 140,
61 | modal: true,
62 | overlay: {
63 | backgroundColor: '#000',
64 | opacity: 0.5
65 | },
66 | buttons: {
67 | 'Yes, Delete It!': function() {
68 | chrome.bookmarks.remove(String(bookmarkNode.id));
69 | span.parent().remove();
70 | $(this).dialog('destroy');
71 | },
72 | Cancel: function() {
73 | $(this).dialog('destroy');
74 | }
75 | }
76 | }).dialog('open');
77 | });
78 | $('#addlink').click(function() {
79 | $('#adddialog').empty().append(edit).dialog({autoOpen: false,
80 | closeOnEscape: true, title: 'Add New Bookmark', modal: true,
81 | buttons: {
82 | 'Add' : function() {
83 | chrome.bookmarks.create({parentId: bookmarkNode.id,
84 | title: $('#title').val(), url: $('#url').val()});
85 | $('#bookmarks').empty();
86 | $(this).dialog('destroy');
87 | window.dumpBookmarks();
88 | },
89 | 'Cancel': function() {
90 | $(this).dialog('destroy');
91 | }
92 | }}).dialog('open');
93 | });
94 | $('#editlink').click(function() {
95 | edit.val(anchor.text());
96 | $('#editdialog').empty().append(edit).dialog({autoOpen: false,
97 | closeOnEscape: true, title: 'Edit Title', modal: true,
98 | show: 'slide', buttons: {
99 | 'Save': function() {
100 | chrome.bookmarks.update(String(bookmarkNode.id), {
101 | title: edit.val()
102 | });
103 | anchor.text(edit.val());
104 | options.show();
105 | $(this).dialog('destroy');
106 | },
107 | 'Cancel': function() {
108 | $(this).dialog('destroy');
109 | }
110 | }}).dialog('open');
111 | });
112 | options.fadeIn();
113 | },
114 | // unhover
115 | function() {
116 | options.remove();
117 | }).append(anchor);
118 | }
119 | var li = $(bookmarkNode.title ? '- ' : '
').append(span);
120 | if (bookmarkNode.children && bookmarkNode.children.length > 0) {
121 | li.append(dumpTreeNodes(bookmarkNode.children, query));
122 | }
123 | return li;
124 | }
125 |
126 | document.addEventListener('DOMContentLoaded', function () {
127 | dumpBookmarks();
128 | });
129 |
--------------------------------------------------------------------------------
/examples/my_devices/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/my_devices/icon.png
--------------------------------------------------------------------------------
/examples/my_devices/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "My Devices",
3 | "version": "1.1",
4 | "description": "A browser action with a popup dump of all devices signed into the same account as the current profile.",
5 | "permissions": [
6 | "signedInDevices"
7 | ],
8 | "browser_action": {
9 | "default_title": "My Devices",
10 | "default_icon": "icon.png",
11 | "default_popup": "popup.html"
12 | },
13 | "manifest_version": 2,
14 | "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
15 | }
16 |
--------------------------------------------------------------------------------
/examples/my_devices/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/my_devices/popup.js:
--------------------------------------------------------------------------------
1 | // Copyright 2013 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | function dumpDevices(devices) {
6 | $('#deviceinfos').empty();
7 | $('#deviceinfos').append(outputDevicesToList(devices));
8 | }
9 |
10 | function outputDevicesToList(devices) {
11 | console.log(devices);
12 | var table = $('
');
13 | table.append($("" +
14 | "" + "Name" + " | " +
15 | "" + "OS" + " | " +
16 | "" + "Id" + " | " +
17 | "" + "Type" + " | " +
18 | "" + "Chrome Version" + " | " +
19 | "
"));
20 | for (i = 0; i < devices.length; i++) {
21 | table.append($("" +
22 | "" + devices[i].name + " | " +
23 | "" + devices[i].os + " | " +
24 | "" + devices[i].id + " | " +
25 | "" + devices[i].type + " | " +
26 | "" + devices[i].chromeVersion + " | " +
27 | "
"));
28 | }
29 | return table;
30 | }
31 |
32 | // Add an event listener to listen for changes to device info. The
33 | // callback would redisplay the list of devices.
34 | chrome.signedInDevices.onDeviceInfoChange.addListener(dumpDevices);
35 |
36 | function populateDevices() {
37 | // Get the list of devices and display it.
38 | chrome.signedInDevices.get(false, dumpDevices);
39 | }
40 |
41 | document.addEventListener('DOMContentLoaded', function () {
42 | populateDevices();
43 | });
44 |
--------------------------------------------------------------------------------
/examples/notifications/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/notifications/128.png
--------------------------------------------------------------------------------
/examples/notifications/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/notifications/16.png
--------------------------------------------------------------------------------
/examples/notifications/48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/notifications/48.png
--------------------------------------------------------------------------------
/examples/notifications/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/notifications/64.png
--------------------------------------------------------------------------------
/examples/notifications/background.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /*
6 | Displays a notification with the current time. Requires "notifications"
7 | permission in the manifest file (or calling
8 | "Notification.requestPermission" beforehand).
9 | */
10 | function show() {
11 | var time = /(..)(:..)/.exec(new Date()); // The prettyprinted time.
12 | var hour = time[1] % 12 || 12; // The prettyprinted hour.
13 | var period = time[1] < 12 ? 'a.m.' : 'p.m.'; // The period of the day.
14 | new Notification(hour + time[2] + ' ' + period, {
15 | icon: '48.png',
16 | body: 'Time to make the toast.'
17 | });
18 | }
19 |
20 | // Conditionally initialize the options.
21 | if (!localStorage.isInitialized) {
22 | localStorage.isActivated = true; // The display activation.
23 | localStorage.frequency = 1; // The display frequency, in minutes.
24 | localStorage.isInitialized = true; // The option initialization.
25 | }
26 |
27 | // Test for notification support.
28 | if (window.Notification) {
29 | // While activated, show notifications at the display frequency.
30 | if (JSON.parse(localStorage.isActivated)) { show(); }
31 |
32 | var interval = 0; // The display interval, in minutes.
33 |
34 | setInterval(function() {
35 | interval++;
36 |
37 | if (
38 | JSON.parse(localStorage.isActivated) &&
39 | localStorage.frequency <= interval
40 | ) {
41 | show();
42 | interval = 0;
43 | }
44 | }, 60000);
45 | }
46 |
--------------------------------------------------------------------------------
/examples/notifications/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Notification Demo",
3 | "version": "1.1",
4 | "description":
5 | "Shows off desktop notifications, which are \"toast\" windows that pop up on the desktop.",
6 | "icons": {"16": "16.png", "48": "48.png", "128": "128.png"},
7 | "permissions": [
8 | "notifications"
9 | ],
10 | "options_page": "options.html",
11 | "background": { "scripts": ["background.js"] },
12 | "manifest_version": 2,
13 |
14 | // crbug.com/134315
15 | "web_accessible_resources": [
16 | "48.png"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/examples/notifications/options.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 | Notification Demo
14 |
15 |
16 |
17 |
18 |
19 |
20 | Notification Demo
21 |
22 | Options
23 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/examples/notifications/options.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | /*
6 | Grays out or [whatever the opposite of graying out is called] the option
7 | field.
8 | */
9 | function ghost(isDeactivated) {
10 | options.style.color = isDeactivated ? 'graytext' : 'black';
11 | // The label color.
12 | options.frequency.disabled = isDeactivated; // The control manipulability.
13 | }
14 |
15 | window.addEventListener('load', function() {
16 | // Initialize the option controls.
17 | options.isActivated.checked = JSON.parse(localStorage.isActivated);
18 | // The display activation.
19 | options.frequency.value = localStorage.frequency;
20 | // The display frequency, in minutes.
21 |
22 | if (!options.isActivated.checked) { ghost(true); }
23 |
24 | // Set the display activation and frequency.
25 | options.isActivated.onchange = function() {
26 | localStorage.isActivated = options.isActivated.checked;
27 | ghost(!options.isActivated.checked);
28 | };
29 |
30 | options.frequency.onchange = function() {
31 | localStorage.frequency = options.frequency.value;
32 | };
33 | });
34 |
--------------------------------------------------------------------------------
/examples/notifications/style.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 | * Use of this source code is governed by a BSD-style license that can be
4 | * found in the LICENSE file.
5 | */
6 |
7 | /* Clone the look and feel of "chrome://" pages. */
8 | body {
9 | margin: 10px;
10 | font: 84% Arial, sans-serif
11 | }
12 |
13 | h1 { font-size: 156% }
14 |
15 | h1 img {
16 | margin: 1px 5px 0 1px;
17 | vertical-align: middle
18 | }
19 |
20 | h2 {
21 | border-top: 1px solid #9cc2ef;
22 | background-color: #ebeff9;
23 | padding: 3px 5px;
24 | font-size: 100%
25 | }
26 |
--------------------------------------------------------------------------------
/examples/set_icon_path/background.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | var min = 1;
6 | var max = 5;
7 | var current = min;
8 |
9 | function updateIcon() {
10 | chrome.browserAction.setIcon({path:"icon" + current + ".png"});
11 | current++;
12 |
13 | if (current > max)
14 | current = min;
15 | }
16 |
17 | chrome.browserAction.onClicked.addListener(updateIcon);
18 | updateIcon();
19 |
--------------------------------------------------------------------------------
/examples/set_icon_path/icon1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/set_icon_path/icon1.png
--------------------------------------------------------------------------------
/examples/set_icon_path/icon2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/set_icon_path/icon2.png
--------------------------------------------------------------------------------
/examples/set_icon_path/icon3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/set_icon_path/icon3.png
--------------------------------------------------------------------------------
/examples/set_icon_path/icon4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/set_icon_path/icon4.png
--------------------------------------------------------------------------------
/examples/set_icon_path/icon5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwyl/learn-chrome-extensions/52e3f91a3b6b9021eea7921d32c216bd730ceaf0/examples/set_icon_path/icon5.png
--------------------------------------------------------------------------------
/examples/set_icon_path/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "A browser action which changes its icon when clicked",
3 | "description": "Change browser action color when its icon is clicked",
4 | "version": "1.2",
5 | "background": { "scripts": ["background.js"] },
6 | "browser_action": {
7 | "name": "Click to change the icon's color"
8 | },
9 | "manifest_version": 2
10 | }
11 |
--------------------------------------------------------------------------------