From 35c63a0b7744d27ea0bb83f9eb02109ffab9b05a Mon Sep 17 00:00:00 2001 From: Mike-FreeAI <145850829+Mike-FreeAI@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:56:18 +0100 Subject: [PATCH] Add unsteal feature Add unsteal feature to the button stealer. * **offscreen/offscreen.js** - Add `unsteal` function to unpublish and delete an entry from Contentful. - Add a new case in `handleMessages` to handle the `unsteal-button` message. * **popup/popup.js** - Add `unstealButton` function to send a message to the background script to unsteal a button. - Add an event listener to the "Unsteal" button to call `unstealButton`. * **scripts/service-worker.js** - Add a new case in `handleMessages` to handle the `unsteal-button` message and call `unstealOffscreen`. - Add `unstealOffscreen` function to send a message to the offscreen document to unsteal a button. * **popup/popup.html** - Add a new button with id `unsteal` to the settings form. --- offscreen/offscreen.js | 338 +++++++++++++++++++--------------- popup/popup.html | 16 +- popup/popup.js | 267 ++++++++++++++------------- scripts/service-worker.js | 377 ++++++++++++++++++++------------------ 4 files changed, 532 insertions(+), 466 deletions(-) diff --git a/offscreen/offscreen.js b/offscreen/offscreen.js index 2399925..ba9a774 100644 --- a/offscreen/offscreen.js +++ b/offscreen/offscreen.js @@ -1,152 +1,186 @@ -const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; -const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; -const CNTFL_SPACE_ID = 'spaceId'; -const CNTFL_TYPE_ID = 'contentTypeId'; - -const upload = async (button, contentful) => { - const content_management_api_key = contentful[CNTFL_MGMT_API_KEY]; - const space_id = contentful[CNTFL_SPACE_ID]; - const content_type_id = contentful[CNTFL_TYPE_ID]; - const environment_id = 'master'; - - const client = createClient({ - accessToken: content_management_api_key - }); - let error = false; - await client.getSpace(space_id) - .then((space) => space.getEnvironment(environment_id)) - .then((env) => env.createEntry(content_type_id, { - fields: { - name: { 'en-US': button.name }, - code: { 'en-US': button.code }, - source: { 'en-US': button.source }, - text: { 'en-US': button.text } - } - })) - .then((entry) => entry.publish()) - .then((entry) => console.log(`Entry ${entry.sys.id} published.`)) - .catch(e => { - console.log(e.message); - error = true; - }) - .finally((e) => { - if (!error) { - sendToBackground(); - } - }); -} - -const find = async (name, cntfl) => { - const content_delivery_api_key = cntfl[CNTFL_DLVR_API_KEY]; - const space_id = cntfl[CNTFL_SPACE_ID]; - const content_type_id = cntfl[CNTFL_TYPE_ID]; - const client = contentful.createClient({ - accessToken: content_delivery_api_key, - space: space_id - }); - const entries = await client.getEntries({ - content_type: content_type_id, - select: 'sys.createdAt', - order: '-sys.createdAt', - locale: 'en-US', - 'fields.name[match]': name - }) - return entries.items.map(entry => entry.sys.id); -} - -const remove = async (button, contentful) => { - const ids = await find(button.name, contentful); - if (ids.length === 0) { - sendToBackground(); - return; - } - const content_management_api_key = contentful[CNTFL_MGMT_API_KEY]; - const space_id = contentful[CNTFL_SPACE_ID]; - const environment_id = 'master'; - const client = createClient({ - accessToken: content_management_api_key, - }); - - let error = false; - await client.getSpace(space_id) - .then((space) => space.getEnvironment(environment_id)) - .then((env) => env.getEntry(ids[0])) - .then((entry) => entry.unpublish()) - .then((entry) => entry.delete()) - .then(() => console.log('Entry deleted.')) - .catch(e => { - console.log(e.message); - error = true; - }) - .finally((e) => { - if (!error) { - sendToBackground(); - } - }); -} - -const sync = async (cntfl) => { - const content_delivery_api_key = cntfl[CNTFL_DLVR_API_KEY]; - const space_id = cntfl[CNTFL_SPACE_ID]; - const content_type_id = cntfl[CNTFL_TYPE_ID]; - const client = contentful.createClient({ - accessToken: content_delivery_api_key, - space: space_id - }); - const buttons = []; - let skip = 0; - let total = Infinity; - while (skip < total) { - const entries = await client.getEntries({ - content_type: content_type_id, - locale: 'en-US', - order: '-sys.createdAt', - select: 'fields, sys.createdAt', - skip: skip - }); - total = entries.total; - skip += entries.limit; - buttons.push(...entries.items); - } - const value = buttons.map((button, i) => { - return { - id: buttons.length - i - 1, - name: button.fields.name, - code: button.fields.code, - source: button.fields.source, - text: button.fields.text, - stolenAt: button.sys.createdAt, - } - }); - chrome.runtime.sendMessage({ - type: 'contentful-syncronized', - target: 'background', - value: JSON.stringify(value) - }); -} - -const handleMessages = async (message) => { - if (message.target !== 'offscreen') return false; - switch (message.type) { - case 'upload-stolen-button': - await upload(message.button, message.contentful); - break; - case 'remove-stolen-button': - await remove(message.button, message.contentful); - break; - case 'full-sync': - await sync(message.contentful); - break; - default: - return false; - } -} - -const sendToBackground = () => { - chrome.runtime.sendMessage({ - type: 'stolen-button-uploaded', - target: 'background' - }); -} - -chrome.runtime.onMessage.addListener(handleMessages); \ No newline at end of file +1 const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; +2 const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; +3 const CNTFL_SPACE_ID = 'spaceId'; +4 const CNTFL_TYPE_ID = 'contentTypeId'; +5 +6 const upload = async (button, contentful) => { +7 const content_management_api_key = contentful[CNTFL_MGMT_API_KEY]; +8 const space_id = contentful[CNTFL_SPACE_ID]; +9 const content_type_id = contentful[CNTFL_TYPE_ID]; +10 const environment_id = 'master'; +11 +12 const client = createClient({ +13 accessToken: content_management_api_key +14 }); +15 let error = false; +16 await client.getSpace(space_id) +17 .then((space) => space.getEnvironment(environment_id)) +18 .then((env) => env.createEntry(content_type_id, { +19 fields: { +20 name: { 'en-US': button.name }, +21 code: { 'en-US': button.code }, +22 source: { 'en-US': button.source }, +23 text: { 'en-US': button.text } +24 } +25 })) +26 .then((entry) => entry.publish()) +27 .then((entry) => console.log(`Entry ${entry.sys.id} published.`)) +28 .catch(e => { +29 console.log(e.message); +30 error = true; +31 }) +32 .finally((e) => { +33 if (!error) { +34 sendToBackground(); +35 } +36 }); +37 } +38 +39 const find = async (name, cntfl) => { +40 const content_delivery_api_key = cntfl[CNTFL_DLVR_API_KEY]; +41 const space_id = cntfl[CNTFL_SPACE_ID]; +42 const content_type_id = cntfl[CNTFL_TYPE_ID]; +43 const client = contentful.createClient({ +44 accessToken: content_delivery_api_key, +45 space: space_id +46 }); +47 const entries = await client.getEntries({ +48 content_type: content_type_id, +49 select: 'sys.createdAt', +50 order: '-sys.createdAt', +51 locale: 'en-US', +52 'fields.name[match]': name +53 }) +54 return entries.items.map(entry => entry.sys.id); +55 } +56 +57 const remove = async (button, contentful) => { +58 const ids = await find(button.name, contentful); +59 if (ids.length === 0) { +60 sendToBackground(); +61 return; +62 } +63 const content_management_api_key = contentful[CNTFL_MGMT_API_KEY]; +64 const space_id = contentful[CNTFL_SPACE_ID]; +65 const environment_id = 'master'; +66 const client = createClient({ +67 accessToken: content_management_api_key, +68 }); +69 +70 let error = false; +71 await client.getSpace(space_id) +72 .then((space) => space.getEnvironment(environment_id)) +73 .then((env) => env.getEntry(ids[0])) +74 .then((entry) => entry.unpublish()) +75 .then((entry) => entry.delete()) +76 .then(() => console.log('Entry deleted.')) +77 .catch(e => { +78 console.log(e.message); +79 error = true; +80 }) +81 .finally((e) => { +82 if (!error) { +83 sendToBackground(); +84 } +85 }); +86 } +87 +88 const unsteal = async (button, contentful) => { +89 const ids = await find(button.name, contentful); +90 if (ids.length === 0) { +91 sendToBackground(); +92 return; +93 } +94 const content_management_api_key = contentful[CNTFL_MGMT_API_KEY]; +95 const space_id = contentful[CNTFL_SPACE_ID]; +96 const environment_id = 'master'; +97 const client = createClient({ +98 accessToken: content_management_api_key, +99 }); +100 +101 let error = false; +102 await client.getSpace(space_id) +103 .then((space) => space.getEnvironment(environment_id)) +104 .then((env) => env.getEntry(ids[0])) +105 .then((entry) => entry.unpublish()) +106 .then((entry) => entry.delete()) +107 .then(() => console.log('Entry unstealed.')) +108 .catch(e => { +109 console.log(e.message); +110 error = true; +111 }) +112 .finally((e) => { +113 if (!error) { +114 sendToBackground(); +115 } +116 }); +117 } +118 +119 const sync = async (cntfl) => { +120 const content_delivery_api_key = cntfl[CNTFL_DLVR_API_KEY]; +121 const space_id = cntfl[CNTFL_SPACE_ID]; +122 const content_type_id = cntfl[CNTFL_TYPE_ID]; +123 const client = contentful.createClient({ +124 accessToken: content_delivery_api_key, +125 space: space_id +126 }); +127 const buttons = []; +128 let skip = 0; +129 let total = Infinity; +130 while (skip < total) { +131 const entries = await client.getEntries({ +132 content_type: content_type_id, +133 locale: 'en-US', +134 order: '-sys.createdAt', +135 select: 'fields, sys.createdAt', +136 skip: skip +137 }); +138 total = entries.total; +139 skip += entries.limit; +140 buttons.push(...entries.items); +141 } +142 const value = buttons.map((button, i) => { +143 return { +144 id: buttons.length - i - 1, +145 name: button.fields.name, +146 code: button.fields.code, +147 source: button.fields.source, +148 text: button.fields.text, +149 stolenAt: button.sys.createdAt, +150 } +151 }); +152 chrome.runtime.sendMessage({ +153 type: 'contentful-syncronized', +154 target: 'background', +155 value: JSON.stringify(value) +156 }); +157 } +158 +159 const handleMessages = async (message) => { +160 if (message.target !== 'offscreen') return false; +161 switch (message.type) { +162 case 'upload-stolen-button': +163 await upload(message.button, message.contentful); +164 break; +165 case 'remove-stolen-button': +166 await remove(message.button, message.contentful); +167 break; +168 case 'unsteal-button': +169 await unsteal(message.button, message.contentful); +170 break; +171 case 'full-sync': +172 await sync(message.contentful); +173 break; +174 default: +175 return false; +176 } +177 } +178 +179 const sendToBackground = () => { +180 chrome.runtime.sendMessage({ +181 type: 'stolen-button-uploaded', +182 target: 'background' +183 }); +184 } +185 +186 chrome.runtime.onMessage.addListener(handleMessages); diff --git a/popup/popup.html b/popup/popup.html index ac45937..be38911 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -35,22 +35,26 @@

