Skip to content

Text Replacer example#612

Closed
dotproto wants to merge 3 commits into
mainfrom
text-replacer
Closed

Text Replacer example#612
dotproto wants to merge 3 commits into
mainfrom
text-replacer

Conversation

@dotproto

Copy link
Copy Markdown
Contributor

Adds a sample extension called "Text Replacer." As the name implies, this extension will replace a string in the page with a custom string. Currently supports 5 replacements.

Comment thread examples/text-replacer/content.js
Comment thread examples/text-replacer/content.js
</div>
</form>

<script src="popup.js"></script>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use type="module"? Then you can use top-level await in the code, rather than the awkward loading and call to loadFormData.

});
});

document.getElementById('clear').addEventListener('click', (event) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get rid of this and change the <button> to be an <input type="reset" />.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've replaced the button with <input type="reset">, but still need an event listener in order to persist the changes.

Addressed in #1718.

const inputs = form.querySelectorAll('input[type=text]');

const patterns = [...inputs].reduce((acc, input, index) => {
const outerIndex = index >> 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do a real division and round it. Sorry, but we should be clear to novices.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #1718.

// https://developers.google.com/open-source/licenses/bsd

// Replace text on the page using a static list of patterns
function textReplacer(replacements) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having this method is a bit confusing. I'd just move its two lines into the callback for the fetcher, and expand the comment:

// Get the patterns to replace from storage, then build a regex from them and replace all text on the page.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #1718.

Comment on lines +7 to +9
chrome.runtime.onInstalled.addListener(() => {
registerContextMenus();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During extension update, will this cause an error by trying to re-register context menu items?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it would. I think I wrote it this way originally because I considered updates to be out of scope. I've updated the code as suggested in order to better set the reader up for success.

Addressed in #1718.

}

chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId == 'replace-text-menuitem') {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract "replace-text-menuitem" into a constant

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #1718.

chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId == 'replace-text-menuitem') {
replaceText(tab.id);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd normally recommend throwing an assert in here, since this is the only id we ever expect. Similarly for commands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added explicit errors for unknown commands and context menus.

Addressed in #1718.


function buildReplacementRegex(source) {
const output = [];
for (var i = 0; i < source.length; i++) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (var i = 0; i < source.length; i++) {
for (let i = 0; i < source.length; i++) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #1718.

Comment thread examples/text-replacer/content.js
function replaceText(replacements) {
let node;
const nodeIterator = document.createNodeIterator(document.body, NodeFilter.SHOW_TEXT);
while (node = nodeIterator.nextNode()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we declare node here? We only need it in the body

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Unlike for-in statements, which may contain declarations, while statements require an expression in the condition position. We also can't use for-in here because the NodeIterator interface predates JavaScript's iteration protocol. The closest we can do is move the let declaration next to the while to make their relationship more clear. I've applied this change to my new PR.

Addressed in #1718.

Comment on lines +45 to +47
chrome.storage.sync.get(['patterns'], function(data) {
textReplacer(data.patterns);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to be gradually encouraging developers to avoid storage access by content scripts unless crucial. WDYT about changing this to a message to the background page? (I don't feel strongly)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the example to route all read/writes through the background context.

Addressed in #1718.

},
"commands": {
"replace-text": {
"description": "Replace text on the current page."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need a default keybinding?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking, no, a default keybinding is not required. The user could still manually assign a key binding if they wanted to use it.

For the sake of clarity, I've updated the demo to have a default keyboard shortcut.

Addressed in #1718.

Comment thread examples/text-replacer/manifest.json
@Linetkhgt

Copy link
Copy Markdown

README.md

@nagayev

nagayev commented Jan 29, 2022

Copy link
Copy Markdown

+1
It was useful for me.

@patrickkettner

Copy link
Copy Markdown
Collaborator

@sebastianbenz @oliverdunk what should we do with these older PRs?

@patrickkettner

Copy link
Copy Markdown
Collaborator

@dotproto, since we still dont have a textreplacer sample, any chance youd like to update this to get it merged?

@dotproto dotproto mentioned this pull request Jul 19, 2026
dotproto added a commit to dotproto/chrome-extensions-samples that referenced this pull request Jul 19, 2026
@dotproto

Copy link
Copy Markdown
Contributor Author

I'm no longer able to edit the text-replacer brach, so this PR has been replaced by #1718.

dotproto added a commit to dotproto/chrome-extensions-samples that referenced this pull request Jul 19, 2026
@dotproto dotproto closed this Jul 19, 2026
patrickkettner pushed a commit that referenced this pull request Jul 20, 2026
* Text Replacer example

* Addressing feedback from PR #612

* Fix issues identified in #1718 review

* Add more icon options to the manifest

* Add README

* Update copyright and license headers

* Iterating on feedback in #1718

* Simplify regex creation logic

* Fix ESLint errors and warnings
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants