From c7030e88e230571e992f49defd79809bf744712b Mon Sep 17 00:00:00 2001 From: mindsgn Date: Tue, 21 Dec 2021 21:38:20 +0200 Subject: [PATCH 1/2] airbnb eslint style guide --- .eslintrc.json | 3 +++ package.json | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 .eslintrc.json create mode 100644 package.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..44cbe88 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "airbnb" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..7d4b172 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "scripts": { + "lint" : "./node_modules/.bin/eslint" + }, + "devDependencies": { + "eslint": "8.2.0", + "eslint-config-airbnb": "19.0.2", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-jsx-a11y": "6.5.1", + "eslint-plugin-react": "7.27.1", + "eslint-plugin-react-hooks": "4.3.0" + } +} From 974254c8f54aa1b376ebf5a13540fc72648e6cb1 Mon Sep 17 00:00:00 2001 From: mindsgn Date: Tue, 21 Dec 2021 22:59:51 +0200 Subject: [PATCH 2/2] eslint emplementation --- .eslintrc.json | 18 ++- popup.js | 364 +++++++++++++++++++++++-------------------------- scrape.js | 19 +-- 3 files changed, 199 insertions(+), 202 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 44cbe88..c7fa714 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,19 @@ { - "extends": "airbnb" + "extends": "airbnb", + "globals": { + "document": "readonly", + "fetch": "readonly", + "window": "readonly", + "chrome": "readonly" + }, + "rules": { + "max-len": [ + "error", { + "code": 90, + "ignoreComments": true, + "ignoreTrailingComments": true + } + ], + "no-await-in-loop": "off" + } } \ No newline at end of file diff --git a/popup.js b/popup.js index 1733b55..937183c 100644 --- a/popup.js +++ b/popup.js @@ -5,201 +5,179 @@ /** * Event handler for when the HTML popup is loaded and parsed. */ -document.addEventListener('DOMContentLoaded', async() => { - const scrapeButton = document.getElementById("scrapeButton"); - const yesButton = document.getElementById("yesButton"); - const noButton = document.getElementById("noButton"); - const downloadButton = document.getElementById("downloadButton"); - const searchButton = document.getElementById("searchButton"); - - let addressNotes; // address notes returned from a scrape - let displayNotes; // address notes being displayed in a table, whether all or just those returned from a search - - /** - * Retrieves the currently focused tab - * @returns {Promise<*>} - */ - async function getTab() { - const queryOptions = {active: true, currentWindow: true}; - const [tab] = await chrome.tabs.query(queryOptions); - return tab; - } - - /** - * Event handler for when the SCRAPER button is clicked. - * Address notes are scraped if the currently focused tab is 'https://etherscan.io/mynotes_address?p=1'. - * Otherwise, user is prompted to open the tab to 'https://etherscan.io/mynotes_address?p=1'. - */ - scrapeButton.addEventListener("click", async () => { - const tab = await getTab(); // retrieve the currently focused tab - - if (tab.url.match(/https:\/\/etherscan.io\/mynotes_address(\?p=1)?/)) { - scrapeButton.disabled = "true"; - scrapeButton.innerText = "SCRAPING..."; - - try { - addressNotes = await getAllNotes(); - displayNotes = addressNotes; - generateNotesTable(); - } catch (err) { - generateError(err.message); - } - } else { - document.getElementById("prompt").style.display = "block"; - document.getElementById("scrape").style.display = "none"; - } - }); - - /** - * Event handler for when a user accepts the prompt to open the tab to 'https://etherscan.io/mynotes_address?p=1'. - * Re-displays the SCRAPER button prompt. - */ - yesButton.addEventListener("click", async () => { - const tab = await getTab(); - await chrome.tabs.update(tab.id, { url: "https://etherscan.io/mynotes_address?p=1" }); - - document.getElementById("scrape").style.display = "block"; - document.getElementById("prompt").style.display = "none"; - }); - - /** - * Event handler for when a user declines the prompt to open the tab to 'https://etherscan.io/mynotes_address?p=1'. - * Closes the window. - */ - noButton.addEventListener("click", async () => { - window.close(); - }); - - /** - * Event handler for when the DOWNLOAD button is clicked. - * Downloads the scraped address notes in JSON format. - * Closes the window. - */ - downloadButton.addEventListener("click", async () => { - downloadButton.disabled = "true"; // disable the DOWNLOAD button while downloading JSON file - downloadButton.innerText = "DOWNLOADING..."; - - const dataString = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(addressNotes)); - const downloadAnchor = document.getElementById('downloadAnchor'); - downloadAnchor.setAttribute("href", dataString); - downloadAnchor.setAttribute("download", "EtherScanAddressNotes.json"); - downloadAnchor.click(); - - window.close(); - }); - - /** - * Event handler for when the SEARCH button is clicked. - * Displays in a table only the address notes with values which include the search text, case-insensitive. - * If the search text is empty, the table displays all address note values retrieved from the scraper. - */ - searchButton.addEventListener("click", async () => { - let searchTxt = document.getElementById("searchInput").value; - - if (searchTxt.length === 0 || searchTxt === "") { - displayNotes = addressNotes; - } else { - displayNotes = []; - searchTxt = searchTxt.toLowerCase(); - - for (let i = 0; i < addressNotes.length; i++) { - if (addressNotes[i].address.toLowerCase().includes(searchTxt) || - addressNotes[i].nameTag.toLowerCase().includes(searchTxt) || - addressNotes[i].note.toLowerCase().includes(searchTxt) || - addressNotes[i].dateCreated.toLowerCase().includes(searchTxt)) { - displayNotes.push(addressNotes[i]); - } - } - } +document.addEventListener('DOMContentLoaded', async () => { + const scrapeButton = document.getElementById('scrapeButton'); + const yesButton = document.getElementById('yesButton'); + const noButton = document.getElementById('noButton'); + const downloadButton = document.getElementById('downloadButton'); + const searchButton = document.getElementById('searchButton'); + let addressNotes; // address notes returned from a scrape + let displayNotes; // address notes being displayed in a table, whether all or just those returned from a search + /** + * Retrieves the currently focused tab + * @returns {Promise<*>} + */ + async function getTab() { + const queryOptions = { active: true, currentWindow: true }; + const [tab] = await chrome.tabs.query(queryOptions); + return tab; + } + /** + * Event handler for when the SCRAPER button is clicked. + * Address notes are scraped if the currently focused tab is 'https://etherscan.io/mynotes_address?p=1'. + * Otherwise, user is prompted to open the tab to 'https://etherscan.io/mynotes_address?p=1'. + */ + scrapeButton.addEventListener('click', async () => { + const tab = await getTab(); // retrieve the currently focused tab + if (tab.url.match(/https:\/\/etherscan.io\/mynotes_address(\?p=1)?/)) { + scrapeButton.disabled = 'true'; + scrapeButton.innerText = 'SCRAPING...'; + try { + // eslint-disable-next-line no-undef + addressNotes = await getAllNotes(); + displayNotes = addressNotes; + // eslint-disable-next-line no-use-before-define generateNotesTable(); + } catch (err) { + // eslint-disable-next-line no-use-before-define + generateError(err.message); + } + } else { + document.getElementById('prompt').style.display = 'block'; + document.getElementById('scrape').style.display = 'none'; + } + }); + /** + * Event handler for when a user accepts the prompt to open the tab to 'https://etherscan.io/mynotes_address?p=1'. + * Re-displays the SCRAPER button prompt. + */ + yesButton.addEventListener('click', async () => { + const tab = await getTab(); + await chrome.tabs.update(tab.id, { + url: 'https://etherscan.io/mynotes_address?p=1', }); - - /** - * Generates a table containing scraped address note values separated in rows by addresses. - * Either displays all scraped address note values, or address note values returned in a search. - */ - function generateNotesTable() { - if (addressNotes.length === 0) { - generateError("There are no address notes"); - } else { - document.getElementById("notes").style.display = "block"; - document.getElementById("search").style.display = "block"; - document.getElementById("scrape").style.display = "none"; - document.getElementById("downloadButton").style.display = "block"; - - let div = document.getElementById("notes-table"); - let table = document.createElement("table"); - let tableBody = document.createElement("tbody"); - - // table headers - let row = document.createElement("tr"); - - let cell = document.createElement("th"); - let cellText = document.createTextNode("Address"); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("th"); - cellText = document.createTextNode("Name Tag"); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("th"); - cellText = document.createTextNode("Note"); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("th"); - cellText = document.createTextNode("Date Created"); - cell.appendChild(cellText); - row.appendChild(cell); - - tableBody.appendChild(row); - - // table rows - for (let i = 0; i < displayNotes.length; i++) { - row = document.createElement("tr"); - - cell = document.createElement("td"); - cellText = document.createTextNode(displayNotes[i].address); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("td"); - cellText = document.createTextNode(displayNotes[i].nameTag); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("td"); - cellText = document.createTextNode(displayNotes[i].note); - cell.appendChild(cellText); - row.appendChild(cell); - - cell = document.createElement("td"); - cellText = document.createTextNode(displayNotes[i].dateCreated); - cell.appendChild(cellText); - row.appendChild(cell); - - tableBody.appendChild(row); - } - - table.appendChild(tableBody); - div.innerHTML = ""; - div.appendChild(table); + document.getElementById('scrape').style.display = 'block'; + document.getElementById('prompt').style.display = 'none'; + }); + /** + * Event handler for when a user declines the prompt to open the tab to 'https://etherscan.io/mynotes_address?p=1'. + * Closes the window. + */ + noButton.addEventListener('click', async () => { + window.close(); + }); + /** + * Event handler for when the DOWNLOAD button is clicked. + * Downloads the scraped address notes in JSON format. + * Closes the window. + */ + downloadButton.addEventListener('click', async () => { + downloadButton.disabled = 'true'; // disable the DOWNLOAD button while downloading JSON file + downloadButton.innerText = 'DOWNLOADING...'; + // eslint-disable-next-line max-len + const dataString = `data:text/json;charset=utf-8,${encodeURIComponent(JSON.stringify(addressNotes))}`; + const downloadAnchor = document.getElementById('downloadAnchor'); + downloadAnchor.setAttribute('href', dataString); + downloadAnchor.setAttribute('download', 'EtherScanAddressNotes.json'); + downloadAnchor.click(); + window.close(); + }); + + /** + * Event handler for when the SEARCH button is clicked. + * Displays in a table only the address notes with values which include the search text, case-insensitive. + * If the search text is empty, the table displays all address note values retrieved from the scraper. + */ + searchButton.addEventListener('click', async () => { + let searchTxt = document.getElementById('searchInput').value; + if (searchTxt.length === 0 || searchTxt === '') { + displayNotes = addressNotes; + } else { + displayNotes = []; + searchTxt = searchTxt.toLowerCase(); + for (let i = 0; i < addressNotes.length; i += 1) { + if (addressNotes[i].address.toLowerCase().includes(searchTxt) + || addressNotes[i].nameTag.toLowerCase().includes(searchTxt) + || addressNotes[i].note.toLowerCase().includes(searchTxt) + || addressNotes[i].dateCreated.toLowerCase().includes(searchTxt)) { + displayNotes.push(addressNotes[i]); } + } } - - /** - * Displays an error message to the popup window - * @param message the error message - */ - function generateError(message) { - document.getElementById("notes").style.display = "block"; - document.getElementById("scrape").style.display = "none"; - - let div = document.getElementById("notes"); - let paragraph = document.createElement("p"); - paragraph.innerHTML = "Scraping returned error: " + message; - div.appendChild(paragraph); + // eslint-disable-next-line no-use-before-define + generateNotesTable(); + }); + /** + * Generates a table containing scraped address note values separated in rows by addresses. + * Either displays all scraped address note values, or address note values returned in a search. + */ + function generateNotesTable() { + if (addressNotes.length === 0) { + // eslint-disable-next-line no-use-before-define + generateError('There are no address notes'); + } else { + document.getElementById('notes').style.display = 'block'; + document.getElementById('search').style.display = 'block'; + document.getElementById('scrape').style.display = 'none'; + document.getElementById('downloadButton').style.display = 'block'; + const div = document.getElementById('notes-table'); + const table = document.createElement('table'); + const tableBody = document.createElement('tbody'); + // table headers + let row = document.createElement('tr'); + let cell = document.createElement('th'); + let cellText = document.createTextNode('Address'); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('th'); + cellText = document.createTextNode('Name Tag'); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('th'); + cellText = document.createTextNode('Note'); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('th'); + cellText = document.createTextNode('Date Created'); + cell.appendChild(cellText); + row.appendChild(cell); + tableBody.appendChild(row); + // table rows + for (let i = 0; i < displayNotes.length; i += 1) { + row = document.createElement('tr'); + cell = document.createElement('td'); + cellText = document.createTextNode(displayNotes[i].address); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('td'); + cellText = document.createTextNode(displayNotes[i].nameTag); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('td'); + cellText = document.createTextNode(displayNotes[i].note); + cell.appendChild(cellText); + row.appendChild(cell); + cell = document.createElement('td'); + cellText = document.createTextNode(displayNotes[i].dateCreated); + cell.appendChild(cellText); + row.appendChild(cell); + tableBody.appendChild(row); + } + table.appendChild(tableBody); + div.innerHTML = ''; + div.appendChild(table); } -}); \ No newline at end of file + } + /** + * Displays an error message to the popup window + * @param message the error message + */ + function generateError(message) { + document.getElementById('notes').style.display = 'block'; + document.getElementById('scrape').style.display = 'none'; + const div = document.getElementById('notes'); + const paragraph = document.createElement('p'); + paragraph.innerHTML = `Scraping returned error: ${message}`; + div.appendChild(paragraph); + } +}); diff --git a/scrape.js b/scrape.js index ffc1405..cb7fc0f 100644 --- a/scrape.js +++ b/scrape.js @@ -4,8 +4,8 @@ const getNotes = (document) => { const figure = document.getElementById('SVGdataReport1'); - if (! figure) { - throw new Error('Could not find SVGdataReport1') + if (!figure) { + throw new Error('Could not find SVGdataReport1'); } const table = figure.firstElementChild; @@ -17,7 +17,7 @@ const getNotes = (document) => { const list = []; - body.childNodes.forEach(element => { + body.childNodes.forEach((element) => { if (element.nodeName !== 'TR') { return; } @@ -26,7 +26,9 @@ const getNotes = (document) => { const address = element.childNodes[3].childNodes[0].textContent.trim(); const note = element.childNodes[3].childNodes[1].textContent.trim(); const dateCreated = element.childNodes[4].textContent; - list.push({ address, nameTag, note, dateCreated }); + list.push({ + address, nameTag, note, dateCreated, + }); }); return list; @@ -35,11 +37,11 @@ const getNotes = (document) => { const getAllNotes = async () => { let allNotes = []; let i = 1; - + // eslint-disable-next-line no-constant-condition while (true) { const url = `https://etherscan.io/mynotes_address?p=${i}`; const response = await fetch(url); - const result = await response.text(); + const result = await Promise.all(response.text()); const doc = new window.DOMParser().parseFromString(result, 'text/html'); const notes = getNotes(doc); allNotes = allNotes.concat(notes); @@ -47,10 +49,11 @@ const getAllNotes = async () => { if (notes.length === 0) { break; } - i++; + i += 1; } return allNotes; }; -getAllNotes().then(console.log) +// eslint-disable-next-line no-console +getAllNotes().then(console.log);