From 49a39fd090378ca473c9dbf0d4af5b957c0d5f6d Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 23 Sep 2024 20:53:42 +0800 Subject: [PATCH 01/12] preparing for migration to manifest v3 --- package.json | 5 +++-- webpack.config.js | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7f0a9c18..b10b95b6 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,9 @@ } }, "dependencies": { + "@vespaiach/axios-fetch-adapter": "^0.3.1", "@babel/runtime": "^7.10.5", - "axios": "^0.21.1", + "axios": "^0.26.1", "bootstrap": "3.4.1", "d3": "^3.3.8", "icanhaz": "0.10.3", @@ -34,7 +35,7 @@ "spark-md5": "^3.0.1", "sugar": "^1.5.0", "url-join": "^5.0.0", - "webextension-polyfill": "^0.7.0" + "webextension-polyfill": "^0.12.0" }, "devDependencies": { "@babel/core": "^7.10.5", diff --git a/webpack.config.js b/webpack.config.js index 7ea74bb9..d970326f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -30,6 +30,7 @@ const config = { resolve: { extensions: ['.js'], }, + devtool: 'source-map', module: { rules: [ { @@ -76,7 +77,7 @@ const config = { 'window.jQuery': 'jquery', }), new webpack.DefinePlugin({ - global: 'window', + global: 'self', }), new MiniCssExtractPlugin({ filename: '[name].css', @@ -106,8 +107,9 @@ const config = { jsonContent.version = version; if (config.mode === 'development') { - jsonContent.content_security_policy = - "script-src 'self' 'unsafe-eval'; object-src 'self'"; + jsonContent.content_security_policy = { + extension_pages: "script-src 'self'; object-src 'self'", + }; } return JSON.stringify(jsonContent, null, 2); From 9ed3b4325d104b41508ef526276b417b8fb66a81 Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 23 Sep 2024 20:56:26 +0800 Subject: [PATCH 02/12] update manifest file --- src/manifest.json | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/manifest.json b/src/manifest.json index de39622a..533f5d3c 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,11 +1,10 @@ { - "manifest_version": 2, + "manifest_version": 3, "version": "", "name": "__MSG_extension_name__", "short_name": "__MSG_extension_short_name__", "description": "__MSG_extension_description__", "permissions": [ - "", "tabs", "notifications", "storage", @@ -13,12 +12,13 @@ "downloads", "webRequest" ], + "host_permissions": [""], "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" }, - "browser_action": { + "action": { "default_icon": { "19": "icons/icon19.png", "38": "icons/icon38.png" @@ -33,15 +33,20 @@ }, "devtools_page": "devtools/devtools.html", "background": { - "scripts": ["background/background.js"] + "service_worker": "background/background.js" }, "web_accessible_resources": [ - "icons/icon16.png", - "icons/icon19.png", - "icons/icon38.png", - "icons/icon48.png", - "icons/icon128.png", - "content_script/AttachedToolbar.html" + { + "resources": [ + "icons/icon16.png", + "icons/icon19.png", + "icons/icon38.png", + "icons/icon48.png", + "icons/icon128.png", + "content_script/AttachedToolbar.html" + ], + "matches": ["*://*/*"] + } ], "content_scripts": [ { From 795a8b573ffde49993d545ef0e46a77c45676f8a Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 23 Sep 2024 21:18:39 +0800 Subject: [PATCH 03/12] Change $.Deferred() to native Promise --- src/background/background.js | 2 +- src/content_script/content_script.js | 2 +- src/options/options.js | 2 +- src/scripts/BackgroundScript.js | 26 ++----- src/scripts/ContentScript.js | 103 +++++++++++++-------------- src/scripts/Controller.js | 43 +++++------ 6 files changed, 75 insertions(+), 103 deletions(-) diff --git a/src/background/background.js b/src/background/background.js index 96918d14..c66d0553 100644 --- a/src/background/background.js +++ b/src/background/background.js @@ -190,7 +190,7 @@ browser.runtime.onMessage.addListener(async request => { const backgroundScript = getBackgroundScript('BackgroundScript'); // TODO change to promises const deferredResponse = backgroundScript[request.fn](request.request); - deferredResponse.done(resolve).catch(reject); + deferredResponse.then(resolve).catch(reject); }); } }); diff --git a/src/content_script/content_script.js b/src/content_script/content_script.js index c78d2f09..6efa2f82 100644 --- a/src/content_script/content_script.js +++ b/src/content_script/content_script.js @@ -39,7 +39,7 @@ browser.runtime.onMessage.addListener(request => { console.log('received ContentScript request', request); const deferredResponse = contentScript[request.fn](request.request); - deferredResponse.done(function (response) { + deferredResponse.then(function (response) { resolve(response, null); }); diff --git a/src/options/options.js b/src/options/options.js index 2901ec9d..2ba3f278 100644 --- a/src/options/options.js +++ b/src/options/options.js @@ -1,7 +1,7 @@ +import * as $ from 'jquery'; import 'bootstrap/dist/css/bootstrap.css'; import 'bootstrap/dist/js/bootstrap'; import * as browser from 'webextension-polyfill'; -import * as $ from 'jquery'; import Config from '../scripts/Config'; import Translator from '../scripts/Translator'; diff --git a/src/scripts/BackgroundScript.js b/src/scripts/BackgroundScript.js index 290eddb7..28160c5e 100644 --- a/src/scripts/BackgroundScript.js +++ b/src/scripts/BackgroundScript.js @@ -5,7 +5,7 @@ import * as browser from 'webextension-polyfill'; */ const BackgroundScript = { dummy() { - return $.Deferred().resolve('dummy').promise(); + return new Promise.resolve('dummy'); }, /** @@ -42,17 +42,9 @@ const BackgroundScript = { fn: request.fn, request: request.request, }; - const deferredResponse = $.Deferred(); - this.getActiveTabId() - .then(tabId => { - browser.tabs - .sendMessage(tabId, reqToContentScript) - .then(deferredResponse.resolve) - .catch(deferredResponse.reject); - }) - .catch(deferredResponse.reject); - - return deferredResponse; + return this.getActiveTabId().then(tabId => + browser.tabs.sendMessage(tabId, reqToContentScript) + ); }, }; @@ -77,15 +69,7 @@ export default function getBackgroundScript(location) { fn: attr, request, }; - - const deferredResponse = $.Deferred(); - - browser.runtime - .sendMessage(reqToBackgroundScript) - .then(deferredResponse.resolve) - .catch(deferredResponse.reject); - - return deferredResponse; + return browser.runtime.sendMessage(reqToBackgroundScript); }; } else { backgroundScript[attr] = BackgroundScript[attr]; diff --git a/src/scripts/ContentScript.js b/src/scripts/ContentScript.js index 146d1288..be0db375 100644 --- a/src/scripts/ContentScript.js +++ b/src/scripts/ContentScript.js @@ -1,3 +1,4 @@ +import * as $ from 'jquery'; import getBackgroundScript from './BackgroundScript'; import ContentSelector from './ContentSelector'; @@ -11,10 +12,8 @@ const ContentScript = { * @returns $.Deferred() */ getHTML(request) { - const deferredHTML = $.Deferred(); const html = $(request.CSSSelector).clone().wrap('

').parent().html(); - deferredHTML.resolve(html); - return deferredHTML.promise(); + return Promise.resolve(html); }, /** @@ -22,17 +21,13 @@ const ContentScript = { * @returns $.Deferred() */ removeCurrentContentSelector() { - const deferredResponse = $.Deferred(); const contentSelector = window.cs; if (contentSelector === undefined) { - deferredResponse.resolve(); - } else { - contentSelector.removeGUI(); - window.cs = undefined; - deferredResponse.resolve(); + return Promise.resolve(); } - - return deferredResponse.promise(); + contentSelector.removeGUI(); + window.cs = undefined; + return Promise.resolve(); }, /** @@ -41,34 +36,32 @@ const ContentScript = { * @param request.allowedElements */ selectSelector(request) { - const deferredResponse = $.Deferred(); - - this.removeCurrentContentSelector().done( - function () { - const contentSelector = new ContentSelector({ - parentCSSSelector: request.parentCSSSelector, - allowedElements: request.allowedElements, - }); - window.cs = contentSelector; - - const deferredCSSSelector = contentSelector.getCSSSelector(); - deferredCSSSelector - .done( - function (response) { - this.removeCurrentContentSelector().done(function () { - deferredResponse.resolve(response); - window.cs = undefined; - }); - }.bind(this) - ) - .fail(function (message) { - deferredResponse.reject(message); - window.cs = undefined; + return new Promise((resolve, reject) => { + this.removeCurrentContentSelector().then( + function () { + const contentSelector = new ContentSelector({ + parentCSSSelector: request.parentCSSSelector, + allowedElements: request.allowedElements, }); - }.bind(this) - ); + window.cs = contentSelector; - return deferredResponse.promise(); + const deferredCSSSelector = contentSelector.getCSSSelector(); + deferredCSSSelector + .then( + function (response) { + this.removeCurrentContentSelector().then(function () { + resolve(response); + window.cs = undefined; + }); + }.bind(this) + ) + .catch(function (message) { + reject(message); + window.cs = undefined; + }); + }.bind(this) + ); + }); }, /** @@ -77,26 +70,26 @@ const ContentScript = { * @param request.elementCSSSelector */ previewSelector(request) { - const deferredResponse = $.Deferred(); - this.removeCurrentContentSelector().done(function () { - const contentSelector = new ContentSelector({ - parentCSSSelector: request.parentCSSSelector, - }); - window.cs = contentSelector; - - const deferredSelectorPreview = contentSelector.previewSelector( - request.elementCSSSelector - ); - deferredSelectorPreview - .done(function () { - deferredResponse.resolve(); - }) - .fail(function (message) { - deferredResponse.reject(message); - window.cs = undefined; + return new Promise((resolve, reject) => { + this.removeCurrentContentSelector().then(function () { + const contentSelector = new ContentSelector({ + parentCSSSelector: request.parentCSSSelector, }); + window.cs = contentSelector; + + const deferredSelectorPreview = contentSelector.previewSelector( + request.elementCSSSelector + ); + deferredSelectorPreview + .then(function () { + resolve(); + }) + .catch(function (message) { + reject(message); + window.cs = undefined; + }); + }); }); - return deferredResponse; }, }; diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index 424efbb3..44b0118b 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -621,7 +621,8 @@ export default class SitemapController { 'sitemap_either_start_urls_and_pattern' ), }; - } else if (Object.hasOwn(sitemap, 'startUrls')) { + } + if (Object.hasOwn(sitemap, 'startUrls')) { if (!Sitemap.validateStartUrls(sitemap.startUrls)) { return { valid: false, @@ -1466,7 +1467,7 @@ export default class SitemapController { }); }); - let options = { + const options = { id, selector: selectorsSelector, tableHeaderRowSelector, @@ -2012,12 +2013,10 @@ export default class SitemapController { currentStateParentSelectorIds ); - const result = await this.contentScript - .selectSelector({ - parentCSSSelector, - allowedElements: selector.getItemCSSSelector(), - }) - .promise(); + const result = await this.contentScript.selectSelector({ + parentCSSSelector, + allowedElements: selector.getItemCSSSelector(), + }); selector = this.getCurrentlyEditedSelector(); await selector.afterSelect(result.CSSSelector, this, input.attr('id')); @@ -2059,12 +2058,10 @@ export default class SitemapController { currentStateParentSelectorIds ); - const result = await this.contentScript - .selectSelector({ - parentCSSSelector, - allowedElements: 'tr', - }) - .promise(); + const result = await this.contentScript.selectSelector({ + parentCSSSelector, + allowedElements: 'tr', + }); const tableHeaderRowSelector = result.CSSSelector; selector.tableHeaderRowSelector = tableHeaderRowSelector; @@ -2089,12 +2086,10 @@ export default class SitemapController { currentStateParentSelectorIds ); - const result = await this.contentScript - .selectSelector({ - parentCSSSelector, - allowedElements: 'tr', - }) - .promise(); + const result = await this.contentScript.selectSelector({ + parentCSSSelector, + allowedElements: 'tr', + }); // update validation for selector field const input = $(button).closest('.form-group').find('input.selector-value'); @@ -2143,7 +2138,7 @@ export default class SitemapController { elementCSSSelector: selector.selector, }); - deferredSelectorPreview.done(function () { + deferredSelectorPreview.then(function () { $(button).addClass('preview'); }); } else { @@ -2172,7 +2167,7 @@ export default class SitemapController { elementCSSSelector: selector[inputName], }); - deferredSelectorPreview.done(function () { + deferredSelectorPreview.then(function () { $(button).addClass('preview'); }); } else { @@ -2202,7 +2197,7 @@ export default class SitemapController { elementCSSSelector: rowSelector, }); - deferredSelectorPreview.done(function () { + deferredSelectorPreview.then(function () { $(button).addClass('preview'); }); } else { @@ -2229,7 +2224,7 @@ export default class SitemapController { elementCSSSelector: selector.selector, }); - deferredSelectorPreview.done(function () { + deferredSelectorPreview.then(function () { $(button).addClass('preview'); }); } else { From a15bba1b037aa9cd51af26e9cd31b6d0aa66c00b Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 23 Sep 2024 21:21:47 +0800 Subject: [PATCH 04/12] Add fetchAdapter to axios(hotfix) --- src/scripts/StoreRestApi.js | 14 ++++++++++---- src/scripts/StoreTalismanApi.js | 11 +++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/scripts/StoreRestApi.js b/src/scripts/StoreRestApi.js index 6f7559f8..2b786c98 100644 --- a/src/scripts/StoreRestApi.js +++ b/src/scripts/StoreRestApi.js @@ -2,12 +2,14 @@ import axios from 'axios'; import Sitemap from './Sitemap'; import StorePouchDB from './StorePouchDB'; import urlJoin from 'url-join'; +import fetchAdapter from '@vespaiach/axios-fetch-adapter'; export default class StoreRestApi { constructor(config, baseUrl, sitemapsPath = 'sitemaps/') { this.localDataStore = new StorePouchDB(config); this.axiosInstance = axios.create({ baseURL: baseUrl, + adapter: fetchAdapter, }); this.axiosInstance.defaults.headers.post['Content-Type'] = 'application/json'; this.axiosInstance.defaults.headers.put['Content-Type'] = 'application/json'; @@ -17,10 +19,14 @@ export default class StoreRestApi { setAxiosInterceptors() { this.axiosInstance.interceptors.response.use(response => { - const [contentType] = response.headers['content-type'].split(';'); - if (contentType !== 'application/json') { - const error = new Error(`Incorrect response type`); - return Promise.reject(error); + //TODO return it when change axios to fetch + // const [contentType] = response.headers['content-type'].split(';'); + // if (contentType !== 'application/json') { + // const error = new Error(`Incorrect response type`); + // return Promise.reject(error); + // } + if (response.headers['content-type']) { + console.log(response.headers['content-type']); } return response; }); diff --git a/src/scripts/StoreTalismanApi.js b/src/scripts/StoreTalismanApi.js index c5d21b3e..fef30179 100644 --- a/src/scripts/StoreTalismanApi.js +++ b/src/scripts/StoreTalismanApi.js @@ -1,4 +1,5 @@ import axios from 'axios'; +import fetchAdapter from '@vespaiach/axios-fetch-adapter'; import StoreRestApi from './StoreRestApi'; import urlJoin from 'url-join'; import * as browser from 'webextension-polyfill'; @@ -35,6 +36,7 @@ export default class StoreTalismanApi extends StoreRestApi { const response = await axios({ method: 'get', url: urlJoin(this.axiosInstance.defaults.baseURL, 'meta.json'), + adapter: fetchAdapter, }); return response.data.APP_NAME; } @@ -50,6 +52,7 @@ export default class StoreTalismanApi extends StoreRestApi { headers: { 'Content-Type': 'multipart/form-data', }, + adapter: fetchAdapter, }) .catch(er => er); if (loginStatus.isAxiosError || loginStatus.data.access_token === undefined) { @@ -74,7 +77,8 @@ export default class StoreTalismanApi extends StoreRestApi { setAxiosInterceptors() { this.axiosInstance.interceptors.response.use(response => { - if (response.request.responseURL.includes('auth')) { + // response.request.responseURL is not returned with current axios config, mb it's return when we change axios to fetch + if (response.request.responseURL && response.request.responseURL.includes('auth')) { browser.runtime.sendMessage({ authError: true, }); @@ -97,6 +101,7 @@ export default class StoreTalismanApi extends StoreRestApi { const response = await axios({ method: 'get', url: `${tUrl}/oauth/token`, + adapter: fetchAdapter, }); try { if (response.data.preferred_username) { @@ -124,7 +129,9 @@ export default class StoreTalismanApi extends StoreRestApi { sortDirection: 'ascending', }, }; - const projects = await this.axiosInstance.post('/graphql', queryData); + const projects = await this.axiosInstance.post('/graphql', queryData, { + adapter: fetchAdapter, + }); return projects.data.data.paginationProject.listProject; } From 0585039576ac3a71ef3d9033c353e4953433dfdc Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 23 Sep 2024 21:36:03 +0800 Subject: [PATCH 05/12] refactor jquery.whencallsequentially.js to native Promise(local scraper fix) --- src/libs/jquery.whencallsequentially.js | 49 ++++--------------------- src/scripts/DataExtractor.js | 10 ++--- src/scripts/Scraper.js | 11 ++---- 3 files changed, 17 insertions(+), 53 deletions(-) diff --git a/src/libs/jquery.whencallsequentially.js b/src/libs/jquery.whencallsequentially.js index 305f4f25..2709e3b9 100644 --- a/src/libs/jquery.whencallsequentially.js +++ b/src/libs/jquery.whencallsequentially.js @@ -1,47 +1,14 @@ -/** - * @author Martins Balodis - * - * An alternative version of $.when which can be used to execute asynchronous - * calls sequentially one after another. - * - * @returns $.Deferred().promise() - */ $.whenCallSequentially = function (functionCalls) { - const deferredResonse = $.Deferred(); - const resultData = new Array(); + let promiseChain = Promise.resolve([]); - // nothing to do - if (functionCalls.length === 0) { - return deferredResonse.resolve(resultData).promise(); - } - - let currentDeferred = functionCalls.shift()(); - // execute synchronous calls synchronously - while (currentDeferred.state() === 'resolved') { - currentDeferred.done(function (data) { - resultData.push(data); - }); - if (functionCalls.length === 0) { - return deferredResonse.resolve(resultData).promise(); - } - currentDeferred = functionCalls.shift()(); - } - - // handle async calls - var interval = setInterval(function () { - // handle mixed sync calls - while (currentDeferred.state() === 'resolved') { - currentDeferred.done(function (data) { + functionCalls.forEach(func => { + promiseChain = promiseChain.then(resultData => { + return func().then(data => { resultData.push(data); + return resultData; }); - if (functionCalls.length === 0) { - clearInterval(interval); - deferredResonse.resolve(resultData); - break; - } - currentDeferred = functionCalls.shift()(); - } - }, 10); + }); + }); - return deferredResonse.promise(); + return promiseChain; }; diff --git a/src/scripts/DataExtractor.js b/src/scripts/DataExtractor.js index 39a47a73..1592a7c7 100644 --- a/src/scripts/DataExtractor.js +++ b/src/scripts/DataExtractor.js @@ -129,7 +129,7 @@ export default class DataExtractor { ); const deferredResponse = $.Deferred(); - $.whenCallSequentially(deferredDataCalls).done(function (responses) { + $.whenCallSequentially(deferredDataCalls).then(function (responses) { let commonData = {}; responses.forEach(function (data) { commonData = Object.merge(commonData, data); @@ -159,7 +159,7 @@ export default class DataExtractor { ); }.bind(this) ) - ).done(function (results) { + ).then(function (results) { d.resolve({ [selector.id]: results.flat() }); }); } else { @@ -226,7 +226,7 @@ export default class DataExtractor { }.bind(this) ); - $.whenCallSequentially(deferredDataCalls).done(function (responses) { + $.whenCallSequentially(deferredDataCalls).then(function (responses) { const resultData = []; responses.forEach(function (childRecordList) { childRecordList.forEach(function (childRecord) { @@ -275,7 +275,7 @@ export default class DataExtractor { ); // merge all data records together - $.whenCallSequentially(dataDeferredCalls).done(function (responses) { + $.whenCallSequentially(dataDeferredCalls).then(function (responses) { const resultData = []; responses.forEach(function (childRecords) { childRecords.forEach(function (childRecord) { @@ -356,7 +356,7 @@ export default class DataExtractor { ); const responseDeferred = $.Deferred(); - $.whenCallSequentially(dataDeferredCalls).done( + $.whenCallSequentially(dataDeferredCalls).then( function (responses) { let results = []; responses.forEach(function (dataResults) { diff --git a/src/scripts/Scraper.js b/src/scripts/Scraper.js index adbba10a..4a3cce5f 100644 --- a/src/scripts/Scraper.js +++ b/src/scripts/Scraper.js @@ -81,10 +81,9 @@ export default class Scraper { * @param record */ saveFile(record) { - const deferredResponse = $.Deferred(); + //const deferredResponse = $.Deferred(); if (!('_attachments' in record)) { - deferredResponse.resolve(); - return deferredResponse.promise(); + return Promise.resolve(); } const downloads = record._attachments.map(async attachment => { @@ -104,12 +103,10 @@ export default class Scraper { return attachment; } }); - Promise.all(downloads).then(attachments => { record._attachments = attachments; - deferredResponse.resolve(); }); - return deferredResponse.promise(); + return Promise.resolve(); } // @TODO remove recursion and add an iterative way to run these jobs. @@ -161,7 +158,7 @@ export default class Scraper { }.bind(this) ); - $.whenCallSequentially(deferredDatamanipulations).done( + $.whenCallSequentially(deferredDatamanipulations).then( function () { this.resultWriter.writeDocs(scrapedRecords).then(() => { const now = new Date().getTime(); From c6abc701c76f06c96c8681f2ea2fed7158bd04b8 Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 30 Sep 2024 16:59:01 +0800 Subject: [PATCH 06/12] views changes to add Searchbar --- src/devtools/panel.css | 7 +++++++ src/devtools/views/ProjectList.html | 1 + src/devtools/views/ProjectListItem.html | 2 +- src/devtools/views/SitemapList.html | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/devtools/panel.css b/src/devtools/panel.css index 02cf403e..404f0119 100644 --- a/src/devtools/panel.css +++ b/src/devtools/panel.css @@ -182,3 +182,10 @@ select[size] { font-style: normal; font-weight: normal; } +.searchbar { + margin: 5px; + &::placeholder { + color: grey; + font-style: italic; + } +} diff --git a/src/devtools/views/ProjectList.html b/src/devtools/views/ProjectList.html index 680e6701..e1210ff7 100644 --- a/src/devtools/views/ProjectList.html +++ b/src/devtools/views/ProjectList.html @@ -1,4 +1,5 @@

+ diff --git a/src/devtools/views/ProjectListItem.html b/src/devtools/views/ProjectListItem.html index 3df96b6d..10b8b51d 100644 --- a/src/devtools/views/ProjectListItem.html +++ b/src/devtools/views/ProjectListItem.html @@ -1,4 +1,4 @@ - + diff --git a/src/devtools/views/SitemapList.html b/src/devtools/views/SitemapList.html index b8933f0c..b4764b8b 100644 --- a/src/devtools/views/SitemapList.html +++ b/src/devtools/views/SitemapList.html @@ -1,4 +1,5 @@
+
{{id}}{{title}}{{title}}
From f4bf345e00307b52008b2169cc9b1e496c11312f Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 30 Sep 2024 17:00:37 +0800 Subject: [PATCH 07/12] add logic for searchbar --- src/scripts/Controller.js | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index 44b0118b..efad8240 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -809,6 +809,8 @@ export default class SitemapController { }); $('#viewport').html($projectListPanel); Translator.translatePage(); + + this.initSearchbar('projects'); } getCurrentProjectId() { @@ -854,8 +856,53 @@ export default class SitemapController { $('#viewport').html($sitemapListPanel); Translator.translatePage(); } + this.initSearchbar('sitemaps'); } + initSearchbar(searchbarLocation) { + document.querySelector('.searchbar').addEventListener('input', event => { + let AllRows = []; + try { + if (searchbarLocation === 'sitemaps') { + AllRows = Array.from(document.querySelectorAll('td.id')).map( + td => td.parentElement + ); + AllRows.forEach(row => { + if ( + row + .querySelector('.id') + .innerText.toLowerCase() + .startsWith(event.target.value.toLowerCase()) + ) { + row.style.display = 'table-row'; + } else { + row.style.display = 'none'; + } + }); + } else if (searchbarLocation === 'projects') { + AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( + td => td.parentElement + ); + AllRows.forEach(row => { + if ( + row + .querySelector('td.projTitle') + .innerText.toLowerCase() + .startsWith(event.target.value.toLowerCase()) + ) { + row.style.display = 'table-row'; + } else { + row.style.display = 'none'; + } + }); + } else { + throw { message: "initSearchbar can't understand the type of table" }; + } + } catch (error) { + console.log(error.message); + } + }); + } getSitemapFromMetadataForm() { const metadata = {}; const $form = $('#viewport form'); From c18a3ccc9dd1e69b22189c01c843e0cc45d430b7 Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Mon, 30 Sep 2024 17:09:49 +0800 Subject: [PATCH 08/12] add messages for searchbar placeholder --- src/_locales/en/messages.json | 3 +++ src/_locales/ru/messages.json | 3 +++ src/scripts/Controller.js | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index b2da4b8c..027b977f 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -378,5 +378,8 @@ }, "popup_ws_version": { "message": "Web Scraper version: " + }, + "searchbar_placeholder_message": { + "message": "Search..." } } diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index cade54ff..065c917d 100644 --- a/src/_locales/ru/messages.json +++ b/src/_locales/ru/messages.json @@ -412,5 +412,8 @@ }, "popup_ws_version": { "message": "Версия Web Scraper: " + }, + "searchbar_placeholder_message": { + "message": "Поиск..." } } diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index efad8240..163fedcf 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -860,6 +860,9 @@ export default class SitemapController { } initSearchbar(searchbarLocation) { + document.querySelector('input.searchbar').placeholder = Translator.getTranslationByKey( + 'searchbar_placeholder_message' + ); document.querySelector('.searchbar').addEventListener('input', event => { let AllRows = []; try { From 758a2acea4173bb57e74412660b9d5516e587aae Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Tue, 22 Oct 2024 21:17:20 +0800 Subject: [PATCH 09/12] add better logic for searchbar based on regex. Also add highlight for matches --- src/devtools/panel.css | 4 ++ src/scripts/Controller.js | 78 +++++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/devtools/panel.css b/src/devtools/panel.css index 404f0119..19f0d174 100644 --- a/src/devtools/panel.css +++ b/src/devtools/panel.css @@ -189,3 +189,7 @@ select[size] { font-style: italic; } } +mark { + margin: 0; + padding: 0; +} diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index 163fedcf..254c6e46 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -865,44 +865,50 @@ export default class SitemapController { ); document.querySelector('.searchbar').addEventListener('input', event => { let AllRows = []; - try { - if (searchbarLocation === 'sitemaps') { - AllRows = Array.from(document.querySelectorAll('td.id')).map( - td => td.parentElement - ); - AllRows.forEach(row => { - if ( - row - .querySelector('.id') - .innerText.toLowerCase() - .startsWith(event.target.value.toLowerCase()) - ) { - row.style.display = 'table-row'; - } else { - row.style.display = 'none'; + const inputText = event.target.value.toLowerCase(); + if (searchbarLocation === 'sitemaps') { + AllRows = Array.from(document.querySelectorAll('td.id')).map( + td => td.parentElement + ); + AllRows.forEach(row => { + const rowText = row.querySelector('.id').innerText.toLowerCase(); + if (rowText.includes(inputText)) { + row.style.display = 'table-row'; + let regex = RegExp(inputText, 'gi'); + if (!inputText) { + regex = /$^/; // will never is valid } - }); - } else if (searchbarLocation === 'projects') { - AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( - td => td.parentElement - ); - AllRows.forEach(row => { - if ( - row - .querySelector('td.projTitle') - .innerText.toLowerCase() - .startsWith(event.target.value.toLowerCase()) - ) { - row.style.display = 'table-row'; - } else { - row.style.display = 'none'; + row.querySelector('td.id').innerHTML = rowText.replace(regex, match => { + return `${match}`; + }); + } else { + row.style.display = 'none'; + } + }); + } else if (searchbarLocation === 'projects') { + AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( + td => td.parentElement + ); + AllRows.forEach(row => { + const rowText = row.querySelector('td.projTitle').innerText; + if (rowText.toLowerCase().includes(inputText)) { + row.style.display = 'table-row'; + let regex = RegExp(inputText, 'gi'); + if (!inputText) { + regex = /$^/; // will never is valid } - }); - } else { - throw { message: "initSearchbar can't understand the type of table" }; - } - } catch (error) { - console.log(error.message); + row.querySelector('td.projTitle').innerHTML = rowText.replace( + regex, + match => { + return `${match}`; + } + ); + } else { + row.style.display = 'none'; + } + }); + } else { + throw { message: "initSearchbar can't understand the type of table" }; } }); } From 9b3913f144491e0a8e0fd4c62cf0eb961ad98eef Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Tue, 22 Oct 2024 21:28:00 +0800 Subject: [PATCH 10/12] edit placeholder message --- src/_locales/en/messages.json | 4 ++-- src/_locales/ru/messages.json | 4 ++-- src/scripts/Controller.js | 9 ++++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 027b977f..eabaca3a 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -379,7 +379,7 @@ "popup_ws_version": { "message": "Web Scraper version: " }, - "searchbar_placeholder_message": { - "message": "Search..." + "searchbar_placeholder_message_for_sitemaps": { + "message": "Sitemap id..." } } diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json index 065c917d..2670e6a8 100644 --- a/src/_locales/ru/messages.json +++ b/src/_locales/ru/messages.json @@ -413,7 +413,7 @@ "popup_ws_version": { "message": "Версия Web Scraper: " }, - "searchbar_placeholder_message": { - "message": "Поиск..." + "searchbar_placeholder_message_for_sitemaps": { + "message": "Id карты обхода..." } } diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index 254c6e46..d0fdf3d0 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -860,13 +860,13 @@ export default class SitemapController { } initSearchbar(searchbarLocation) { - document.querySelector('input.searchbar').placeholder = Translator.getTranslationByKey( - 'searchbar_placeholder_message' - ); document.querySelector('.searchbar').addEventListener('input', event => { let AllRows = []; const inputText = event.target.value.toLowerCase(); if (searchbarLocation === 'sitemaps') { + document.querySelector('input.searchbar').placeholder = + Translator.getTranslationByKey('searchbar_placeholder_message_for_sitemaps'); + AllRows = Array.from(document.querySelectorAll('td.id')).map( td => td.parentElement ); @@ -886,6 +886,9 @@ export default class SitemapController { } }); } else if (searchbarLocation === 'projects') { + document.querySelector('input.searchbar').placeholder = + Translator.getTranslationByKey('projectName') + '...'; + AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( td => td.parentElement ); From 48878ddbe1cb759ddf0bc0a31628b414d4660f23 Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Tue, 22 Oct 2024 21:38:33 +0800 Subject: [PATCH 11/12] placeholder fix --- src/scripts/Controller.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index d0fdf3d0..a7f7971c 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -811,6 +811,8 @@ export default class SitemapController { Translator.translatePage(); this.initSearchbar('projects'); + document.querySelector('input.searchbar').placeholder = + Translator.getTranslationByKey('projectName') + '...'; } getCurrentProjectId() { @@ -857,6 +859,9 @@ export default class SitemapController { Translator.translatePage(); } this.initSearchbar('sitemaps'); + document.querySelector('input.searchbar').placeholder = Translator.getTranslationByKey( + 'searchbar_placeholder_message_for_sitemaps' + ); } initSearchbar(searchbarLocation) { @@ -864,9 +869,6 @@ export default class SitemapController { let AllRows = []; const inputText = event.target.value.toLowerCase(); if (searchbarLocation === 'sitemaps') { - document.querySelector('input.searchbar').placeholder = - Translator.getTranslationByKey('searchbar_placeholder_message_for_sitemaps'); - AllRows = Array.from(document.querySelectorAll('td.id')).map( td => td.parentElement ); @@ -886,9 +888,6 @@ export default class SitemapController { } }); } else if (searchbarLocation === 'projects') { - document.querySelector('input.searchbar').placeholder = - Translator.getTranslationByKey('projectName') + '...'; - AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( td => td.parentElement ); From 8951d59c6ce918991c1fc1edc0347a12188de520 Mon Sep 17 00:00:00 2001 From: Alexander Vokin Date: Sat, 26 Oct 2024 22:30:59 +0800 Subject: [PATCH 12/12] refactor initSearchbar: remove bulky if-construction --- src/scripts/Controller.js | 66 ++++++++++++--------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/src/scripts/Controller.js b/src/scripts/Controller.js index a7f7971c..174e4388 100644 --- a/src/scripts/Controller.js +++ b/src/scripts/Controller.js @@ -810,7 +810,7 @@ export default class SitemapController { $('#viewport').html($projectListPanel); Translator.translatePage(); - this.initSearchbar('projects'); + this.initSearchbar('td.projTitle'); document.querySelector('input.searchbar').placeholder = Translator.getTranslationByKey('projectName') + '...'; } @@ -858,60 +858,34 @@ export default class SitemapController { $('#viewport').html($sitemapListPanel); Translator.translatePage(); } - this.initSearchbar('sitemaps'); + this.initSearchbar('td.id'); document.querySelector('input.searchbar').placeholder = Translator.getTranslationByKey( 'searchbar_placeholder_message_for_sitemaps' ); } - initSearchbar(searchbarLocation) { + initSearchbar(rowSelector) { document.querySelector('.searchbar').addEventListener('input', event => { let AllRows = []; const inputText = event.target.value.toLowerCase(); - if (searchbarLocation === 'sitemaps') { - AllRows = Array.from(document.querySelectorAll('td.id')).map( - td => td.parentElement - ); - AllRows.forEach(row => { - const rowText = row.querySelector('.id').innerText.toLowerCase(); - if (rowText.includes(inputText)) { - row.style.display = 'table-row'; - let regex = RegExp(inputText, 'gi'); - if (!inputText) { - regex = /$^/; // will never is valid - } - row.querySelector('td.id').innerHTML = rowText.replace(regex, match => { - return `${match}`; - }); - } else { - row.style.display = 'none'; - } - }); - } else if (searchbarLocation === 'projects') { - AllRows = Array.from(document.querySelectorAll('td.projTitle')).map( - td => td.parentElement - ); - AllRows.forEach(row => { - const rowText = row.querySelector('td.projTitle').innerText; - if (rowText.toLowerCase().includes(inputText)) { - row.style.display = 'table-row'; - let regex = RegExp(inputText, 'gi'); - if (!inputText) { - regex = /$^/; // will never is valid - } - row.querySelector('td.projTitle').innerHTML = rowText.replace( - regex, - match => { - return `${match}`; - } - ); - } else { - row.style.display = 'none'; + AllRows = Array.from(document.querySelectorAll(rowSelector)).map( + td => td.parentElement + ); + AllRows.forEach(row => { + const rowText = row.querySelector(rowSelector).innerText; + if (rowText.toLowerCase().includes(inputText)) { + row.style.display = 'table-row'; + let regex = RegExp(inputText, 'gi'); + if (!inputText) { + regex = /$^/; // will never is valid and returns [] } - }); - } else { - throw { message: "initSearchbar can't understand the type of table" }; - } + row.querySelector(rowSelector).innerHTML = rowText.replace(regex, match => { + return `${match}`; + }); + } else { + row.style.display = 'none'; + } + }); }); } getSitemapFromMetadataForm() {