Como me livrei de mil abas ...

... e estava 3 anos atrasado. Idealmente, deve ser assim: o usuário inicia o navegador e mostra o que o usuário precisa. Mas, embora isso não seja implementado, você deve usar os mecanismos de pesquisa. Idealmente, deve ser assim: o usuário abre um mecanismo de pesquisa, entra em uma consulta de pesquisa e mostra o que o usuário precisa. Porém, embora o botão "Sinto-me com sorte" não funcione tão bem (embora ultimamente tenha havido um movimento perceptível nessa direção), às vezes você precisa acessar vários endereços da página de resultados da pesquisa.

Aparentemente, o cenário de utilização de mecanismos de busca foi corrigido historicamente (quando a Internet estava lenta): ao acessar a página de resultados da pesquisa, abri várias guias em segundo plano e, enquanto o restante estava carregando, já era possível ler a primeira guia. No caso em que encontrei as informações necessárias em uma das guias, o restante precisou ser fechado manualmente. Se não fechasse imediatamente, as guias permaneceriam suspensas, aumentando o número de guias abertas no navegador, que, em regra, raramente eram fechadas depois disso.

Além disso, se você clicar na página com os links que abrem em uma nova janela, várias guias (logicamente) serão criadas. Quando você encontra as informações necessárias, nem sempre consegue lembrar quais guias estão conectadas, não pode fechar tudo, o que também leva ao aumento do número de guias abertas.

Eu sempre precisei do botão "Encontrado" , que limparia depois de mim as consequências da pesquisa (vamos chamá-lo de "tive sorte" ). Depois de mergulhar no mundo das extensões de navegador, pensei que era algo que poderia ajudar nesse caso. Tão vagamente começou a aparecer o desejo de escrever uma extensão que resolvesse meus problemas.

Vou contar minha história, vou liderar a história em ordem cronológica, as conclusões podem ser inesperadas.

Primeiro passo em direção a


A primeira coisa que fiz foi configurar a infraestrutura: webpack + babel . E imediatamente não gostei desse código duplicado da babel para seus auxiliares em cada módulo. Era possível configurá-lo para usar o objeto babelHelper, mas o arquivo de código babelHelperprecisava ser conectado na configuração do webpack . Manter esse arquivo no projeto e apontá-lo entryera feio, criei um plug-in para o webpack que fazia isso automaticamente para mim. Depois de gastar muito esforço no primeiro passo e escrever mais um código para a extensão em si, diminuí a velocidade.

Plugar

Fundação


O tempo passou e apenas um plug-in para o webpack estava disponível, o que não resolveu meus problemas de forma alguma. E toda vez que eu procurava algo e não fechava as guias, havia um pensamento: “Seria bom concluir essa extensão ...” O desejo cresceu e cresceu, e agora, em um belo dia, a quantidade cresceu em qualidade.

É hora de dizer qual era a idéia principal: o
usuário acessa a página de resultados da pesquisa - SICKLE , analisamos os resultados da pesquisa, salvamos os endereços do link para nós mesmos, depois que o usuário clicou em um dos endereços, mostra uma notificação com os outros endereços e o botão "Encontrado" para fechar guias.

Quando você vai para a página, pode haver várias opções. O mais simples: um pedido - uma resposta do servidor ( 200) O mais difícil: uma solicitação - vários redirecionamentos de servidor ( 3xx ), após o qual o cliente redireciona (usando <meta/>ou javascript), a API de histórico também está no topo . E as combinações entre eles, como regra, a maioria dos sites se enquadram nessa categoria.

Caso de transição simples:

O caso de uma transição simples (resposta 200)

Caso de transição complexo:

Caso de transição complexo (redirecionamentos de cliente 3xx +)

Ou seja, salvar o endereço da página e verificar apenas ele nem sempre é suficiente. Portanto, você precisa criar uma transição lógica, onde anote todos os endereços encontrados no caminho e verifique se a transição lógica contém o endereço armazenado. A tarefa é clara, mas nem tudo é tão direto na execução.

No Chrome, existem duas APIs relacionadas à navegação: webNavigation e webRequest - cada uma com seus próprios eventos. O primeiro - conecta as transições e a interface do usuário do navegador, o último - as solicitações de rede subjacentes. Portanto, se a alteração de endereço na página ocorreu devido à API do histórico, não haverá eventos para o último e, se ocorrerem redirecionamentos durante uma solicitação de rede, o primeiro não o reportará. Portanto, é necessário usar as duas APIs, coletando uma pitada de cada evento de cada API, para formar uma transição lógica.

Alguns detalhes
, webNavigation (wN) :

onBeforeNavigate -> onCommitted -> onDOMContentLoaded -> onCompleted

webRequest (wR):

onBeforeRequest -> [onBeforeRedirect -> onBeforeRequest]* -> onCompleted | onErrorOccurred

wR wN ( ), .. - wN.onBeforeNavigate wR.onBeforeRequest, - . .

, , .

Desenvolvimento


... Voltemos ao momento em que a quantidade cresceu em qualidade. Uma quantidade significativa de tempo passou desde o início do desenvolvimento até este ponto: os navegadores começaram a suportar os módulos es6 , o DOM sombra e outros recursos modernos. Para construir o projeto, mudei para o Rollup , desta vez não precisei escrever um plugin. Depois de criar a base - a capacidade de obter informações sobre qualquer transição em qualquer guia, resta implementar a lógica de analisar os SICKLES suportados e exibir notificações nas páginas relacionadas.

