Skip to content

Commit e84d413

Browse files
authored
Dismissable hints (#105)
1 parent 96ac138 commit e84d413

11 files changed

Lines changed: 94 additions & 32 deletions

File tree

assets/popup.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<meta charset="UTF-8" />
55
<link href="bootstrap.min.css" rel="stylesheet" />
6+
<script src="bootstrap.min.js"></script>
67
<style>
78
html {
89
height: fit-content;

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"permissions": ["activeTab", "storage", "notifications"],
3232
"host_permissions": ["http://*/*", "https://*/*"],
3333
"update_url": "http://clients2.google.com/service/update2/crx",
34-
"version":"2.0.3",
34+
"version":"2.0.4",
3535
"options_page": "assets/options.html",
3636
"icons": {
3737
"16": "assets/icon-16.png",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "search_and_replace",
3-
"version": "2.0.3",
3+
"version": "2.0.4",
44
"resolutions": {
55
"author": "Chris Taylor <cjtaylor38@gmail.com>"
66
},

src/background/admin.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
HintPreferences,
23
SavedInstances,
34
SavedSearchReplaceInstance,
45
SearchReplaceBackgroundMessage,
@@ -11,14 +12,16 @@ import { getInstanceId } from '../util'
1112
async function saveStorage(
1213
instance: SearchReplaceInstance,
1314
history: SearchReplaceInstance[],
14-
savedInstances: SavedInstances
15+
savedInstances: SavedInstances,
16+
hintPreferences?: HintPreferences
1517
) {
1618
// always store the instance and history
1719
const newStorage: SearchReplacePopupStorage = {
1820
storage: {
1921
instance,
2022
history,
2123
saved: savedInstances,
24+
hintPreferences,
2225
},
2326
}
2427
await chrome.storage.local.set(newStorage)
@@ -43,14 +46,15 @@ export async function setupStorage(msg: SearchReplaceBackgroundMessage) {
4346
//console.log('BACKGROUND: history is: ', history)
4447
const url = msg.url
4548
const savedInstances: SavedInstances = storage.saved || {}
49+
const hintPreferences = { ...(storage.hintPreferences || {}), ...(msg.storage?.hintPreferences || {}) }
4650
//console.log('BACKGROUND: SavedInstances is: ', savedInstances)
47-
return { instance, history, url, savedInstances, storage }
51+
return { instance, history, url, savedInstances, storage, hintPreferences }
4852
}
4953

5054
export async function listenerAdmin(msg: SearchReplaceBackgroundMessage, port: chrome.runtime.Port) {
5155
if (msg.action) {
5256
const storage = await setupStorage(msg)
53-
const { instance, history, url } = storage
57+
const { instance, history, url, hintPreferences } = storage
5458
const savedInstances = storage.savedInstances
5559

5660
if (msg.action === 'recover') {
@@ -91,7 +95,7 @@ export async function listenerAdmin(msg: SearchReplaceBackgroundMessage, port: c
9195
await saveStorage(instance, history, savedInstances)
9296
} else if (msg.action === 'store') {
9397
// Store the instance and history in the storage
94-
await saveStorage(instance, history, savedInstances)
98+
await saveStorage(instance, history, savedInstances, hintPreferences)
9599
}
96100
}
97101
}

src/background/content.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SearchReplaceResponse } from '../types'
1+
import { HintPreferences, SearchReplaceResponse, SearchReplaceStorageItems } from '../types'
22
import { getAllStorageKeys } from './storage'
33
import { getExtensionStorage, getInstanceId, mergeSearchReplaceResponse } from '../util'
44

@@ -79,12 +79,15 @@ async function checkPreviousResponse(msg: SearchReplaceResponse) {
7979

8080
// merge the responses if there are iframeResults
8181
if (iframeResults) {
82+
const hintPreferences: HintPreferences =
83+
(await getExtensionStorage<SearchReplaceStorageItems>('storage'))?.hintPreferences || {}
8284
for (const iframeResult of iframeResults) {
83-
mergedResult = mergeSearchReplaceResponse(mergedResult, iframeResult)
85+
mergedResult = mergeSearchReplaceResponse(mergedResult, iframeResult, hintPreferences)
8486
}
8587
// if the total number in msg.backGroundReceived is equal to the number of iframes then we're good,
8688
// send the response to the popup.
8789
if (mergedResult.backgroundReceived === mergedResult.iframes) {
90+
console.log('Sending merged result to popup', JSON.stringify(mergedResult, null, 4))
8891
await chrome.runtime.sendMessage(mergedResult)
8992
await removeSearchReplaceResponses(`savedResponse-${msg.instance.instanceId}`)
9093
}

src/constants.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
import { Hint } from './types'
2+
13
export const ELEMENT_FILTER = /(HTML|HEAD|SCRIPT|STYLE|IFRAME)/i
24
export const INPUT_TEXTAREA_FILTER = /(INPUT|TEXTAREA)/
3-
export const GMAIL_APPLICATION_NAME = 'Gmail'
4-
export const GOOGLE_MAIL_DOMAIN = 'mail.google.com'
5-
6-
export const HINTS = {
7-
gmail: 'Hint: Gmail detected. Check "Visible content only?" when editing draft emails.',
5+
export const HINTS: Record<string, Hint> = {
6+
gmail: {
7+
hint: 'Hint: Gmail detected. Check "Visible content only?" when editing draft emails.',
8+
domain: 'mail.google.com',
9+
selector: `meta[content="Gmail"]`,
10+
name: 'gmail',
11+
},
12+
amazon_seller: {
13+
hint: 'Hint: Amazon Seller Central detected. Check "Hidden content?" and "Input fields only?" when editing listings.',
14+
domain: 'sellercentral.amazon',
15+
selector: '*[product="SellOnAmazon"]',
16+
name: 'amazon_seller',
17+
},
818
}

src/hints.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import { GMAIL_APPLICATION_NAME, GOOGLE_MAIL_DOMAIN, HINTS } from './constants'
2-
import { inIframe } from './elements'
1+
import { HINTS } from './constants'
2+
import { Hint } from './types'
33

4-
export function getHints(document: Document): string[] {
5-
const hints: string[] = []
6-
// check if meta tag application-name is Gmail
7-
if (!inIframe()) {
8-
const meta = document.querySelector(`meta[content=${GMAIL_APPLICATION_NAME}]`)
9-
if (window.location.href.indexOf(GOOGLE_MAIL_DOMAIN) > -1 || meta) {
10-
hints.push(HINTS.gmail)
4+
export function getHints(document: Document): Hint[] {
5+
const hints: Hint[] = []
6+
for (const [hintType, { domain, selector }] of Object.entries(HINTS)) {
7+
const hasSelector = document.querySelector(selector)
8+
if (window.location.href.indexOf(domain) > -1 || hasSelector) {
9+
hints.push(HINTS[hintType])
1110
}
1211
}
1312
return hints

src/popup.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
SEARCH_TERM_INPUT_ID,
77
} from './popup/constants'
88
import {
9+
Hint,
10+
HintPreferences,
911
SearchReplaceActions,
1012
SearchReplaceBackgroundMessage,
1113
SearchReplaceContentMessage,
@@ -268,15 +270,32 @@ function setCount(result: SearchReplaceResult, translationFn: TranslationProxy)
268270
}
269271
}
270272

271-
function setHints(hints?: string[]) {
273+
function setHints(hints?: Hint[]) {
272274
const hintsElement = document.getElementById('hints')
273275
if (hintsElement) {
274276
hintsElement.innerHTML = ''
275277
if (hints) {
278+
console.log('Hints', hints)
276279
for (const hint of hints) {
280+
console.log('hint', hint)
281+
// check that this hint has not been previously dismissed by reading the local storage
282+
277283
const hintElement = document.createElement('div')
278-
hintElement.innerText = hint
279-
hintElement.className = 'hint alert alert-info'
284+
hintElement.innerText = hint.hint
285+
hintElement.setAttribute('role', 'alert')
286+
const dismissButton = document.createElement('button')
287+
dismissButton.className = 'btn-close'
288+
dismissButton.setAttribute('data-bs-dismiss', 'alert')
289+
dismissButton.setAttribute('aria-label', 'Close')
290+
dismissButton.setAttribute('type', 'button')
291+
hintElement.appendChild(dismissButton)
292+
dismissButton.onclick = function () {
293+
const searchReplaceInput = getInputValues(false)
294+
const history = constructSearchReplaceHistory()
295+
const hintPreferences: HintPreferences = { [hint.name]: true }
296+
sendToStorage(searchReplaceInput, history, hintPreferences)
297+
}
298+
hintElement.className = 'hint alert alert-info alert-dismissible'
280299
hintsElement.appendChild(hintElement)
281300
}
282301
}
@@ -310,14 +329,15 @@ async function storeTerms(
310329
// This counts the terms on the page
311330
const url = await contentScriptCall('count', searchReplaceInput, history)
312331
// This sends the search replace terms to the background page and stores them
313-
sendToStorage(searchReplaceInput, history, url, save)
332+
sendToStorage(searchReplaceInput, history, {}, url, save)
314333
}
315334
}
316335
}
317336

318337
function sendToStorage(
319338
searchReplaceInstance: SearchReplaceInstance,
320339
history: SearchReplaceInstance[],
340+
hintPreferences?: HintPreferences,
321341
url?: string,
322342
save?: boolean
323343
) {
@@ -329,6 +349,7 @@ function sendToStorage(
329349
storage: {
330350
instance: searchReplaceInstance,
331351
history,
352+
hintPreferences,
332353
},
333354
action: 'store',
334355
url,

src/searchreplace.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,6 @@ function replaceInner(
418418
if (!config.hiddenContent) {
419419
inputs = inputs.filter((input) => elementIsVisible(input, true, false))
420420
}
421-
console.log('Found inputs', inputs)
422421

423422
const inputResult = replaceInInputs(config, document, inputs, searchReplaceResult, elementsChecked)
424423

@@ -446,7 +445,6 @@ function replaceInInputs(
446445
} else {
447446
const oldValue = getValue(input, config)
448447
const occurrences = oldValue.match(config.globalSearchPattern)
449-
console.log('oldValue', oldValue, 'occurrences', occurrences)
450448
if (occurrences) {
451449
searchReplaceResult.count.original = Number(searchReplaceResult.count.original) + occurrences.length
452450
if (config.replace) {
@@ -565,7 +563,6 @@ function replaceInHTML(
565563
clonedElement = clonedElementRemoved as HTMLElement
566564
ignoredElements = new Set([...ignoredElements, ...removedSet])
567565
}
568-
console.log('Ignored elements', ignoredElements)
569566

570567
// replace inner texts first, dropping out if we have done a replacement and are not working globally
571568
const innerResult = replaceInner(
@@ -734,6 +731,7 @@ if (chrome && chrome.runtime && chrome.runtime.onMessage) {
734731
}
735732

736733
// Send the response to the background script for processing
734+
console.log('sending response to background script')
737735
chrome.runtime.sendMessage(response).then((r) => {
738736
sendResponse({
739737
action: 'searchReplaceResponsePopup',

src/types/types.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export type SearchReplaceStorageItems = {
3333
history: SearchReplaceInstance[]
3434
instance: SearchReplaceInstance
3535
saved?: SavedInstances
36+
hintPreferences?: HintPreferences
3637
}
3738

3839
export type SearchReplacePopupStorage = {
@@ -125,10 +126,21 @@ export interface LangFile {
125126
}
126127
}
127128

129+
export type Hint = {
130+
hint: string
131+
domain: string
132+
selector: string
133+
name: string
134+
}
135+
136+
export type HintPreferences = {
137+
[key: string]: boolean
138+
}
139+
128140
export interface SearchReplaceResponse {
129141
instance: SearchReplaceInstance
130142
inIframe: boolean
131-
hints?: string[]
143+
hints?: Hint[]
132144
location: string
133145
result: SearchReplaceResult
134146
action: SearchReplaceActions

0 commit comments

Comments
 (0)