Muitos dizem que reinventar a roda é inútil, por demandar esforço para criar algo que já existe e que muitos já conhecem e usam.
Entretanto, antes do primeiro “inventor” criar a roda, de fato, a qualidade de vida era inferior e ninguém mais imaginou construir aquilo.
E se para o primeiro inventor o esforço foi grande e reconhecido, por que para os seguintes não? Sendo que o esforço é o mesmo.
É nessa filosofia de realizar o mesmo trabalho que o criador original de determinado recurso que pretendo mostrar como reinventar uma coisa muito utilizada nos navegadores Web atualmente, mas que antes de existir, o trabalho era excessivo e frustrante: o Ctrl + F (buscar, pesquisar, encontrar na página, etc).
– O Ctrl + F? Mas ele já existe!
Existe mesmo! Mas antes de existir, ninguém além de seu inventor imaginava como fazê-lo. Por isso, fazer uma versão dele, mesmo já existindo, pode comparar o seu esforço e habilidade com o de quem fez pela primeira vez, além de ser um bom aprendizado de como recriá-lo e até modificá-lo.
Para criarmos uma simulação desse método de encontrar determinados trechos de texto no documento HTML com todos os seus efeitos a que estamos acostumados no Chrome, no Internet Explorer e em outros navegadores Web, podemos utilizar o projeto implementado no GitHub para esse fim: o FindTextInDocument.
Em um documento HTML começamos inserindo a estrutura da ferramenta onde vamos inserir os textos a serem procurados, o que vai iniciar uma nova busca a cada modificação nos termos, e selecionar a opção de realçar o próximo resultado ou o anterior, aqui implementado de forma a incrementar ou decrementar da lista de resultados encontrados.
<div class="find-in-document-container">
<input type="text" id="txt-to-find" value="" oninput="findInDocument({position: 0})"/>
<input type="button" value="Prev" onclick="findInDocument({position: -1})"/>
<input type="button" value="Next" onclick="findInDocument({position: 1})"/>
</div>
Para termos uma apresentação funcional e bacana da ferramenta, precisamos adicionar a classe CSS que envolverá os estilos da nossa estrutura de busca da ferramenta e a classe que irá aplicar o highlight nos trechos de texto encontrados no documento.
.find-in-document-container{
background-color: #FFF;
box-shadow: 2px 2px 5px 2px #ccc;
padding: 5px;
position: fixed;
right: 0;
width: auto;
z-index: 9999;
}
.txtFoundInSearch{
background-color: #ff0;
}
Antes de desenvolvermos o código JavaScript das funcionalidades da ferramenta, vamos importar a biblioteca jQuery que ajuda em um dos principais recursos da nossa aplicação.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Aqui, é importada uma versão superior da qual um importante método da ferramenta foi implantado, mas por tanta flexibilidade e diferentes usos, outra versão que suporte a funcionalidade que teremos a frente pode ser utilizada sem problemas.
Agora, partindo para o funcionamento de fato do nosso recurso, vamos declarar uma variável que armazenará a posição do texto realçado da lista de todos os termos encontrados e navegados, e uma constante que guardará o nome da classe que definimos para realçar esses termos.
let foundTxtPosition = 0;
const classTxtFoundInSearch = 'txtFoundInSearch';
Logo, após essas variáveis, está na hora de definirmos a função principal da ferramenta que encontrará todos os trechos na página HTML que contenham os termos que procuramos e realçar o da posição que desejarmos.
const findInDocument = (positionSelection) => {
const positionToFind = positionSelection.position;
let txt = document.querySelector('#txt-to-find').value;
const cleanFind = () => {
$("*").removeClass(classTxtFoundInSearch);
}
if(txt.trim() == ""){
cleanFind();
return;
}
let $txtElement = $(`p:contains('${txt}'), span:contains('${txt}')`);
foundTxtPosition = foundTxtPosition + (positionToFind);
if(foundTxtPosition == 0 || !$txtElement.length || $txtElement[foundTxtPosition - 1] >= $txtElement.length){
cleanFind();
}
$txtElement = $txtElement[foundTxtPosition];
if(typeof($txtElement) === "undefined"){
foundTxtPosition = foundTxtPosition - (positionToFind);
}else{
cleanFind();
$($txtElement).addClass(classTxtFoundInSearch);
if($($txtElement).length){
let txtElementTopPosition = $($txtElement).offset().top;
window.scrollTo(0, txtElementTopPosition);
}
}
}
Sempre que for acionada ao ter o texto modificado no campo de pesquisa ou clicados os botões de alternar o realce da posição do trecho encontrado, essa função se manterá atualizada com o atual texto na caixa de pesquisa e receberá como parâmetro a posição do termo ao ser realçado na lista de termos encontrados.
Os passos dessa função são então definidos como:
- Definir a função que limpará a classe CSS que gera o efeito de highlight de todos os elementos da página;
- Verificar se o campo de pesquisa não está vazio, e se estiver, limpar os últimos highlights encontrados e retornar finalizando sua execução;
- Pesquisar todos os elementos de texto, tags p e span, que contenham o texto buscado no campo de pesquisa.
Nesse trecho está a importante funcionalidade da biblioteca jQuery que comentamos: o pseudo-seletor contains. Não há funções nativas na linguagem JavaScript atualmente que nos proporcionem essa busca de elementos que contenham determinado texto dentro de suas tags, e sem utilizar essa biblioteca, teria que ser montado um método para buscar todas as tags do documento e em uma estrutura de repetição verificar o conteúdo texto dentro do HTML de cada uma delas e comparar com o texto desejado pelo usuário, perdendo um pouco o nosso foco da abordagem principal.
- Após selecionar os termos, precisamos atualizar a ultima posição encontrada, somando com o valor positivo ou negativo passado como parâmetro da função para ordenar a seleção
- Verificar se essa posição é válida, não sendo o reinício da busca ou um valor que seja maior do que o número total de termos encontrados, e se for, limpar todos os highlights
- Selecionar o termo da posição desejada na lista de termos encontrados
- Verificar se realmente há valor nesses resultados e nessa posição selecionada. Se não houver, retroceder a variável de posição desejada para o último valor com termo encontrado
- Se houver valor na verificação do termo encontrado, as próximas etapas serão limpar os highlights nos últimos termos encontrados e então adicioná-los aos novos, para manter um efeito de atualização, e se esse elemento HTML que deve conter o termo encontrado tiver conteúdo na página, capturar a coordenada de sua posição vertical na página e realizar o scroll da tela até essa posição.
São essas as funções que os navegadores implementam para suas ferramentas de buscar textos na página? Sem o código deles não temos como saber.
Entretanto, essa é a nossa versão dessa funcionalidade, seguindo o raciocínio para simular os mesmos efeitos lógicos de um recurso como esse da forma que conhecemos.
Acabamos de reinventar o “Buscar texto na página” – o famoso Ctrl + F.
Ele não é inovador e muito menos desconhecido, mas é justamente devido a essa importância e fama do recurso que conseguir reproduzi-lo por esforço próprio. Dá um belo highlight nas habilidades de quem o fizer.
Ao menos no quesito de programação e desenvolvimento, criar algo da enésima vez não iguala e nem tira o mérito de quem o fez de primeira, mas certamente pode mostrar as mesmas capacidades de quem conseguir fazê-lo.