diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..37f3e66 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +**/node_modules/** +react-es6-popup/**/dist +mocha-client-tests diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bd5191f --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "root": true, + "parserOptions": { + "ecmaVersion": 6 + }, + "env": { + "browser": true, + "es6": true, + "webextensions": true + }, + "extends": [ + "eslint:recommended" + ], + "rules": { + "no-console": 0, + "no-unused-vars": ["warn", { "vars": "all", "args": "all" } ], + "no-undef": ["warn"], + "no-proto": ["error"], + "prefer-arrow-callback": ["warn"], + "prefer-spread": ["warn"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..96c06b2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "8" +sudo: false + +script: + - "npm test" diff --git a/README.md b/README.md index 505ef63..426b57a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# webextensions-examples +# webextensions-examples [![Build Status](https://travis-ci.org/mdn/webextensions-examples.svg?branch=master)](https://travis-ci.org/mdn/webextensions-examples) [https://github.com/mdn/webextensions-examples](https://github.com/mdn/webextensions-examples) diff --git a/annotate-page/sidebar/panel.js b/annotate-page/sidebar/panel.js index f4fdb46..2af8505 100644 --- a/annotate-page/sidebar/panel.js +++ b/annotate-page/sidebar/panel.js @@ -4,14 +4,14 @@ const contentBox = document.querySelector("#content"); /* Make the content box editable as soon as the user mouses over the sidebar. */ -window.addEventListener("mouseover", (e) => { +window.addEventListener("mouseover", () => { contentBox.setAttribute("contenteditable", true); }); /* When the user mouses out, save the current contents of the box. */ -window.addEventListener("mouseout", (e) => { +window.addEventListener("mouseout", () => { contentBox.setAttribute("contenteditable", false); browser.tabs.query({windowId: myWindowId, active: true}).then((tabs) => { let contentToStore = {}; diff --git a/apply-css/background.js b/apply-css/background.js index 7e936a0..3c0b1aa 100644 --- a/apply-css/background.js +++ b/apply-css/background.js @@ -51,7 +51,7 @@ When first loaded, initialize the page action for all tabs. */ var gettingAllTabs = browser.tabs.query({}); gettingAllTabs.then((tabs) => { - for (tab of tabs) { + for (let tab of tabs) { initializePageAction(tab); } }); diff --git a/chill-out/background.js b/chill-out/background.js index bbf453f..d29d949 100644 --- a/chill-out/background.js +++ b/chill-out/background.js @@ -69,6 +69,6 @@ browser.alarms.onAlarm.addListener((alarm) => { /* On page action click, navigate the corresponding tab to the cat gifs. */ -browser.pageAction.onClicked.addListener(function () { +browser.pageAction.onClicked.addListener(() => { browser.tabs.update({url: CATGIFS}); }); diff --git a/commands/background.js b/commands/background.js index 825c559..a54dc95 100644 --- a/commands/background.js +++ b/commands/background.js @@ -12,7 +12,7 @@ */ var gettingAllCommands = browser.commands.getAll(); gettingAllCommands.then((commands) => { - for (command of commands) { + for (let command of commands) { console.log(command); } }); diff --git a/context-menu-copy-link-with-types/background.js b/context-menu-copy-link-with-types/background.js index b8d1505..9152745 100644 --- a/context-menu-copy-link-with-types/background.js +++ b/context-menu-copy-link-with-types/background.js @@ -3,7 +3,7 @@ browser.contextMenus.create({ title: "Copy link to clipboard", contexts: ["link"], }); -browser.contextMenus.onClicked.addListener(function(info, tab) { +browser.contextMenus.onClicked.addListener((info, tab) => { if (info.menuItemId === "copy-link-to-clipboard") { // Examples: text and HTML to be copied. const text = "This is text: " + info.linkUrl; @@ -22,7 +22,7 @@ browser.contextMenus.onClicked.addListener(function(info, tab) { browser.tabs.executeScript({ code: "typeof copyToClipboard === 'function';", - }).then(function(results) { + }).then((results) => { // The content script's last expression will be true if the function // has been defined. If this is not the case, then we need to run // clipboard-helper.js to define function copyToClipboard. @@ -31,11 +31,11 @@ browser.contextMenus.onClicked.addListener(function(info, tab) { file: "clipboard-helper.js", }); } - }).then(function() { + }).then(() => { return browser.tabs.executeScript(tab.id, { code, }); - }).catch(function(error) { + }).catch((error) => { // This could happen if the extension is not allowed to run code in // the page, for example if the tab is a privileged page. console.error("Failed to copy text: " + error); diff --git a/context-menu-demo/background.js b/context-menu-demo/background.js index 98f43a1..359c57b 100644 --- a/context-menu-demo/background.js +++ b/context-menu-demo/background.js @@ -2,7 +2,7 @@ Called when the item has been created, or when creation failed due to an error. We'll just log success/failure here. */ -function onCreated(n) { +function onCreated() { if (browser.runtime.lastError) { console.log(`Error: ${browser.runtime.lastError}`); } else { @@ -127,7 +127,7 @@ function updateCheckUncheck() { The click event listener, where we perform the appropriate action given the ID of the menu item that was clicked. */ -browser.contextMenus.onClicked.addListener(function(info, tab) { +browser.contextMenus.onClicked.addListener((info, tab) => { switch (info.menuItemId) { case "log-selection": console.log(info.selectionText); diff --git a/embedded-webextension-bootstrapped/.eslintrc.json b/embedded-webextension-bootstrapped/.eslintrc.json new file mode 100644 index 0000000..30e26e9 --- /dev/null +++ b/embedded-webextension-bootstrapped/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "env": { + "browser": true, + "es6": true, + "amd": true, + "webextensions": true + } +} diff --git a/embedded-webextension-sdk/.eslintrc.json b/embedded-webextension-sdk/.eslintrc.json new file mode 100644 index 0000000..30e26e9 --- /dev/null +++ b/embedded-webextension-sdk/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "env": { + "browser": true, + "es6": true, + "amd": true, + "webextensions": true + } +} diff --git a/emoji-substitution/emojiMap.js b/emoji-substitution/emojiMap.js index 16c689e..b2f1b9e 100644 --- a/emoji-substitution/emojiMap.js +++ b/emoji-substitution/emojiMap.js @@ -2,6 +2,8 @@ * This file contains the Map of word --> emoji substitutions. */ +/* exported sortedEmojiMap */ + let dictionary = new Map(); dictionary.set('apple', '🍎'); dictionary.set('banana', '🍌'); diff --git a/emoji-substitution/substitute.js b/emoji-substitution/substitute.js index c886063..39203db 100644 --- a/emoji-substitution/substitute.js +++ b/emoji-substitution/substitute.js @@ -3,6 +3,8 @@ * all occurrences of each mapped word with its emoji counterpart. */ +/*global sortedEmojiMap*/ + // emojiMap.js defines the 'sortedEmojiMap' variable. // Referenced here to reduce confusion. const emojiMap = sortedEmojiMap; diff --git a/google-userinfo/background/authorize.js b/google-userinfo/background/authorize.js index 633c41b..b49bb72 100644 --- a/google-userinfo/background/authorize.js +++ b/google-userinfo/background/authorize.js @@ -1,3 +1,5 @@ +/* exported getAccessToken */ + const REDIRECT_URL = browser.identity.getRedirectURL(); const CLIENT_ID = "YOUR-CLIENT-ID"; const SCOPES = ["openid", "email", "profile"]; diff --git a/google-userinfo/background/main.js b/google-userinfo/background/main.js index ac70222..9ddf1fb 100644 --- a/google-userinfo/background/main.js +++ b/google-userinfo/background/main.js @@ -1,3 +1,5 @@ +/*global getAccessToken*/ + function notifyUser(user) { browser.notifications.create({ "type": "basic", diff --git a/google-userinfo/background/userinfo.js b/google-userinfo/background/userinfo.js index 84a5427..5f7ac1d 100644 --- a/google-userinfo/background/userinfo.js +++ b/google-userinfo/background/userinfo.js @@ -2,6 +2,9 @@ Fetch the user's info, passing in the access token in the Authorization HTTP request header. */ + +/* exported getUserInfo */ + function getUserInfo(accessToken) { const requestURL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"; const requestHeaders = new Headers(); diff --git a/history-deleter/history.js b/history-deleter/history.js index 11a1dff..798f8db 100644 --- a/history-deleter/history.js +++ b/history-deleter/history.js @@ -7,7 +7,7 @@ function get_hostname(url) { } function set_domain(domain) { - spans = document.getElementsByClassName('domain'); + const spans = document.getElementsByClassName('domain'); [].slice.call(spans).forEach((span) => { span.textContent = domain; }); @@ -65,7 +65,7 @@ function clearAll(e) { // Loop through them and delete them one by one. var searchingHistory = browser.history.search({text: hostname}) searchingHistory.then((results) => { - for (k = 0; k < results.length; k++) { + for (let k of results) { browser.history.deleteUrl({url: results[k].url}); } // Clear out the UI. diff --git a/list-cookies/cookies.js b/list-cookies/cookies.js index 74c5a84..db2fc8e 100644 --- a/list-cookies/cookies.js +++ b/list-cookies/cookies.js @@ -1,6 +1,6 @@ function showCookiesForTab(tabs) { //get the first tab object in the array - tab = tabs.pop(); + let tab = tabs.pop(); //get all cookies in the domain var gettingAllCookies = browser.cookies.getAll({url: tab.url}); @@ -14,22 +14,22 @@ function showCookiesForTab(tabs) { if (cookies.length > 0) { //add an
  • item with the name and value of the cookie to the list - for (cookie of cookies) { - var li = document.createElement("li"); - var content = document.createTextNode(cookie.name + ": "+ cookie.value); + for (let cookie of cookies) { + let li = document.createElement("li"); + let content = document.createTextNode(cookie.name + ": "+ cookie.value); li.appendChild(content); cookieList.appendChild(li); } } else { - var p = document.createElement("p"); - var content = document.createTextNode("No cookies in this tab."); - var parent = cookieList.parentNode; + let p = document.createElement("p"); + let content = document.createTextNode("No cookies in this tab."); + let parent = cookieList.parentNode; p.appendChild(content); parent.appendChild(p); } }); -}; +} //get active tab to run an callback function. //it sends to our callback an array of tab objects diff --git a/mocha-client-tests/.eslintrc.json b/mocha-client-tests/.eslintrc.json new file mode 100644 index 0000000..30e26e9 --- /dev/null +++ b/mocha-client-tests/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "env": { + "browser": true, + "es6": true, + "amd": true, + "webextensions": true + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..019418f --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "webextensions-examples", + "title": "WebExtensions Examples", + "version": "1.0.0", + "description": "Example Firefox add-ons created using the WebExtensions API", + "devDependencies": { + "eslint": "^3.19.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/mdn/webextensions-examples.git" + }, + "scripts": { + "test": "eslint .", + "lint": "eslint ." + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/mdn/webextensions-examples/issues" + }, + "keywords": [ + "webextensions", + "webextensions-apis", + "mdn", + "firefox", + "mozilla" + ], + "homepage": "https://developer.mozilla.org/Add-ons/WebExtensions/Examples", + "dependencies": { + "babel-eslint": "^7.2.3" + } +} diff --git a/page-to-extension-messaging/content-script.js b/page-to-extension-messaging/content-script.js index 01646c9..418fa46 100644 --- a/page-to-extension-messaging/content-script.js +++ b/page-to-extension-messaging/content-script.js @@ -2,7 +2,7 @@ Listen for messages from the page. If the message was from the page script, show an alert. */ -window.addEventListener("message", function(event) { +window.addEventListener("message", (event) => { if (event.source == window && event.data && event.data.direction == "from-page-script") { diff --git a/permissions/.eslintrc.json b/permissions/.eslintrc.json new file mode 100644 index 0000000..22c3ada --- /dev/null +++ b/permissions/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "parserOptions": { + "ecmaVersion": 8 + } +} diff --git a/proxy-blocker/background/proxy-handler.js b/proxy-blocker/background/proxy-handler.js index 098089c..aabcd89 100644 --- a/proxy-blocker/background/proxy-handler.js +++ b/proxy-blocker/background/proxy-handler.js @@ -15,7 +15,7 @@ browser.proxy.onProxyError.addListener(error => { }); // Initialize the proxy -function handleInit(message) { +function handleInit() { // update the proxy whenever stored settings change browser.storage.onChanged.addListener((newSettings) => { browser.runtime.sendMessage(newSettings.blockedHosts.newValue, {toProxyScript: true}); diff --git a/proxy-blocker/proxy/proxy-script.js b/proxy-blocker/proxy/proxy-script.js index 135295c..31343e6 100644 --- a/proxy-blocker/proxy/proxy-script.js +++ b/proxy-blocker/proxy/proxy-script.js @@ -1,3 +1,5 @@ +/* exported FindProxyForURL */ + var blockedHosts = []; const allow = "DIRECT 1234"; const deny = "PROXY 127.0.0.1:65535"; diff --git a/quicknote/popup/quicknote.js b/quicknote/popup/quicknote.js index b94c29e..04d5a81 100644 --- a/quicknote/popup/quicknote.js +++ b/quicknote/popup/quicknote.js @@ -27,7 +27,7 @@ function initialize() { var gettingAllStorageItems = browser.storage.local.get(null); gettingAllStorageItems.then((results) => { var noteKeys = Object.keys(results); - for(noteKey of noteKeys) { + for (let noteKey of noteKeys) { var curValue = results[noteKey]; displayNote(noteKey,curValue); } @@ -88,8 +88,8 @@ function displayNote(title, body) { /* set up listener for the delete functionality */ - deleteBtn.addEventListener('click',function(e){ - evtTgt = e.target; + deleteBtn.addEventListener('click',(e) => { + const evtTgt = e.target; evtTgt.parentNode.parentNode.parentNode.removeChild(evtTgt.parentNode.parentNode); browser.storage.local.remove(title); }) @@ -125,24 +125,24 @@ function displayNote(title, body) { /* set up listeners for the update functionality */ - noteH.addEventListener('click',function(){ + noteH.addEventListener('click',() => { noteDisplay.style.display = 'none'; noteEdit.style.display = 'block'; }) - notePara.addEventListener('click',function(){ + notePara.addEventListener('click',() => { noteDisplay.style.display = 'none'; noteEdit.style.display = 'block'; }) - cancelBtn.addEventListener('click',function(){ + cancelBtn.addEventListener('click',() => { noteDisplay.style.display = 'block'; noteEdit.style.display = 'none'; noteTitleEdit.value = title; noteBodyEdit.value = body; }) - updateBtn.addEventListener('click',function(){ + updateBtn.addEventListener('click',() => { if(noteTitleEdit.value !== title || noteBodyEdit.value !== body) { updateNote(title,noteTitleEdit.value,noteBodyEdit.value); note.parentNode.removeChild(note); diff --git a/react-es6-popup/.eslintrc.json b/react-es6-popup/.eslintrc.json new file mode 100644 index 0000000..bc30d96 --- /dev/null +++ b/react-es6-popup/.eslintrc.json @@ -0,0 +1,15 @@ +{ + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } + }, + "env": { + "browser": true, + "es6": true, + "amd": true, + "webextensions": true + } +} diff --git a/selection-to-clipboard/content-script.js b/selection-to-clipboard/content-script.js index 8fb2598..1b78c5b 100644 --- a/selection-to-clipboard/content-script.js +++ b/selection-to-clipboard/content-script.js @@ -1,7 +1,7 @@ /* copy the selected text to clipboard */ -function copySelection(e) { +function copySelection() { var selectedText = window.getSelection().toString().trim(); if (selectedText) { diff --git a/tabs-tabs-tabs/tabs.js b/tabs-tabs-tabs/tabs.js index dba3dfc..27e7a1b 100644 --- a/tabs-tabs-tabs/tabs.js +++ b/tabs-tabs-tabs/tabs.js @@ -47,7 +47,7 @@ function getCurrentWindowTabs() { return browser.tabs.query({currentWindow: true}); } -document.addEventListener("click", function(e) { +document.addEventListener("click", (e) => { function callOnActiveTab(callback) { getCurrentWindowTabs().then((tabs) => { for (var tab of tabs) { @@ -163,7 +163,7 @@ document.addEventListener("click", function(e) { // Currently (11/2/2016) only supported by Chrome else if (e.target.id === "tabs-highlight") { // highlights current tab and next tab (cycles back to first tab if current tab is the last one) callOnActiveTab((tab, tabs) => { - next = (tab.index+1) % tabs.length; + let next = (tab.index+1) % tabs.length; browser.tabs.highlight({tabs:[tab.index, next]}); }); } @@ -173,7 +173,7 @@ document.addEventListener("click", function(e) { chrome.tabs.query({ currentWindow: true - }, function(tabs) { + }, (tabs) => { for (var tab of tabs) { if (tab.id === tabId) { chrome.tabs.update(tabId, { @@ -188,7 +188,7 @@ document.addEventListener("click", function(e) { }); //onRemoved listener. fired when tab is removed -browser.tabs.onRemoved.addListener(function(tabId, removeInfo){ +browser.tabs.onRemoved.addListener((tabId, removeInfo) => { console.log(`The tab with id: ${tabId}, is closing`); if(removeInfo.isWindowClosing) { @@ -199,7 +199,7 @@ browser.tabs.onRemoved.addListener(function(tabId, removeInfo){ }); //onMoved listener. fired when tab is moved into the same window -browser.tabs.onMoved.addListener(function(tabId, moveInfo){ +browser.tabs.onMoved.addListener((tabId, moveInfo) => { var startIndex = moveInfo.fromIndex; var endIndex = moveInfo.toIndex; console.log(`Tab with id: ${tabId} moved from index: ${startIndex} to index: ${endIndex}`); diff --git a/user-agent-rewriter/popup/choose_ua.js b/user-agent-rewriter/popup/choose_ua.js index baaddaf..91dbbc9 100644 --- a/user-agent-rewriter/popup/choose_ua.js +++ b/user-agent-rewriter/popup/choose_ua.js @@ -4,7 +4,7 @@ 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) { +document.addEventListener("click", (e) => { if (!e.target.classList.contains("ua-choice")) { return; } diff --git a/webpack-modules/.eslintrc.json b/webpack-modules/.eslintrc.json new file mode 100644 index 0000000..30e26e9 --- /dev/null +++ b/webpack-modules/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "env": { + "browser": true, + "es6": true, + "amd": true, + "webextensions": true + } +} diff --git a/window-manipulator/window.js b/window-manipulator/window.js index d6e36eb..a659b48 100644 --- a/window-manipulator/window.js +++ b/window-manipulator/window.js @@ -26,48 +26,48 @@ document.addEventListener("click", (e) => { } else if (e.target.id === "window-create-normal") { - var createData = {}; - var creating = browser.windows.create(createData); + let createData = {}; + let creating = browser.windows.create(createData); creating.then(() => { console.log("The normal window has been created"); }); } else if (e.target.id === "window-create-incognito") { - var createData = { + let createData = { incognito: true, }; - var creating = browser.windows.create(createData); + let creating = browser.windows.create(createData); creating.then(() => { console.log("The incognito window has been created"); }); } else if (e.target.id === "window-create-panel") { - var createData = { + let createData = { type: "panel", }; - var creating = browser.windows.create(createData); + let creating = browser.windows.create(createData); creating.then(() => { console.log("The panel has been created"); }); } else if (e.target.id === "window-create-detached-panel") { - var createData = { + let createData = { type: "detached_panel", }; - var creating = browser.windows.create(createData); + let creating = browser.windows.create(createData); creating.then(() => { console.log("The detached panel has been created"); }); } else if (e.target.id === "window-create-popup") { - var createData = { + let createData = { type: "popup", }; - var creating = browser.windows.create(createData); + let creating = browser.windows.create(createData); creating.then(() => { console.log("The popup has been created"); });