Front End

31 dez, 2018

Reinventando a roda – Buscar texto na página

Publicidade

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.

FindTextInDocument — Pesquisando trecho de texto

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.