Adiciona uma extensão MV3 (Firefox e Chromium/Brave) que insere CPF ou CNPJ
válido direto no campo focado, pelo menu de contexto de qualquer input,
textarea ou contenteditable.
Extensões rodam em sandbox sem acesso a processos, então não há como invocar
os binários cpfgen/cnpjgen; fazer isso exigiria um host de native messaging
registrado no SO. Como os algoritmos são curtos e puros, foram portados para
JS em extension/generator.js, a partir de main.go (CPF) e de
cnpj_generator/cnpj/generate.go (CNPJ), trocando math/rand por
crypto.getRandomValues. test_generator.mjs compara as duas implementações
para que não divirjam.
A inserção usa document.execCommand("insertText"), que emite os eventos
nativos e portanto funciona em campos controlados por React/Vue — atribuir
.value diretamente seria descartado por esses frameworks.
Somente desktop: o Firefox para Android não implementa a API menus.
Testes carregam a extensão de verdade nos dois navegadores e verificam que os
8 itens de menu são criados e que a inserção funciona nos três tipos de campo.
87 lines
2.3 KiB
JavaScript
87 lines
2.3 KiB
JavaScript
import {
|
|
generateCPF,
|
|
formatCPF,
|
|
generateCNPJ,
|
|
generateCNPJAlpha,
|
|
formatCNPJ,
|
|
} from "./generator.js";
|
|
|
|
// Firefox expõe `browser`, Chromium expõe `chrome`. As APIs usadas aqui são
|
|
// compatíveis nos dois, então basta escolher o objeto disponível.
|
|
const api = typeof browser !== "undefined" ? browser : chrome;
|
|
|
|
const MENU_ITEMS = [
|
|
{ id: "cpf-formatted", parentId: "cpf", title: "Formatado (000.000.000-00)" },
|
|
{ id: "cpf-raw", parentId: "cpf", title: "Só números" },
|
|
{
|
|
id: "cnpj-formatted",
|
|
parentId: "cnpj",
|
|
title: "Formatado (00.000.000/0000-00)",
|
|
},
|
|
{ id: "cnpj-raw", parentId: "cnpj", title: "Só números" },
|
|
{ id: "cnpj-alpha-formatted", parentId: "cnpj", title: "Alfanumérico" },
|
|
{
|
|
id: "cnpj-alpha-raw",
|
|
parentId: "cnpj",
|
|
title: "Alfanumérico, só números",
|
|
},
|
|
];
|
|
|
|
function buildMenus() {
|
|
api.contextMenus.removeAll(() => {
|
|
// contexts: "editable" faz o menu aparecer apenas em input, textarea e
|
|
// elementos contenteditable — nunca no resto da página.
|
|
api.contextMenus.create({
|
|
id: "cpf",
|
|
title: "Gerar CPF",
|
|
contexts: ["editable"],
|
|
});
|
|
api.contextMenus.create({
|
|
id: "cnpj",
|
|
title: "Gerar CNPJ",
|
|
contexts: ["editable"],
|
|
});
|
|
|
|
for (const item of MENU_ITEMS) {
|
|
api.contextMenus.create({ ...item, contexts: ["editable"] });
|
|
}
|
|
});
|
|
}
|
|
|
|
api.runtime.onInstalled.addListener(buildMenus);
|
|
api.runtime.onStartup.addListener(buildMenus);
|
|
|
|
function valueFor(menuItemId) {
|
|
switch (menuItemId) {
|
|
case "cpf-formatted":
|
|
return formatCPF(generateCPF());
|
|
case "cpf-raw":
|
|
return generateCPF();
|
|
case "cnpj-formatted":
|
|
return formatCNPJ(generateCNPJ());
|
|
case "cnpj-raw":
|
|
return generateCNPJ();
|
|
case "cnpj-alpha-formatted":
|
|
return formatCNPJ(generateCNPJAlpha());
|
|
case "cnpj-alpha-raw":
|
|
return generateCNPJAlpha();
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
api.contextMenus.onClicked.addListener((info, tab) => {
|
|
const value = valueFor(info.menuItemId);
|
|
if (value === null || !tab?.id) return;
|
|
|
|
api.scripting.executeScript({
|
|
target: { tabId: tab.id, frameIds: [info.frameId ?? 0] },
|
|
files: ["insert.js"],
|
|
});
|
|
|
|
api.scripting.executeScript({
|
|
target: { tabId: tab.id, frameIds: [info.frameId ?? 0] },
|
|
func: (text) => insertIntoFocused(text),
|
|
args: [value],
|
|
});
|
|
});
|