A primeira tarefa é bastante primitiva: conhecemos o endereço do SICKLE, acessamos o conteúdo da página usando o script content, obtemos os dados nos quais estamos interessados, salve-os, aguarde o usuário ir a uma das páginas para mostrar uma notificação com as outras páginas.

Para a segunda tarefa, você precisa implementar a notificação em si, o que mostrar ao usuário na página. E aqui também os scripts de conteúdo não podem funcionar.

Inicialmente, havia apenas um manipulador (também conhecido como controlador) responsável pela lógica durante a interação do usuário com os mecanismos de pesquisa. Então surgiu a ideia: por que não mostrar notificações nas guias relacionadas quando o usuário simplesmente clica nos links abertos em novas guias? Eu tive que refazer a lógica, tornando-a mais universal. Semelhante ao middleware React / Redux, você pode conectar vários manipuladores de transição, o que no futuro permitirá implementar a capacidade de desativar / ativar vários manipuladores nas configurações de extensão.

Privacidade


Como a notificação é o painel na parte inferior da tela e é adicionada ao layout da página, o script na página pode acessar esse elemento, bem como qualquer outro elemento nesta página. Ou seja, teoricamente, a página poderia descobrir qual consulta de pesquisa você usou, em qual mecanismo de pesquisa e quais outras páginas foram oferecidas, o que não é muito bom.

Uma tecnologia chamada shadow DOM vem em socorro . Não é recomendável usá-lo closed modena Web ao criá-lo shadowRoot, porque não faz muito sentido (você ainda precisa armazenar o link do elemento em shadowRootalgum lugar se quiser ter acesso a ele programaticamente; também é possível redefinir a função attachShadowpara criarshadowRootno modo aberto, e os scripts carregados após a redefinição já usarão a nova versão da função).

No caso de expansão, não é assim. Os scripts de conteúdo e de página vivem em mundos paralelos. Os scripts da página não têm acesso aos objetos definidos nos scripts de conteúdo, enquanto os scripts de conteúdo operam com a implementação nativa das funções DOM dos objetos (uma função substituída por um script da página não afeta a função com a qual o script de conteúdo funciona). Combinando essas duas condições, vemos que é possível criar um elemento com um privado shadowRootarmazenando o link para ele em uma variável.

Nesse caso, o script da página poderá acessar apenas o elemento wrapper, que ficará vazio para ele. Ele não poderá receber o texto da solicitação ou as páginas propostas. Deve-se tomar cuidado para não fornecer um link para qualquer elemento dentro da notificação ou texto sem formatação nos eventos gerados. Portanto, na extensão, o ID gerado é usado em eventos, e o script em segundo plano já entende o que é exigido por esse ID. Para a página, esse ID não tem sentido.

Dificuldades de tradução


Inicialmente, a extensão foi desenvolvida apenas para o Google Chrome , mas desde a API WebExtensions , em algum lugar na minha cabeça, mantive a capacidade de portar para outros navegadores. E a presença de webextension-polyfill inspirou confiança. Mas não importa como. O polifil dessa extensão trouxe apenas a capacidade de usar a API do Chrome com promessas.

O Firefox se tornou uma decepção do ano. A incompatibilidade da API do chrome no Firefox ( Bug 1543647 , Bug 1595621 ) acabou sendo crítica para a extensão funcionar, podemos dizer que ela não funciona neste navegador (conforme o esperado).

Vivaldi era o mais próximo, mas também não sem custo. EventowN.onCreatedNavigationTargetIsso não ocorre quando o usuário abre o link com o botão do meio do mouse ou através do botão Shift|Ctrl+ esquerdo do mouse, em vez do evento wN.onCommitted transitionType == 'start_page', que não está na API do chrome , por isso, nem sempre a extensão funciona corretamente. Também em Vivaldi não funcionam teclas de atalho para extensões. O que é um recurso matador, neste caso, no Chrome, permite navegar rapidamente pelas guias e fechá-las, sem a necessidade de usar um mouse para isso.

Conclusão


Durante a gravação do código, a lógica para exibir notificações mudou várias vezes, simplificando cada vez. Como resultado, verificou-se que era possível não cercar o jardim com transições lógicas, mas capturar as "transições relacionadas" do usuário (no caso de wN.onCommittedhaver uma bandeira transitionTypeque indique para que serve a transição, em muitos casos, é "link", o que significa que o usuário mudou por referência), o que simplificaria bastante o código e funcionaria em muitos casos, mas não em todos.

Além disso, não estando no assunto, esperava mais compatibilidade em termos da API webExtensions. Como sempre, é bom viver em um mundo de navegadores modernos quando você não precisa de suporte para versões mais antigas. As animações CSS são uma coisa maravilhosa: o que você costumava usar na biblioteca js agora é feito em algumas linhas em css. Os elementos personalizados não funcionam em extensões, mas o DOM sombra funciona, permitindo que você aproveite todos os seus recursos.

Expansão
chrome web store: Handy Search

Source: https://habr.com/ru/post/undefined/


All Articles