Merge remote-tracking branch 'origin/master'
* origin/master: (34 commits) add _locales/ja Apply minor tweaks and fix typos in inpage-toolbar-ui doc and comments Minor tweaks on inpage-toolbar-ui stylesheet Add inpage-toolbar-ui add-on example Add 48px icon in 'icons' key Added README; stop using alarm name for tab ID Fix review comments: https://github.com/mdn/webextensions-examples/issues/31#issuecomment-172650159 Fix review comments: https://github.com/mdn/webextensions-examples/issues/30#issuecomment-172649839 Fix review comments: https://github.com/mdn/webextensions-examples/issues/29#issuecomment-172646879 Fix review comments: https://github.com/mdn/webextensions-examples/issues/28#issuecomment-172645256 add alarms permission, very minor update to a comment added comments to one missing file added short comments for all JS functions ask that examples should contain the key added strict_min_version to manifest.json ask that examples include the key use the right size icons use the 'icons' key for all examples updates and typo fixes for CONTRIBUTING.md added draft CONTRIBUTING.md ...
33
CONTRIBUTING.md
Normal file
@@ -0,0 +1,33 @@
|
||||
This repository contains example Firefox [WebExtensions](https://developer.mozilla.org/en-US/Add-ons/WebExtensions).
|
||||
|
||||
We're really happy to accept contributions, either as new examples or as
|
||||
improvements to the existing examples. This file lists some general guidelines
|
||||
to help contributors write useful examples.
|
||||
|
||||
The examples are intended to demonstrate how to use the WebExtensions technology,
|
||||
particularly [APIs](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API),
|
||||
but also [manifest.json keys](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json)
|
||||
and more general techniques such as internationalization or message passing.
|
||||
|
||||
More specifically, they're intended to be referenced from the MDN documentation
|
||||
for WebExtensions. So, for example, we'll expect the reference page for
|
||||
`tabs.executeScript()` to link to some examples that demonstrate how to use this
|
||||
API.
|
||||
|
||||
So examples should:
|
||||
|
||||
* have a clear function, that's easy to explain and understand
|
||||
* focus on demonstrating how to use the WebExtension technology, minimizing any
|
||||
complex logic that's extraneous to the WebExtension technology itself
|
||||
* demonstrate good-practice use of the technology, even at the expense of extra
|
||||
complexity
|
||||
* include useful optional manifest.json keys:
|
||||
* [`description`](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/description)
|
||||
* [`icons`](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/icons)
|
||||
* `homepage_url`
|
||||
* [`strict_min_version` in the `applications` key](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/applications)
|
||||
|
||||
Finally, note that the examples are all made available under the
|
||||
[Mozilla Public License 2.0](https://github.com/mdn/webextensions-examples/blob/master/LICENSE),
|
||||
so any contributions must be
|
||||
[compatible with that license](https://www.mozilla.org/en-US/MPL/license-policy/).
|
||||
@@ -1 +1,27 @@
|
||||
# beastify
|
||||
|
||||
## What it does ##
|
||||
|
||||
The extension includes:
|
||||
|
||||
* a browser action with a popup including HTML, CSS, and JS
|
||||
* a content script
|
||||
* three images, each of a different beast, packaged as web accessible resources
|
||||
|
||||
When the user clicks the browser action button, the popup is shown, enabling
|
||||
the user to choose one of three beasts.
|
||||
|
||||
When they choose a beast, the extension injects the content script into
|
||||
the current page, and sends the content script a message containing
|
||||
the name of the chosen beast.
|
||||
|
||||
When the content script receives this message, it replaces the current page
|
||||
content with an image of the chosen beast.
|
||||
|
||||
## What it shows ##
|
||||
|
||||
* write a browser action with a popup
|
||||
* give the popup style and behavior using CSS and JS
|
||||
* inject a content script programmatically using `tabs.executeScript()`
|
||||
* send a message from the main extension to a content script
|
||||
* use web accessible resources to enable web pages to load packaged content
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The icon "beasts.png" is taken from the IconBeast Lite iconset, and used under the terms of its license (http://www.iconbeast.com/faq/), with a link back to the website: http://www.iconbeast.com/free/.
|
||||
@@ -1,18 +1,28 @@
|
||||
// Assign beastify() as a listener for messages from the extension.
|
||||
chrome.runtime.onMessage.addListener(beastify);
|
||||
|
||||
/*
|
||||
beastify():
|
||||
* removes every node in the document.body,
|
||||
* then inserts the chosen beast
|
||||
* then removes itself as a listener
|
||||
*/
|
||||
function beastify(request, sender, sendResponse) {
|
||||
removeEverything();
|
||||
insertBeast(beastNameToURL(request.beast));
|
||||
insertBeast(request.beastURL);
|
||||
chrome.runtime.onMessage.removeListener(beastify);
|
||||
}
|
||||
|
||||
/*
|
||||
Remove every node under document.body
|
||||
*/
|
||||
function removeEverything() {
|
||||
while (document.body.firstChild) {
|
||||
document.body.firstChild.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Given a URL to a beast image, create and style an IMG node pointing to
|
||||
that image, then insert the node into the document.
|
||||
*/
|
||||
function insertBeast(beastURL) {
|
||||
var beastImage = document.createElement("img");
|
||||
beastImage.setAttribute("src", beastURL);
|
||||
@@ -21,6 +31,15 @@ function insertBeast(beastURL) {
|
||||
document.body.appendChild(beastImage);
|
||||
}
|
||||
|
||||
/*
|
||||
Assign beastify() as a listener for messages from the extension.
|
||||
*/
|
||||
chrome.runtime.onMessage.addListener(beastify);
|
||||
|
||||
|
||||
/*
|
||||
Given the name of a beast, get the URL to the corresponding image.
|
||||
*/
|
||||
function beastNameToURL(beastName) {
|
||||
switch (beastName) {
|
||||
case "Frog":
|
||||
|
||||
4
beastify/icons/LICENSE
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
The icon "beasts-32.png" is taken from the IconBeast Lite iconset, and used under the terms of its license (http://www.iconbeast.com/faq/), with a link back to the website: http://www.iconbeast.com/free/.
|
||||
|
||||
The icon "beasts-48.png" is taken from Aha-Soft’s Free Retina iconset, and used under the terms of its license (http://www.aha-soft.com/free-icons/free-retina-icon-set/), with a link back to the website: http://www.aha-soft.com/.
|
||||
|
Before Width: | Height: | Size: 550 B After Width: | Height: | Size: 550 B |
BIN
beastify/icons/beasts-48.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
@@ -4,20 +4,24 @@
|
||||
"manifest_version": 2,
|
||||
"name": "Beastify",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
|
||||
"icons": {
|
||||
"48": "icons/beasts-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "beastify@mozilla.org"
|
||||
"id": "beastify@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"activeTab"
|
||||
],
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "button/beasts.png",
|
||||
"default_icon": "icons/beasts-32.png",
|
||||
"default_title": "Beastify",
|
||||
"default_popup": "popup/choose_beast.html"
|
||||
},
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
html, body {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.beast {
|
||||
height: 30%;
|
||||
width: 90%;
|
||||
margin: 3% auto;
|
||||
padding-top: 6%;
|
||||
padding: 4px;
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
background-color: #E5F2F2;
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
Given the name of a beast, get the URL to the corresponding image.
|
||||
*/
|
||||
function beastNameToURL(beastName) {
|
||||
switch (beastName) {
|
||||
case "Frog":
|
||||
return chrome.extension.getURL("beasts/frog.jpg");
|
||||
case "Snake":
|
||||
return chrome.extension.getURL("beasts/snake.jpg");
|
||||
case "Turtle":
|
||||
return chrome.extension.getURL("beasts/turtle.jpg");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Listen for clicks in the popup.
|
||||
|
||||
@@ -5,12 +20,10 @@ If the click is not on one of the beasts, return early.
|
||||
|
||||
Otherwise, the text content of the node is the name of the beast we want.
|
||||
|
||||
Run the "beastify.js" content script in the active tab, calling setBeast()
|
||||
once the content script has executed.
|
||||
Inject the "beastify.js" content script in the active tab.
|
||||
|
||||
Inside setBeast(), get the active tab, then send it a message containing
|
||||
the chosen beast's name. This message will be received by the content script
|
||||
we just executed.
|
||||
Then get the active tab and send "beastify.js" a message
|
||||
containing the URL to the chosen beast's image.
|
||||
*/
|
||||
document.addEventListener("click", function(e) {
|
||||
if (!e.target.classList.contains("beast")) {
|
||||
@@ -18,13 +31,14 @@ document.addEventListener("click", function(e) {
|
||||
}
|
||||
|
||||
var chosenBeast = e.target.textContent;
|
||||
|
||||
var chosenBeastURL = beastNameToURL(chosenBeast);
|
||||
|
||||
chrome.tabs.executeScript(null, {
|
||||
file: "content_scripts/beastify.js"
|
||||
file: "/content_scripts/beastify.js"
|
||||
});
|
||||
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
|
||||
chrome.tabs.sendMessage(tabs[0].id, {beast: chosenBeast});
|
||||
chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
14
borderify/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# borderify
|
||||
|
||||
## What it does
|
||||
|
||||
This extension just includes:
|
||||
|
||||
* a content script, "borderify.js", that is injected into any pages
|
||||
under "mozilla.org/" or any of its subdomains
|
||||
|
||||
The content script draws a border around the document.body.
|
||||
|
||||
## What it shows
|
||||
|
||||
* how to inject content scripts declaratively using manifest.json
|
||||
@@ -1 +1,4 @@
|
||||
/*
|
||||
Just draw a border round the document.body.
|
||||
*/
|
||||
document.body.style.border = "5px solid red";
|
||||
|
||||
1
borderify/icons/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
The icon “border-48.png” is taken from the Google Material Design iconset, and is used under the terms of the Creative Commons Attribution-ShareAlike license: http://creativecommons.org/licenses/by-sa/3.0/.
|
||||
BIN
borderify/icons/border-48.png
Normal file
|
After Width: | Height: | Size: 225 B |
@@ -4,10 +4,15 @@
|
||||
"manifest_version": 2,
|
||||
"name": "Borderify",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/borderify",
|
||||
"icons": {
|
||||
"48": "icons/border-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "borderify@mozilla.org"
|
||||
"id": "borderify@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1 +1,24 @@
|
||||
# chill-out
|
||||
|
||||
## What it does
|
||||
|
||||
After N seconds of inactivity (defined as, the user not having navigated
|
||||
or switched the active tab) display show a page action for that tab.
|
||||
|
||||
When the user clicks the page action,
|
||||
navigate to http://chilloutandwatchsomecatgifs.com/.
|
||||
|
||||
"N" is set to 6 seconds in this example. Such a short period is chosen to make
|
||||
the extension's behavior more obvious, but this is not recommended in real life.
|
||||
Note that in Chrome, alarms cannot be set for less than a minute. In Chrome:
|
||||
|
||||
* if you install this extension "unpacked", you'll see a warning
|
||||
in the console, but the alarm will still go off after 6 seconds
|
||||
* if you package the extension and install it, then the alarm will go off after
|
||||
a minute.
|
||||
|
||||
## What it shows
|
||||
|
||||
* how to use various `tabs` functions
|
||||
* how to show/hide a page action
|
||||
* how to set alarms and handle alarms going off
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
/*
|
||||
DELAY is set to 6 seconds in this example. Such a short period is chosen to make
|
||||
the extension's behavior more obvious, but this is not recommended in real life.
|
||||
Note that in Chrome, alarms cannot be set for less than a minute. In Chrome:
|
||||
|
||||
* if you install this extension "unpacked", you'll see a warning
|
||||
in the console, but the alarm will still go off after 6 seconds
|
||||
* if you package the extension and install it, then the alarm will go off after
|
||||
a minute.
|
||||
*/
|
||||
var DELAY = 0.1;
|
||||
var CATGIFS = "http://chilloutandwatchsomecatgifs.com/";
|
||||
|
||||
/*
|
||||
Start-stop for the currently active tab, whenever this script is run.
|
||||
Restart alarm for the currently active tab, whenever background.js is run.
|
||||
*/
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
|
||||
startStopAlarm(tabs[0].id);
|
||||
restartAlarm(tabs[0].id);
|
||||
});
|
||||
|
||||
/*
|
||||
Start-stop for the currently active tab, whenever the user navigates.
|
||||
Restart alarm for the currently active tab, whenever the user navigates.
|
||||
*/
|
||||
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
|
||||
if (!changeInfo.url) {
|
||||
@@ -17,28 +27,28 @@ chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
|
||||
}
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
|
||||
if (tabId == tabs[0].id) {
|
||||
startStopAlarm(tabId);
|
||||
restartAlarm(tabId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
Start-stop for the currently active tab, whenever a new tab becomes active.
|
||||
Restart alarm for the currently active tab, whenever a new tab becomes active.
|
||||
*/
|
||||
chrome.tabs.onActivated.addListener(function (activeInfo) {
|
||||
startStopAlarm(activeInfo.tabId);
|
||||
restartAlarm(activeInfo.tabId);
|
||||
});
|
||||
|
||||
/*
|
||||
Start-stop: clear all alarms,
|
||||
restartAlarm: clear all alarms,
|
||||
then set a new alarm for the given tab.
|
||||
*/
|
||||
function startStopAlarm(tabId) {
|
||||
function restartAlarm(tabId) {
|
||||
chrome.pageAction.hide(tabId);
|
||||
chrome.alarms.clearAll();
|
||||
chrome.tabs.get(tabId, function(tab) {
|
||||
if (tab.url != CATGIFS) {
|
||||
chrome.alarms.create(tabId, {delayInMinutes: DELAY});
|
||||
chrome.alarms.create("", {delayInMinutes: DELAY});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -48,7 +58,7 @@ On alarm, show the page action.
|
||||
*/
|
||||
chrome.alarms.onAlarm.addListener(function(alarm) {
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
|
||||
chrome.pageAction.show(alarm.name);
|
||||
chrome.pageAction.show(tabs[0].id);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The icon "chillout.png" is taken from the IconBeast Lite iconset, and used under the terms of its license (http://www.iconbeast.com/faq/), with a link back to the website: http://www.iconbeast.com/free/.
|
||||
3
chill-out/icons/LICENSE
Normal file
@@ -0,0 +1,3 @@
|
||||
The icon "chillout-32.png" is taken from the IconBeast Lite iconset, and used under the terms of its license (http://www.iconbeast.com/faq/), with a link back to the website: http://www.iconbeast.com/free/.
|
||||
|
||||
The icon "chillout-48.png" is taken from Aha-Soft’s Free Retina iconset, and used under the terms of its license (http://www.aha-soft.com/free-icons/free-retina-icon-set/), with a link back to the website: http://www.aha-soft.com/.
|
||||
|
Before Width: | Height: | Size: 550 B After Width: | Height: | Size: 550 B |
BIN
chill-out/icons/chillout-48.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
@@ -1,4 +1,12 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Chill out",
|
||||
"version": "1.0",
|
||||
"description": "Show a page action after a period of inactivity. Show cat gifs when the page action is clicked.",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/chill-out",
|
||||
"icons": {
|
||||
"48": "icons/chillout-48.png"
|
||||
},
|
||||
|
||||
"manifest_version": 2,
|
||||
"name": "chillout-page-action",
|
||||
@@ -11,11 +19,12 @@
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"alarms",
|
||||
"tabs"
|
||||
],
|
||||
|
||||
"page_action": {
|
||||
"default_icon": "button/chillout.png",
|
||||
"default_icon": "icons/chillout-32.png",
|
||||
"default_title": "Chill out"
|
||||
},
|
||||
|
||||
|
||||
27
inpage-toolbar-ui/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# inpage-toolbar-ui
|
||||
|
||||
## What it does ##
|
||||
|
||||
The extension includes:
|
||||
|
||||
* a browser action which enables/disables the in-page toolbar
|
||||
* a content script which creates/removes the in-page toolbar iframe
|
||||
* the toolbar ui resources, packaged as web accessible resources
|
||||
|
||||
When the user clicks the browser action button, a toolbar is shown/hidden
|
||||
in the current web page.
|
||||
|
||||
The toolbar UI is packaged in the add-on resources, exposed to the current
|
||||
web page as a web accessible resource and injected into the page by the
|
||||
content script by creating and injecting into the page an iframe which
|
||||
points to the toolbar UI page.
|
||||
|
||||
## What it shows ##
|
||||
|
||||
How to expose an in-page toolbar UI by creating an iframe:
|
||||
|
||||
* use web accessible resources to enable web pages to load packaged content
|
||||
* use a content script to create and inject in a web page an iframe which points to the
|
||||
packaged content
|
||||
* use the same API enabled in content scripts (but from the add-on iframe)
|
||||
to exchange messages directly with the add-on background page
|
||||
17
inpage-toolbar-ui/background.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Send a message to the current tab's content script.
|
||||
function toggleToolbar() {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
||||
chrome.tabs.sendMessage(tabs[0].id, "toggle-in-page-toolbar");
|
||||
});
|
||||
}
|
||||
|
||||
// Handle the browser action button.
|
||||
chrome.browserAction.onClicked.addListener(toggleToolbar);
|
||||
|
||||
// Handle connections received from the add-on toolbar ui iframes.
|
||||
chrome.runtime.onConnect.addListener(function (port) {
|
||||
if (port.sender.url == chrome.runtime.getURL("toolbar/ui.html")) {
|
||||
// Handle port messages received from the connected toolbar ui frames.
|
||||
port.onMessage.addListener(toggleToolbar);
|
||||
}
|
||||
});
|
||||
36
inpage-toolbar-ui/contentscript.js
Normal file
@@ -0,0 +1,36 @@
|
||||
var toolbarUI;
|
||||
|
||||
// Create the toolbar ui iframe and inject it in the current page
|
||||
function initToolbar() {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", chrome.runtime.getURL("toolbar/ui.html"));
|
||||
iframe.setAttribute("style", "position: fixed; top: 0; left: 0; z-index: 10000; width: 100%; height: 36px;");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
return toolbarUI = {
|
||||
iframe: iframe, visible: true
|
||||
};
|
||||
}
|
||||
|
||||
function toggleToolbar(toolbarUI) {
|
||||
if (toolbarUI.visible) {
|
||||
toolbarUI.visible = false;
|
||||
toolbarUI.iframe.style["display"] = "none";
|
||||
} else {
|
||||
toolbarUI.visible = true;
|
||||
toolbarUI.iframe.style["display"] = "block";
|
||||
}
|
||||
}
|
||||
|
||||
// Handle messages from the add-on background page (only in top level iframes)
|
||||
if (window.parent == window) {
|
||||
chrome.runtime.onMessage.addListener(function(msg) {
|
||||
if (msg == "toggle-in-page-toolbar") {
|
||||
if (toolbarUI) {
|
||||
toggleToolbar(toolbarUI);
|
||||
} else {
|
||||
toolbarUI = initToolbar();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
BIN
inpage-toolbar-ui/icons/32.png
Normal file
|
After Width: | Height: | Size: 484 B |
BIN
inpage-toolbar-ui/icons/48.png
Normal file
|
After Width: | Height: | Size: 570 B |
40
inpage-toolbar-ui/manifest.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"description": "Adds a browser action icon to the toolbar. Click the button to inject an in-page toolbar UI into the current webpage. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#inpage-toolbar-ui",
|
||||
"manifest_version": 2,
|
||||
"name": "In Page Toolbar UI",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/inpage-toolbar-ui",
|
||||
"icons": {
|
||||
"48": "icons/48.png"
|
||||
},
|
||||
|
||||
"permissions": [],
|
||||
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "icons/32.png",
|
||||
"default_title": "In Page Toolbar"
|
||||
},
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"js": ["contentscript.js"],
|
||||
"run_at": "document_idle",
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
],
|
||||
|
||||
"web_accessible_resources": [
|
||||
"toolbar/ui.html"
|
||||
],
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "inpage-toolbar-ui@mozilla.org",
|
||||
"strict_min_version": "46.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
62
inpage-toolbar-ui/toolbar/ui.css
Normal file
@@ -0,0 +1,62 @@
|
||||
body {
|
||||
overflow: hidden;
|
||||
color: black;
|
||||
background: rgba(255,255,255,0.9);
|
||||
}
|
||||
|
||||
#rainbow {
|
||||
background: linear-gradient(0deg, rgba(217,26,18,0.70) 15%, rgba(225,51,0,0.70) 15%, rgba(255, 127, 20, 0.70) 16%, rgba(242, 171, 3, 0.70) 32%, rgba(235, 192, 0, 0.70) 32%, rgba(250, 222, 0, 0.70) 33%, rgba(239, 255, 3, 0.70) 48%, rgba(86, 252, 2, 0.70) 49%, rgba(82, 255, 1, 0.70) 66%, rgba(74, 222, 126, 0.70) 67%, rgba(59, 170, 242, 0.70) 67%, rgba(59, 170, 242, 0.70) 84%, rgba(115, 55, 247, 0.70) 84%, rgba(107, 64, 242, 0.70) 100%);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.whimsy {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
/* Toggle Button. */
|
||||
|
||||
#toggle {
|
||||
top: 8px;
|
||||
right: 4px;
|
||||
position: absolute;
|
||||
margin: 0 1em;
|
||||
text-decoration: underline;
|
||||
border-radius: 1em;
|
||||
background: transparent linear-gradient(0deg, rgb(255, 162, 0), rgba(189, 122, 6, 0.66));
|
||||
}
|
||||
|
||||
/* Annoying animation. */
|
||||
|
||||
@keyframes wobbling {
|
||||
50% {
|
||||
transform: translateY(-13px);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
}
|
||||
|
||||
.wobbling {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
transform: translateZ(0);
|
||||
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
|
||||
animation-name: wobbling;
|
||||
animation-duration: 1.25s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
17
inpage-toolbar-ui/toolbar/ui.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="ui.css">
|
||||
</head>
|
||||
<body>
|
||||
<span>
|
||||
<div id="rainbow"></div>
|
||||
<img src="whimsy.png" class="whimsy wobbling">
|
||||
<span id="title" class="wobbling">In-Page "Amazing and super-useful" Toolbar</span>
|
||||
</span>
|
||||
<button id="toggle">toggle</button>
|
||||
<script src="ui.js">
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
8
inpage-toolbar-ui/toolbar/ui.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Connect to the background page.
|
||||
var port = chrome.runtime.connect();
|
||||
|
||||
// Handle click events on the toolbar button.
|
||||
document.querySelector("#toggle").addEventListener("click", function() {
|
||||
// Ask the background page to toggle the toolbar on the current tab
|
||||
port.postMessage("toggle-in-page-toolbar");
|
||||
});
|
||||
BIN
inpage-toolbar-ui/toolbar/whimsy.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
@@ -1 +0,0 @@
|
||||
The "link.png" icon is taken from the Geomicons iconset, and is used here under the MIT license: http://opensource.org/licenses/MIT.
|
||||
25
notify-link-clicks-i18n/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# notify-link-clicks-i18n
|
||||
|
||||
## What it does
|
||||
|
||||
This extension includes:
|
||||
|
||||
* a content script, "content-script.js", that is injected into all pages
|
||||
* a background script, "background-script.js"
|
||||
|
||||
The content script listens for clicks in the page it's attached to.
|
||||
If a click is on a link, the content script sends the link's href
|
||||
to the background script.
|
||||
|
||||
The background script listens for this message. When the background script
|
||||
receives the message, it displays a notification containing the href.
|
||||
|
||||
The notification's content, as well as the extension's name and description, are
|
||||
localized into German and Dutch, as well as en-US.
|
||||
|
||||
# What it shows
|
||||
|
||||
* how to inject content scripts declaratively using manifest.json
|
||||
* how to send messages from a content script to a background script
|
||||
* how to display system notifications using the notifications API
|
||||
* how to use the internationalization (i18n) system
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extensionName": {
|
||||
"message": "Notify link clicks",
|
||||
"message": "Notify link clicks i18n",
|
||||
"description": "Name of the extension."
|
||||
},
|
||||
|
||||
|
||||
21
notify-link-clicks-i18n/_locales/ja/messages.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"extensionName": {
|
||||
"message": "リンクを通知する",
|
||||
"description": "拡張機能の名前です。"
|
||||
},
|
||||
|
||||
"extensionDescription": {
|
||||
"message": "ユーザーがリンクをクリックした時通知を表示します。",
|
||||
"description": "拡張機能の説明です。"
|
||||
},
|
||||
|
||||
"notificationTitle": {
|
||||
"message": "クリック通知",
|
||||
"description": "pushのタイトルです。"
|
||||
},
|
||||
|
||||
"notificationContent": {
|
||||
"message": "$1がクリックされました。",
|
||||
"description": "リンクをクリックした時通知を表示します。:変数$1にはurlが代入されます。"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,21 @@
|
||||
chrome.runtime.onMessage.addListener(notify);
|
||||
|
||||
/*
|
||||
Log that we received the message.
|
||||
Then display a notification. The notification contains the URL,
|
||||
which we read from the message.
|
||||
*/
|
||||
function notify(message) {
|
||||
console.log("background script received message");
|
||||
var title = chrome.i18n.getMessage("notificationTitle");
|
||||
var content = chrome.i18n.getMessage("notificationContent", message.url);
|
||||
chrome.notifications.create({
|
||||
"type": "basic",
|
||||
"iconUrl": chrome.extension.getURL("link.png"),
|
||||
"iconUrl": chrome.extension.getURL("icons/link-48.png"),
|
||||
"title": title,
|
||||
"message": content
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Assign `notify()` as a listener to messages from the content script.
|
||||
*/
|
||||
chrome.runtime.onMessage.addListener(notify);
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
window.addEventListener("click", notifyExtension);
|
||||
|
||||
/*
|
||||
If the click was on a link, send a message to the background page.
|
||||
The message contains the link's URL.
|
||||
*/
|
||||
function notifyExtension(e) {
|
||||
console.log("content script sending message");
|
||||
if (e.target.tagName != "A") {
|
||||
return;
|
||||
var target = e.target;
|
||||
while ((target.tagName != "A" || !target.href) && target.parentNode) {
|
||||
target = target.parentNode;
|
||||
}
|
||||
chrome.runtime.sendMessage({"url": e.target.href});
|
||||
if (target.tagName != "A")
|
||||
return;
|
||||
|
||||
console.log("content script sending message");
|
||||
chrome.runtime.sendMessage({"url": target.href});
|
||||
}
|
||||
|
||||
/*
|
||||
Add notifyExtension() as a listener to click events.
|
||||
*/
|
||||
window.addEventListener("click", notifyExtension);
|
||||
|
||||
1
notify-link-clicks-i18n/icons/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
The "link-48.png" icon is taken from the Geomicons iconset, and is used here under the MIT license: http://opensource.org/licenses/MIT.
|
||||
|
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 596 B |
@@ -4,9 +4,15 @@
|
||||
"name": "__MSG_extensionName__",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/notify-link-clicks-i18n",
|
||||
"icons": {
|
||||
"48": "icons/link-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "notify-link-clicks@mozilla.org"
|
||||
"id": "notify-link-clicks-i18n@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The "link.png" icon is taken from the Geomicons iconset, and is used here under the MIT license: http://opensource.org/licenses/MIT.
|
||||
@@ -1,11 +0,0 @@
|
||||
chrome.runtime.onMessage.addListener(notify);
|
||||
|
||||
function notify(message) {
|
||||
console.log("background script received message");
|
||||
chrome.notifications.create({
|
||||
"type": "basic",
|
||||
"iconUrl": chrome.extension.getURL("link.png"),
|
||||
"title": "You clicked a link!",
|
||||
"message": message.url
|
||||
});
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
window.addEventListener("click", notifyExtension);
|
||||
|
||||
function notifyExtension(e) {
|
||||
console.log("content script sending message");
|
||||
if (e.target.tagName != "A") {
|
||||
return;
|
||||
}
|
||||
chrome.runtime.sendMessage({"url": e.target.href});
|
||||
}
|
||||
|
Before Width: | Height: | Size: 596 B |
@@ -1,25 +0,0 @@
|
||||
{
|
||||
|
||||
"description": "Displays notifications when the user clicks links. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#notify-link-clicks",
|
||||
"manifest_version": 2,
|
||||
"name": "Notify link clicks",
|
||||
"version": "1.0",
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "notify-link-clicks@mozilla.org"
|
||||
}
|
||||
},
|
||||
|
||||
"permissions": ["notifications"],
|
||||
|
||||
"background": {
|
||||
"scripts": ["background-script.js"]
|
||||
},
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content-script.js"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
/*
|
||||
Add openMyPage() as a listener to clicks on the browser action.
|
||||
*/
|
||||
chrome.browserAction.onClicked.addListener(openMyPage);
|
||||
|
||||
/*
|
||||
Open a new tab, and load "my-page.html" into it.
|
||||
*/
|
||||
function openMyPage() {
|
||||
console.log("injecting");
|
||||
chrome.tabs.create({
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The icon "beasts.png" is taken from the IconBeast Lite iconset, and used under the terms of its license (http://www.iconbeast.com/faq/), with a link back to the website: http://www.iconbeast.com/free/.
|
||||
|
Before Width: | Height: | Size: 550 B |
2
open-my-page-button/icons/LICENSE
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
The "page-32.png" and "page-48.png" icons are taken from the miu iconset created by Linh Pham Thi Dieu, and are used under the terms of its license: http://linhpham.me/miu/.
|
||||
BIN
open-my-page-button/icons/page-32.png
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
open-my-page-button/icons/page-48.png
Normal file
|
After Width: | Height: | Size: 310 B |
@@ -4,23 +4,24 @@
|
||||
"manifest_version": 2,
|
||||
"name": "open-my-page",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/open-my-page-button",
|
||||
"icons": {
|
||||
"48": "icons/page-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "open-my-page-button@mozilla.org"
|
||||
"id": "open-my-page-button@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"tabs"
|
||||
],
|
||||
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "button/beasts.png"
|
||||
"default_icon": "icons/page-32.png"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
Listen for messages from the page.
|
||||
If the message was from the page script, show an alert.
|
||||
*/
|
||||
window.addEventListener("message", function(event) {
|
||||
if (event.source == window &&
|
||||
event.data.direction &&
|
||||
@@ -6,13 +10,19 @@ window.addEventListener("message", function(event) {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
Add messagePageScript() as a listener to click events on
|
||||
the "from-content-script" element.
|
||||
*/
|
||||
var fromContentScript = document.getElementById("from-content-script");
|
||||
|
||||
fromContentScript.addEventListener("click", messagePageScript);
|
||||
|
||||
/*
|
||||
Send a message to the page script.
|
||||
*/
|
||||
function messagePageScript() {
|
||||
window.postMessage({
|
||||
direction: "from-content-script",
|
||||
message: "Message from the content script"
|
||||
}, "*");
|
||||
}, "https://mdn.github.io");
|
||||
}
|
||||
|
||||
2
page-to-extension-messaging/icons/LICENSE
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
The "message-48.png" icon is taken from the miu iconset created by Linh Pham Thi Dieu, and is used under the terms of its license: http://linhpham.me/miu/.
|
||||
BIN
page-to-extension-messaging/icons/message-48.png
Normal file
|
After Width: | Height: | Size: 670 B |
@@ -4,10 +4,15 @@
|
||||
"name": "Page to extension messaging",
|
||||
"description": "Visit https://mdn.github.io/webextensions-examples/content-script-page-script-messaging.html for the demo. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#page-to-extension-messaging",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/page-to-extension-messaging",
|
||||
"icons": {
|
||||
"48": "icons/message-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "page-to-extension-messaging@mozilla.org"
|
||||
"id": "page-to-extension-messaging@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
This is the page for which we want to rewrite the User-Agent header.
|
||||
*/
|
||||
var targetPage = "http://useragentstring.com/*";
|
||||
|
||||
/*
|
||||
Map browser names to UA strings.
|
||||
*/
|
||||
var uaStrings = {
|
||||
"Firefox 41": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:41.0) Gecko/20100101 Firefox/41.0",
|
||||
"Chrome 41": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
|
||||
"IE 11": "Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the UA to Firefox 41.
|
||||
*/
|
||||
var ua = uaStrings["Firefox 41"];
|
||||
|
||||
/*
|
||||
Add rewriteUserAgentHeader as a listener to onBeforeSendHeaders,
|
||||
only for the target page.
|
||||
|
||||
Make it "blocking" so we can modify the headers.
|
||||
*/
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(rewriteUserAgentHeader,
|
||||
{urls: [targetPage]},
|
||||
["blocking", "requestHeaders"]);
|
||||
|
||||
/*
|
||||
Rewrite the User-Agent header to "ua".
|
||||
*/
|
||||
function rewriteUserAgentHeader(e) {
|
||||
for (var header of e.requestHeaders) {
|
||||
if (header.name == "User-Agent") {
|
||||
@@ -23,8 +41,9 @@ function rewriteUserAgentHeader(e) {
|
||||
return {requestHeaders: e.requestHeaders};
|
||||
}
|
||||
|
||||
chrome.runtime.onMessage.addListener(setUaString);
|
||||
|
||||
function setUaString(message) {
|
||||
ua = uaStrings[message.uaString];
|
||||
/*
|
||||
Update ua to a new value, mapped from the uaString parameter.
|
||||
*/
|
||||
function setUaString(uaString) {
|
||||
ua = uaStrings[uaString];
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
The icon “choose_ua.png” is taken from Yummygum’s Iconsweets iconset, and is used under the terms of its license (http://yummygum.com/work/iconsweets).
|
||||
|
Before Width: | Height: | Size: 471 B |
1
user-agent-rewriter/icons/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
The "person-32.png" "person-48.png" icons are taken from the Ionicons iconset (http://ionicons.com/), and are used here under the MIT license: http://opensource.org/licenses/MIT.
|
||||
BIN
user-agent-rewriter/icons/person-32.png
Normal file
|
After Width: | Height: | Size: 393 B |
BIN
user-agent-rewriter/icons/person-48.png
Normal file
|
After Width: | Height: | Size: 573 B |
@@ -4,10 +4,15 @@
|
||||
"manifest_version": 2,
|
||||
"name": "user-agent-rewriter",
|
||||
"version": "1.0",
|
||||
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/user-agent-rewriter",
|
||||
"icons": {
|
||||
"48": "icons/person-48.png"
|
||||
},
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "user-agent-rewriter@mozilla.org"
|
||||
"id": "user-agent-rewriter@mozilla.org",
|
||||
"strict_min_version": "45.0.0"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,9 +23,9 @@
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "button/choose_ua.png",
|
||||
"default_icon": "icons/person-32.png",
|
||||
"default_title": "Choose a user agent",
|
||||
"default_popup": "popup/choose_ua.html"
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
html, body {
|
||||
html, body, .ua-choices {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
width: 120px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ua-choices {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.ua-choice {
|
||||
height: 20%;
|
||||
width: 90%;
|
||||
margin: 3% auto;
|
||||
padding: 8% 6% 0 6%;
|
||||
margin: 0.2em;
|
||||
padding: 0.2em;
|
||||
background-color: #E5F2F2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
<body>
|
||||
|
||||
<div class="ua-choice">Firefox 41</div>
|
||||
<div class="ua-choice">Chrome 41</div>
|
||||
<div class="ua-choice">IE 11</div>
|
||||
<div class="ua-choices">
|
||||
<div class="ua-choice">Firefox 41</div>
|
||||
<div class="ua-choice">Chrome 41</div>
|
||||
<div class="ua-choice">IE 11</div>
|
||||
</div>
|
||||
|
||||
<script src="choose_ua.js"></script>
|
||||
</body>
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
|
||||
/*
|
||||
If the user clicks on an element which has the class "ua-choice":
|
||||
* fetch the element's textContent: for example, "IE 11"
|
||||
* pass it into the background page's setUaString() function
|
||||
*/
|
||||
document.addEventListener("click", function(e) {
|
||||
if (!e.target.classList.contains("ua-choice")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chosenUa = e.target.textContent;
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
"command": "set-user-agent",
|
||||
"uaString": chosenUa
|
||||
});
|
||||
var backgroundPage = chrome.extension.getBackgroundPage();
|
||||
backgroundPage.setUaString(chosenUa);
|
||||
});
|
||||
|
||||