Settings

Ignore List

- +

Maximum Buttons

- +

Contentful Settings

- - + + - +

These settings are for author use only.

Remove All Buttons + Unsteal Button
@@ -61,4 +65,4 @@

Contentful Settings

- \ No newline at end of file + diff --git a/popup/popup.js b/popup/popup.js index 2577128..975083a 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -1,129 +1,138 @@ -const MAXIMUM = 'maximum'; -const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; -const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; -const CNTFL_SPACE_ID = 'spaceId'; -const CNTFL_TYPE_ID = 'contentTypeId'; -const CONTENTFUL = 'contentful'; -const BUTTONS = 'buttons'; -const IGNORE = 'ignore'; -const maximumInput = document.getElementById(MAXIMUM); -const maximumValue = document.getElementById('maximumValue'); -const ignoreInput = document.getElementById(IGNORE); -const mgmtApiKeyInput = document.getElementById(CNTFL_MGMT_API_KEY); -const dlvrApiKeyInput = document.getElementById(CNTFL_DLVR_API_KEY); -const spaceIdInput = document.getElementById(CNTFL_SPACE_ID); -const typeIdInput = document.getElementById(CNTFL_TYPE_ID); -const contentfulForm = document.getElementById(`${CONTENTFUL}-form`); - -const saveContentful = () => { - const formData = new FormData(contentfulForm); - sendToBackground(`update-${CONTENTFUL}`, JSON.stringify({ - contentManagementApiKey: formData.get(CNTFL_MGMT_API_KEY), - contentDeliveryApiKey: formData.get(CNTFL_DLVR_API_KEY), - spaceId: formData.get(CNTFL_SPACE_ID), - contentTypeId: formData.get(CNTFL_TYPE_ID), - })); -} - -const updateContentful = (contentful) => { - mgmtApiKeyInput.value = contentful.contentManagementApiKey; - dlvrApiKeyInput.value = contentful.contentDeliveryApiKey; - spaceIdInput.value = contentful.spaceId; - typeIdInput.value = contentful.contentTypeId; -} - -const saveMaximum = () => { - sendToBackground(`update-${MAXIMUM}`, maximumInput.value); -} - -const updateMaximum = (maximum) => { - maximumInput.value = maximum; - maximumValue.innerText = maximum; -} - -const saveIgnore = () => { - sendToBackground(`update-${IGNORE}`, ignoreInput.value); -} - -const updateIgnore = (ignore) => { - ignoreInput.value = ignore.join(' '); -} - -const updateButtons = (buttons) => { - let stat; - let length = 0; - buttons.map(button => button.hidden ? length : length++); - switch (true) { - case length === 1: - stat = "One button already stolen" - break; - case length > 1: - stat = `${length} buttons stolen` - break; - default: - stat = "No buttons stolen yet" - break; - } - document.getElementById('stat').innerText = stat; - document.getElementById('buttons').innerHTML = ''; - for (let i = 0; i < Math.min(50, buttons.length); i++) { - const button = buttons[i]; - if (button.hidden) continue; - const div = document.createElement('div'); - div.classList.add('button-wrapper'); - div.innerHTML = button.code; - document.getElementById('buttons').append(div); - } -} - -const getData = async () => { - const { maximum, contentful, ignore, buttons } = await chrome.storage.local.get([MAXIMUM, CONTENTFUL, IGNORE, BUTTONS]); - updateMaximum(maximum); - updateContentful(contentful); - updateIgnore(ignore); - updateButtons(buttons) -} - -const sendToBackground = (type, value) => { - chrome.runtime.sendMessage({ - type, - value, - target: 'background' - }); -} -let maximumDelay = -1; -let contentfulDelay = -1; -let ignoreDelay = -1; - -maximumInput.addEventListener('input', () => { - maximumValue.innerText = maximumInput.value; - clearTimeout(maximumDelay); - maximumDelay = setTimeout(saveMaximum, 500); -}); - -[mgmtApiKeyInput, dlvrApiKeyInput, spaceIdInput, typeIdInput].forEach(input => { - input.addEventListener('input', () => { - clearTimeout(contentfulDelay); - contentfulDelay = setTimeout(saveContentful, 500); - }); -}) - -document.getElementById('remove-all').addEventListener('click', () => { - if (window.confirm("Remove buttons?") == true) { - chrome.runtime.sendMessage({ - type: 'remove-all', - target: 'background' - }); - } -}); - -ignoreInput.addEventListener('input', ()=> { - clearTimeout(ignoreDelay); - contentfulDelay = setTimeout(saveIgnore, 500); -}); - -document.getElementById('switch').addEventListener('click', ()=> { - document.body.classList.toggle('show-settings'); -}); - -getData(); \ No newline at end of file +1 const MAXIMUM = 'maximum'; +2 const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; +3 const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; +4 const CNTFL_SPACE_ID = 'spaceId'; +5 const CNTFL_TYPE_ID = 'contentTypeId'; +6 const CONTENTFUL = 'contentful'; +7 const BUTTONS = 'buttons'; +8 const IGNORE = 'ignore'; +9 const maximumInput = document.getElementById(MAXIMUM); +10 const maximumValue = document.getElementById('maximumValue'); +11 const ignoreInput = document.getElementById(IGNORE); +12 const mgmtApiKeyInput = document.getElementById(CNTFL_MGMT_API_KEY); +13 const dlvrApiKeyInput = document.getElementById(CNTFL_DLVR_API_KEY); +14 const spaceIdInput = document.getElementById(CNTFL_SPACE_ID); +15 const typeIdInput = document.getElementById(CNTFL_TYPE_ID); +16 const contentfulForm = document.getElementById(`${CONTENTFUL}-form`); +17 +18 const saveContentful = () => { +19 const formData = new FormData(contentfulForm); +20 sendToBackground(`update-${CONTENTFUL}`, JSON.stringify({ +21 contentManagementApiKey: formData.get(CNTFL_MGMT_API_KEY), +22 contentDeliveryApiKey: formData.get(CNTFL_DLVR_API_KEY), +23 spaceId: formData.get(CNTFL_SPACE_ID), +24 contentTypeId: formData.get(CNTFL_TYPE_ID), +25 })); +26 } +27 +28 const updateContentful = (contentful) => { +29 mgmtApiKeyInput.value = contentful.contentManagementApiKey; +30 dlvrApiKeyInput.value = contentful.contentDeliveryApiKey; +31 spaceIdInput.value = contentful.spaceId; +32 typeIdInput.value = contentful.contentTypeId; +33 } +34 +35 const saveMaximum = () => { +36 sendToBackground(`update-${MAXIMUM}`, maximumInput.value); +37 } +38 +39 const updateMaximum = (maximum) => { +40 maximumInput.value = maximum; +41 maximumValue.innerText = maximum; +42 } +43 +44 const saveIgnore = () => { +45 sendToBackground(`update-${IGNORE}`, ignoreInput.value); +46 } +47 +48 const updateIgnore = (ignore) => { +49 ignoreInput.value = ignore.join(' '); +50 } +51 +52 const updateButtons = (buttons) => { +53 let stat; +54 let length = 0; +55 buttons.map(button => button.hidden ? length : length++); +56 switch (true) { +57 case length === 1: +58 stat = "One button already stolen" +59 break; +60 case length > 1: +61 stat = `${length} buttons stolen` +62 break; +63 default: +64 stat = "No buttons stolen yet" +65 break; +66 } +67 document.getElementById('stat').innerText = stat; +68 document.getElementById('buttons').innerHTML = ''; +69 for (let i = 0; i < Math.min(50, buttons.length); i++) { +70 const button = buttons[i]; +71 if (button.hidden) continue; +72 const div = document.createElement('div'); +73 div.classList.add('button-wrapper'); +74 div.innerHTML = button.code; +75 document.getElementById('buttons').append(div); +76 } +77 } +78 +79 const getData = async () => { +80 const { maximum, contentful, ignore, buttons } = await chrome.storage.local.get([MAXIMUM, CONTENTFUL, IGNORE, BUTTONS]); +81 updateMaximum(maximum); +82 updateContentful(contentful); +83 updateIgnore(ignore); +84 updateButtons(buttons) +85 } +86 +87 const sendToBackground = (type, value) => { +88 chrome.runtime.sendMessage({ +89 type, +90 value, +91 target: 'background' +92 }); +93 } +94 let maximumDelay = -1; +95 let contentfulDelay = -1; +96 let ignoreDelay = -1; +97 +98 maximumInput.addEventListener('input', () => { +99 maximumValue.innerText = maximumInput.value; +100 clearTimeout(maximumDelay); +101 maximumDelay = setTimeout(saveMaximum, 500); +102 }); +103 +104 [mgmtApiKeyInput, dlvrApiKeyInput, spaceIdInput, typeIdInput].forEach(input => { +105 input.addEventListener('input', () => { +106 clearTimeout(contentfulDelay); +107 contentfulDelay = setTimeout(saveContentful, 500); +108 }); +109 }) +110 +111 document.getElementById('remove-all').addEventListener('click', () => { +112 if (window.confirm("Remove buttons?") == true) { +113 chrome.runtime.sendMessage({ +114 type: 'remove-all', +115 target: 'background' +116 }); +117 } +118 }); +119 +120 ignoreInput.addEventListener('input', ()=> { +121 clearTimeout(ignoreDelay); +122 contentfulDelay = setTimeout(saveIgnore, 500); +123 }); +124 +125 document.getElementById('switch').addEventListener('click', ()=> { +126 document.body.classList.toggle('show-settings'); +127 }); +128 +129 const unstealButton = () => { +130 chrome.runtime.sendMessage({ +131 type: 'unsteal-button', +132 target: 'background' +133 }); +134 } +135 +136 document.getElementById('unsteal').addEventListener('click', unstealButton); +137 +138 getData(); diff --git a/scripts/service-worker.js b/scripts/service-worker.js index f76b89f..a015c6f 100644 --- a/scripts/service-worker.js +++ b/scripts/service-worker.js @@ -1,179 +1,198 @@ -const MAXIMUM = 'maximum'; -const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; -const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; -const CNTFL_SPACE_ID = 'spaceId'; -const CNTFL_TYPE_ID = 'contentTypeId'; -const CONTENTFUL = 'contentful'; -const IGNORE = 'ignore'; -const BUTTONS = 'buttons'; -const UPLOAD = 'upload'; -const OFFSCREEN_DOCUMENT_PATH = '/offscreen/offscreen.html'; -let isDark = false; - -chrome.runtime.onInstalled.addListener(async ({ reason }) => { - switch (reason) { - case 'install': - chrome.storage.local.set({ - buttons: [], - upload: [], - ignore: [], - maximum: 200, - contentful: { - contentManagementApiKey: '', - contentDeliveryApiKey: '', - spaceId: '', - contentTypeId: '' - } - }); - break; - case 'update': - const { buttons, upload, contentful } = await chrome.storage.local.get([BUTTONS, UPLOAD, CONTENTFUL]); - if (buttons.length === 0) break; - let counter = buttons.length - 1; - buttons.map(button => { button.id = counter--; button.hidden = false;} ); - chrome.storage.local.set({ buttons: buttons }); - if (!upload) chrome.storage.local.set({ 'upload': [] }); - if (!contentful.contentDeliveryApiKey) { - contentful.contentDeliveryApiKey = ''; - chrome.storage.local.set({ 'contentful': contentful }); - } - break; - default: - break; - } -}); - -chrome.storage.onChanged.addListener(async (obj) => { - switch (true) { - case obj.hasOwnProperty(MAXIMUM): - const { buttons } = await chrome.storage.local.get(BUTTONS); - while (buttons.length >= obj.maximum.newValue) buttons.pop(); - chrome.storage.local.set({ 'buttons': buttons }); - break; - case obj.hasOwnProperty(UPLOAD): - uploadOffscreen(); - break; - case obj.hasOwnProperty(CONTENTFUL): - uploadOffscreen(); - break; - default: - break; - } -}); - -const uploadOffscreen = async () => { - const { upload, contentful } = await chrome.storage.local.get([UPLOAD, CONTENTFUL]); - if (!(contentful[CNTFL_MGMT_API_KEY] && contentful[CNTFL_DLVR_API_KEY] && contentful[CNTFL_SPACE_ID] && contentful[CNTFL_TYPE_ID])) { - if (upload.length > 0) chrome.storage.local.set({ 'upload': [] }); - return; - } - if (upload.length === 0) { - chrome.runtime.sendMessage({ - type: 'full-sync', - target: 'offscreen', - contentful: contentful - }); - return; - } - if (!(await hasDocument())) { - await chrome.offscreen.createDocument({ - url: OFFSCREEN_DOCUMENT_PATH, - reasons: [chrome.offscreen.Reason.DOM_PARSER], - justification: 'Parse DOM' - }); - } - const button = upload[upload.length - 1]; - const type = button.hasOwnProperty('code') ? 'upload-stolen-button' : 'remove-stolen-button'; - chrome.runtime.sendMessage({ - type: type, - target: 'offscreen', - button: button, - contentful: contentful - }); -} - -const handleMessages = async (message) => { - if (message.target !== 'background') return; - switch (message.type) { - case 'stolen-button-uploaded': - const { upload } = await chrome.storage.local.get(UPLOAD); - upload.pop(); - chrome.runtime.sendMessage({ - type: 'full-refresh', - target: 'stolen-buttons', - }); - chrome.storage.local.set({ 'upload': upload }); - break; - case 'contentful-syncronized': - chrome.storage.local.set({ buttons: JSON.parse(message.value) }); - closeOffscreenDocument(); - break; - case 'update-maximum': - chrome.storage.local.set({ maximum: parseInt(message.value) }); - break; - case 'update-contentful': - chrome.storage.local.set({ contentful: JSON.parse(message.value) }); - break; - case 'update-ignore': - chrome.storage.local.set({ ignore: message.value.split(' ') }); - break; - case 'remove-all': - chrome.storage.local.set({ buttons: [], upload: [] }) - break; - case 'remove-buttons': - handleRemoveButtons(JSON.parse(message.value)); - break; - case 'color-scheme-changed': - if (isDark !== message.isDark) { - isDark = message.isDark; - chrome.action.setIcon({ - "path": { - "16": `/images/icon-${isDark? "dark" : "light"}-16.png`, - "32": `/images/icon-${isDark? "dark" : "light"}-32.png`, - "48": `/images/icon-${isDark? "dark" : "light"}-48.png`, - "128": `/images/icon-${isDark? "dark" : "light"}-128.png` - } - }) - } - break; - default: - break; - } -} - -const handleRemoveButtons = async (selected) => { - const { buttons, upload } = await chrome.storage.local.get([BUTTONS, UPLOAD]); - selected.forEach(s => { - for (let i = 0; i < buttons.length; i++) { - const button = buttons[i]; - if (button.stolenAt === s.stolenAt) { - if (button.name === s.name) { - button.hidden = true; - break; - } - } - } - }); - chrome.storage.local.set({ buttons: buttons }); - upload.unshift(...selected); - chrome.storage.local.set({ upload: upload }); -} - -chrome.runtime.onMessage.addListener(handleMessages); - -const closeOffscreenDocument = async () => { - if (!(await hasDocument())) { - return; - } - await chrome.offscreen.closeDocument(); -} - -const hasDocument = async () => { - const matchedClients = await clients.matchAll(); - for (const client of matchedClients) { - if (client.url.endsWith(OFFSCREEN_DOCUMENT_PATH)) { - return true; - } - } - return false; -} \ No newline at end of file +1 const MAXIMUM = 'maximum'; +2 const CNTFL_MGMT_API_KEY = 'contentManagementApiKey'; +3 const CNTFL_DLVR_API_KEY = 'contentDeliveryApiKey'; +4 const CNTFL_SPACE_ID = 'spaceId'; +5 const CNTFL_TYPE_ID = 'contentTypeId'; +6 const CONTENTFUL = 'contentful'; +7 const IGNORE = 'ignore'; +8 const BUTTONS = 'buttons'; +9 const UPLOAD = 'upload'; +10 const OFFSCREEN_DOCUMENT_PATH = '/offscreen/offscreen.html'; +11 let isDark = false; +12 +13 chrome.runtime.onInstalled.addListener(async ({ reason }) => { +14 switch (reason) { +15 case 'install': +16 chrome.storage.local.set({ +17 buttons: [], +18 upload: [], +19 ignore: [], +20 maximum: 200, +21 contentful: { +22 contentManagementApiKey: '', +23 contentDeliveryApiKey: '', +24 spaceId: '', +25 contentTypeId: '' +26 } +27 }); +28 break; +29 case 'update': +30 const { buttons, upload, contentful } = await chrome.storage.local.get([BUTTONS, UPLOAD, CONTENTFUL]); +31 if (buttons.length === 0) break; +32 let counter = buttons.length - 1; +33 buttons.map(button => { button.id = counter--; button.hidden = false;} ); +34 chrome.storage.local.set({ buttons: buttons }); +35 if (!upload) chrome.storage.local.set({ 'upload': [] }); +36 if (!contentful.contentDeliveryApiKey) { +37 contentful.contentDeliveryApiKey = ''; +38 chrome.storage.local.set({ 'contentful': contentful }); +39 } +40 break; +41 default: +42 break; +43 } +44 }); +45 +46 chrome.storage.onChanged.addListener(async (obj) => { +47 switch (true) { +48 case obj.hasOwnProperty(MAXIMUM): +49 const { buttons } = await chrome.storage.local.get(BUTTONS); +50 while (buttons.length >= obj.maximum.newValue) buttons.pop(); +51 chrome.storage.local.set({ 'buttons': buttons }); +52 break; +53 case obj.hasOwnProperty(UPLOAD): +54 uploadOffscreen(); +55 break; +56 case obj.hasOwnProperty(CONTENTFUL): +57 uploadOffscreen(); +58 break; +59 default: +60 break; +61 } +62 }); +63 +64 const uploadOffscreen = async () => { +65 const { upload, contentful } = await chrome.storage.local.get([UPLOAD, CONTENTFUL]); +66 if (!(contentful[CNTFL_MGMT_API_KEY] && contentful[CNTFL_DLVR_API_KEY] && contentful[CNTFL_SPACE_ID] && contentful[CNTFL_TYPE_ID])) { +67 if (upload.length > 0) chrome.storage.local.set({ 'upload': [] }); +68 return; +69 } +70 if (upload.length === 0) { +71 chrome.runtime.sendMessage({ +72 type: 'full-sync', +73 target: 'offscreen', +74 contentful: contentful +75 }); +76 return; +77 } +78 if (!(await hasDocument())) { +79 await chrome.offscreen.createDocument({ +80 url: OFFSCREEN_DOCUMENT_PATH, +81 reasons: [chrome.offscreen.Reason.DOM_PARSER], +82 justification: 'Parse DOM' +83 }); +84 } +85 const button = upload[upload.length - 1]; +86 const type = button.hasOwnProperty('code') ? 'upload-stolen-button' : 'remove-stolen-button'; +87 chrome.runtime.sendMessage({ +88 type: type, +89 target: 'offscreen', +90 button: button, +91 contentful: contentful +92 }); +93 } +94 +95 const handleMessages = async (message) => { +96 if (message.target !== 'background') return; +97 switch (message.type) { +98 case 'stolen-button-uploaded': +99 const { upload } = await chrome.storage.local.get(UPLOAD); +100 upload.pop(); +101 chrome.runtime.sendMessage({ +102 type: 'full-refresh', +103 target: 'stolen-buttons', +104 }); +105 chrome.storage.local.set({ 'upload': upload }); +106 break; +107 case 'contentful-syncronized': +108 chrome.storage.local.set({ buttons: JSON.parse(message.value) }); +109 closeOffscreenDocument(); +110 break; +111 case 'update-maximum': +112 chrome.storage.local.set({ maximum: parseInt(message.value) }); +113 break; +114 case 'update-contentful': +115 chrome.storage.local.set({ contentful: JSON.parse(message.value) }); +116 break; +117 case 'update-ignore': +118 chrome.storage.local.set({ ignore: message.value.split(' ') }); +119 break; +120 case 'remove-all': +121 chrome.storage.local.set({ buttons: [], upload: [] }) +122 break; +123 case 'remove-buttons': +124 handleRemoveButtons(JSON.parse(message.value)); +125 break; +126 case 'color-scheme-changed': +127 if (isDark !== message.isDark) { +128 isDark = message.isDark; +129 chrome.action.setIcon({ +130 "path": { +131 "16": `/images/icon-${isDark? "dark" : "light"}-16.png`, +132 "32": `/images/icon-${isDark? "dark" : "light"}-32.png`, +133 "48": `/images/icon-${isDark? "dark" : "light"}-48.png`, +134 "128": `/images/icon-${isDark? "dark" : "light"}-128.png` +135 } +136 }) +137 } +138 break; +139 case 'unsteal-button': +140 unstealOffscreen(message.button, message.contentful); +141 break; +142 default: +143 break; +144 } +145 } +146 +147 const handleRemoveButtons = async (selected) => { +148 const { buttons, upload } = await chrome.storage.local.get([BUTTONS, UPLOAD]); +149 selected.forEach(s => { +150 for (let i = 0; i < buttons.length; i++) { +151 const button = buttons[i]; +152 if (button.stolenAt === s.stolenAt) { +153 if (button.name === s.name) { +154 button.hidden = true; +155 break; +156 } +157 } +158 } +159 }); +160 chrome.storage.local.set({ buttons: buttons }); +161 upload.unshift(...selected); +162 chrome.storage.local.set({ upload: upload }); +163 } +164 +165 chrome.runtime.onMessage.addListener(handleMessages); +166 +167 const closeOffscreenDocument = async () => { +168 if (!(await hasDocument())) { +169 return; +170 } +171 await chrome.offscreen.closeDocument(); +172 } +173 +174 const hasDocument = async () => { +175 const matchedClients = await clients.matchAll(); +176 for (const client of matchedClients) { +177 if (client.url.endsWith(OFFSCREEN_DOCUMENT_PATH)) { +178 return true; +179 } +180 } +181 return false; +182 } +183 +184 const unstealOffscreen = async (button, contentful) => { +185 if (!(await hasDocument())) { +186 await chrome.offscreen.createDocument({ +187 url: OFFSCREEN_DOCUMENT_PATH, +188 reasons: [chrome.offscreen.Reason.DOM_PARSER], +189 justification: 'Parse DOM' +190 }); +191 } +192 chrome.runtime.sendMessage({ +193 type: 'unsteal-button', +194 target: 'offscreen', +195 button: button, +196 contentful: contentful +197 }); +198 }