diff --git a/functional-samples/tutorial.mole-game/README.md b/functional-samples/tutorial.mole-game/README.md new file mode 100644 index 00000000..9d181503 --- /dev/null +++ b/functional-samples/tutorial.mole-game/README.md @@ -0,0 +1,26 @@ +# Mole Game + +This mole game is based on a YouTube tutorial in our Chrome Extensions series. Watch it [here](https://goo.gle/Chrome-Ext). + + + +## Overview + +In the sample, moles periodically appear from pipes in the browser toolbar. You score points by clicking the icon before the mole disappears. + +If enabled, a browser tab is closed if you miss one of the moles. + +## Implementation Notes + +Each icon in the browser toolbar is a seperate extension. The extensions communicate using the `chrome.runtime.sendMessage` API and the `chrome.runtime.onMessageExternal` event. + +To discover mole extensions, the controller extension uses the `chrome.management` API. + +By default, the tab closing behavior is disabled. You can enable this by commenting out the line in `mole/service-worker.js`. + +## Running this extension + +1. Clone this repository. +1. Make several copies of the `mole` directory. +1. Load the `controller` directory and all mole directories in Chrome as [unpacked extensions](https://developer.chrome.com/docs/extensions/mv3/getstarted/development-basics/#load-unpacked). +1. Wait for a mole to appear! diff --git a/functional-samples/tutorial.mole-game/controller/manifest.json b/functional-samples/tutorial.mole-game/controller/manifest.json new file mode 100644 index 00000000..5aceec31 --- /dev/null +++ b/functional-samples/tutorial.mole-game/controller/manifest.json @@ -0,0 +1,10 @@ +{ + "name": "mole controller", + "version": "1.0", + "manifest_version": 3, + "background": { + "service_worker": "service-worker.js" + }, + "permissions": ["management", "alarms"], + "action": {} +} diff --git a/functional-samples/tutorial.mole-game/controller/service-worker.js b/functional-samples/tutorial.mole-game/controller/service-worker.js new file mode 100644 index 00000000..de2c54ee --- /dev/null +++ b/functional-samples/tutorial.mole-game/controller/service-worker.js @@ -0,0 +1,19 @@ +chrome.runtime.onInstalled.addListener(() => { + chrome.alarms.create({ periodInMinutes: (1 / 60) * 3 }); +}); + +chrome.alarms.onAlarm.addListener(async () => { + const extensions = await chrome.management.getAll(); + const moles = extensions.filter((e) => e.name === 'mole'); + + const randomIndex = Math.floor(Math.random() * moles.length); + + chrome.runtime.sendMessage(moles[randomIndex].id, { id: chrome.runtime.id }); +}); + +let counter = 0; + +chrome.runtime.onMessageExternal.addListener(() => { + counter++; + chrome.action.setBadgeText({ text: `${counter}` }); +}); diff --git a/functional-samples/tutorial.mole-game/mole-game.png b/functional-samples/tutorial.mole-game/mole-game.png new file mode 100644 index 00000000..d1df691d Binary files /dev/null and b/functional-samples/tutorial.mole-game/mole-game.png differ diff --git a/functional-samples/tutorial.mole-game/mole/icon-empty.png b/functional-samples/tutorial.mole-game/mole/icon-empty.png new file mode 100644 index 00000000..65b6fe1a Binary files /dev/null and b/functional-samples/tutorial.mole-game/mole/icon-empty.png differ diff --git a/functional-samples/tutorial.mole-game/mole/icon-mole.png b/functional-samples/tutorial.mole-game/mole/icon-mole.png new file mode 100644 index 00000000..328ae859 Binary files /dev/null and b/functional-samples/tutorial.mole-game/mole/icon-mole.png differ diff --git a/functional-samples/tutorial.mole-game/mole/manifest.json b/functional-samples/tutorial.mole-game/mole/manifest.json new file mode 100644 index 00000000..83210d16 --- /dev/null +++ b/functional-samples/tutorial.mole-game/mole/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "mole", + "version": "1.0", + "manifest_version": 3, + "background": { + "service_worker": "service-worker.js" + }, + "action": { + "default_icon": "icon-empty.png" + }, + "permissions": ["management", "tabs"] +} diff --git a/functional-samples/tutorial.mole-game/mole/service-worker.js b/functional-samples/tutorial.mole-game/mole/service-worker.js new file mode 100644 index 00000000..68982a39 --- /dev/null +++ b/functional-samples/tutorial.mole-game/mole/service-worker.js @@ -0,0 +1,38 @@ +let failTimeout; +let moleShowing = false; +let controllerId; + +chrome.action.onClicked.addListener(() => { + if (!moleShowing) return; + + chrome.runtime.sendMessage(controllerId, 'success'); + hideMole(); + + failTimeout && clearTimeout(failTimeout); + failTimeout = undefined; +}); + +function showMole() { + chrome.action.setIcon({ path: 'icon-mole.png' }); + moleShowing = true; +} + +function hideMole() { + chrome.action.setIcon({ path: 'icon-empty.png' }); + moleShowing = false; +} + +chrome.runtime.onMessageExternal.addListener((msg) => { + controllerId = msg.id; + showMole(); + failTimeout = setTimeout(async () => { + hideMole(); + const tabs = await chrome.tabs.query({}); + const eligibleTabs = tabs.filter((t) => t.title.includes('Example')); + + if (eligibleTabs.length > 0) { + // const tabToClose = Math.floor(Math.random() * eligibleTabs.length); + // chrome.tabs.remove(eligibleTabs[tabToClose].id); + } + }, 2000); +});