DOM

Este guia descreve como acessar a um documento DOM, encontrar elementos, modificar uma estrutura DOM, simular a entrada do usuário, etc.

Visão geral

Cada página Web carregada em um Browser tem um Frame principal . O próprio Frame pode ter frames filhos. Por exemplo, quando uma página web tem IFRAMEs, utilize a classe Frame para acessar o DOM e o JavaScript.

Acessando o documento

Cada Frame tem um Document DOM. Para acessar o Documento utilize o método Frame.document():

frame.document().ifPresent(document -> {});
frame.document().ifPresent { document -> }

Encontrando elementos

Você pode encontrar elementos HTML dentro de um elemento através de diferentes condições. O exemplo a seguir demonstra como encontrar todos os elementos DIV dentro do elemento document:

document.documentElement().ifPresent(documentElement ->
        documentElement.findElementsByTagName("div").forEach(element -> {})); 
document.documentElement().ifPresent { documentElement ->
        documentElement.findElementsByTagName("div").forEach { element -> } }

Se você precisar encontrar apenas o primeiro elemento HTML, utilize a seguinte abordagem:

documentElement.findElementByTagName("div").ifPresent(element -> {});
documentElement.findElementByTagName("div").ifPresent { element -> }

Aqui estão os exemplos de pesquisa de elementos HTML por diferentes condições:

documentElement.findElementsById("<id>");
documentElement.findElementsByName("<attr-name>");
documentElement.findElementsByTagName("<tag-name>");
documentElement.findElementsByClassName("<attr-class>");
documentElement.findElementsById("<id>")
documentElement.findElementsByName("<attr-name>")
documentElement.findElementsByTagName("<tag-name>")
documentElement.findElementsByClassName("<attr-class>")

XPath

A API DOM do JxBrowser permite a avaliação de expressões XPath utilizando Node.evaluate(String expression). É possível avaliar uma expressão XPath no âmbito de um Node especificado utilizando o seguinte código:

try {
    XPathResult result = node.evaluate("count(//div)");
} catch (XPathException e) {
    // Falha ao avaliar a expressão fornecida.
}
try {
    val result: XPathResult = node.evaluate("count(//div)")
} catch (e: XPathException) {
    // Failed to evaluate the given expression.
}

O método lança XPathException quando a biblioteca não consegue avaliar a expressão fornecida.

O resultado da avaliação é armazenado no objeto XPathResult. Certifique-se de que o resultado contém o tipo de valor esperado em, por exemplo, Number, Boolean, String, Node, e extrai o próprio valor:

if (result.isNumber()) {
    double number = result.asNumber();
}
if (result.isNumber()) {
    val number: Double = result.asNumber()
}

Seletor de Query

Para encontrar os elementos que correspondem a um seletor especificado, por exemplo, #root, utilize o seguinte código:

List<Element> elements = element.findElementsByCssSelector("#root");
val elements = element.findElementsByCssSelector("#root")

Node no Ponto

Para encontrar o Node num ponto específico, por exemplo, 100x150, na página Web, utilize a seguinte abordagem:

PointInspection inspection = frame.inspect(Point.of(100, 150));
inspection.node().ifPresent(node -> {});
val inspection: PointInspection = frame.inspect(Point.of(100, 150))
inspection.node().ifPresent { node -> }

Trabalhando com elementos

Limites de elementos

Você pode obter os limites do Element com a posição relativa ao topo esquerdo da janela de visualização do Document atual da seguinte forma:

Rect rect = element.boundingClientRect();
val rect = element.boundingClientRect()

Este método devolve um Rect vazio quando o elemento tem um atributo hidden ou o estilo CSS do elemento contém a declaração display: none;.

Atributos do elemento

A classe Element fornece métodos que permitem obter, adicionar, remover ou modificar os atributos de elementos HTML. O seguinte exemplo demonstra como obter todos os atributos do elemento e imprimir os seus nomes e valores:

element.attributes().forEach((name, value) ->
        System.out.println(name + ": " + value));
element.attributes().forEach { name, value ->
    println("$name: $value") 
}

O exemplo seguinte demonstra como adicionar/modificar um atributo de elemento:

element.putAttribute("attrName", "attrValue");
element.putAttribute("attrName", "attrValue")

Criação de elementos

A API DOM permite modificar a estrutura DOM do documento. O exemplo seguinte demonstra como criar e inserir o elemento <p> com algum texto:

// Cria um novo elemento de parágrafo.
Element paragraph = document.createElement("p");
// Criar um nó de texto com o texto fornecido.
Node text = document.createTextNode("Text");
// Inserir o nó de texto no elemento de parágrafo.
if (paragraph.appendChild(text)) {
    // Inserir o elemento de parágrafo no elemento necessário.
    boolean success = element.appendChild(paragraph);
}
// Cria um novo elemento de parágrafo.
val paragraph = document.createElement("p")
// Criar um nó de texto com o texto fornecido.
val text = document.createTextNode("Text")
// Inserir o nó de texto no elemento de parágrafo.
if (paragraph.appendChild(text)) {
    // Inserir o elemento de parágrafo no elemento necessário.
    success = element.appendChild(paragraph)
}

Fechando Nodes

Objetos DOM que possuem uma contraparte Node não estão sujeitos à coleta de lixo do Blink. Por padrão, mantemos estes objetos na memória até a página ser descarregada.

Para otimizar a utilização da memória, pode ativar a recolha de lixo por objeto:

node.close();
node.close()

Fechar o Node marca o objeto Blink correspondente como coletável, mas não libera o objeto imediatamente. Depois de chamar o método close(), as tentativas de usar Node levarão a ObjectClosedException.

Eventos DOM

Cada Node implementa a interface EventTarget que fornece métodos para registar eventos DOM. Você pode registrar DOM listener para receber eventos DOM como click, mousedown, mouseup, keydown, load, error etc.

O exemplo a seguir demonstra como registrar um ouvinte de evento click para um elemento HTML de documento:

document.documentElement().ifPresent(element ->
        element.addEventListener(EventType.CLICK, event -> {
            // O evento de clique do mouse foi recebido.
            if (event instanceof MouseEvent) {
                MouseEvent mouseEvent = (MouseEvent) event;
                int clickCount = mouseEvent.clickCount();
            }
        }, false));
document.documentElement().ifPresent { element ->
    element.addEventListener(EventType.CLICK, { event ->
            // O evento de clique do mouse foi recebido.
            if (event is MouseEvent) {
                val clickCount = event.clickCount()
            }
        }, false
    )
}

Além disso, o JxBrowser permite que você ouça os eventos DOM personalizados e acessar sua carga útil:

// Criar um tipo de evento DOM personalizado.
EventType eventType = EventType.of("MyEvent");
// Escuta os eventos do tipo de evento fornecido.
element.addEventListener(eventType, event -> {
    // O evento MyEvent foi recebido.
    if (event instanceof CustomEvent) {
        CustomEvent customEvent = (CustomEvent) event;
        JsObject payload = customEvent.detail();
    }
}, false);
// Cria um tipo de evento DOM personalizado.
val eventType = EventType.of("MyEvent")
// Escuta os eventos do tipo de evento fornecido.
element.addEventListener(eventType, { event ->
    // O evento MyEvent foi recebido.
    if (event is CustomEvent) {
        val payload = event.detail<JsObject>()
    }
}, false)

Automatização

A API DOM do JxBrowser fornece tudo o que é necessário para automatizar o preenchimento de formulários Web. Esta seção descreve como atualizar o texto nos campos de texto, selecionar uma caixa de verificação ou um botão radio, selecionar uma ou várias opções numa lista drop-down, simular um clique, etc.

Para trabalhar com controles de formulários Web, utilize a interface FormControlElement. Esta interface permite verificar se o controle está ativado e modificar o seu valor. Todos os controles de formulário, tais como INPUT, SELECT, TEXTAREA, e outros herdam esta interface.

Entrada

Para trabalhar com elementos INPUT utilize a interface InputElement. Fornece todos os métodos necessários para verificar o tipo de entrada e definir o seu valor.

Texto, E-mail, Senha

Para substituir o valor padrão de um campo de texto, e-mail ou senha por um novo valor, utilize o método InputElement.value(String).

Por exemplo, se o seu formulário Web contiver os elementos <input> com os seguintes tipos:

<input type="text" id="firstname" placeholder="First Name">
<input type="email" id="email" placeholder="Email Address">
<input type="password" id="password" placeholder="Password">

você pode definir o seu valor utilizando a seguinte abordagem:

documentElement.findElementById("firstname").ifPresent(element ->
        ((InputElement) element).value("John"));

documentElement.findElementById("email").ifPresent(element ->
        ((InputElement) element).value("me@company.com"));

documentElement.findElementById("password").ifPresent(element ->
        ((InputElement) element).value("Jkdl12!"));
documentElement.findElementById("firstname").ifPresent { element ->
        (element as InputElement).value("John")
}

documentElement.findElementById("email").ifPresent { element ->
        (element as InputElement).value("me@company.com")
}

documentElement.findElementById("password").ifPresent { element ->
        (element as InputElement).value("Jkdl12!")
}

Check Box, Radio Button

Para verificar um botão radio ou uma checkbox, utilize o método InputElement.check().

Por exemplo, se o seu formulário Web contiver os elementos <input> com os seguintes tipos:

<input type="checkbox" id="checkbox" value="Remember me">
<input type="radio" id="radio" checked>

você pode selecionar/desmarcar utilizando a seguinte abordagem:

documentElement.findElementById("checkbox").ifPresent(element ->
        ((InputElement) element).check());

documentElement.findElementById("radio").ifPresent(element ->
        ((InputElement) element).uncheck());
documentElement.findElementById("checkbox").ifPresent { element ->
        (element as InputElement).check()
}

documentElement.findElementById("radio").ifPresent { element ->
        (element as InputElement).uncheck()
}

Arquivo

Os elementos <input> com type=file permitem ao usuário escolher um ou mais arquivos do seu dispositivo de armazenamento. JxBrowser lhe permite selecionar programaticamente um arquivo e atualizar o valor dos <input type=file> elementos.

Por exemplo, se o seu formulário web contiver um elemento <input> como:

<input type="file" id="avatar" accept="image/png, image/jpeg" multiple>

você pode selecionar o(s) arquivo(s) necessário(s) programaticamente utilizando a seguinte abordagem:

documentElement.findElementById("avatar").ifPresent(element ->
        ((InputElement) element).file("file1.png", "file2.jpeg"));
documentElement.findElementById("avatar").ifPresent { element ->
        (element as InputElement).file("file1.png", "file2.jpeg")
}

Área de texto

Para definir o texto num elemento <textarea> como:

<textarea id="details"></textarea>

utilize a seguinte abordagem:

documentElement.findElementById("details").ifPresent(element ->
        ((TextAreaElement) element).value("Some text..."));
documentElement.findElementById("details").ifPresent { element ->
        (element as TextAreaElement).value("Some text...")
}

Select & Option

Para selecionar todas as opções num controle SELECT como:

<select id="fruits" multiple>
    <option>Maçã</option>
    <option>Laranja</option>
    <option>Abacaxi</option>
    <option>Banana</option>
</select>

utilize a seguinte abordagem:

documentElement.findElementById("fruits").ifPresent(element -> {
    SelectElement selectElement = (SelectElement) element;
    selectElement.options().forEach(optionElement ->
            optionElement.select());
});
documentElement.findElementById("fruits").ifPresent { element ->
        val selectElement = element as SelectElement
        selectElement.options().forEach { it.select() }
}

Com esta abordagem, você pode selecionar apenas uma opção necessária.

Simulação de clique

Para simular um clique do mouse num elemento, utilize o seguinte método:

element.click();
element.click()

Quando click() é utilizado com os elementos suportados (como um <input>), ele dispara o evento de clique do elemento. Este evento é então transmitido para os elementos mais elevados na árvore do documento e ativa os respectivos eventos de clique.

Envio de eventos

É possível enviar um Event para o EventTarget especificado utilizando o método EventTarget.dispatch(Event).

O exemplo a seguir demonstra como enviar um evento click padrão para o elemento especificado:

// Localização do cliente e da tela.
Point location = Point.of(10, 10);
// Criar MouseEvent com as opções necessárias.
MouseEvent mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // O botão principal pressionado.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build());
// Gera um evento de clique no elemento de destino.
element.dispatch(mouseClickEvent);
// Localização do cliente e da tela.
val location = Point.of(10, 10)
// Criar MouseEvent com as opções necessárias.
val mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // O botão principal pressionado.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build())
// Gera um evento de clique no elemento de destino.
element.dispatch(mouseClickEvent)

Utilizando esta abordagem, você pode criar e enviar vários eventos DOM. Tais eventos são normalmente designados por eventos sintéticos, por oposição aos eventos disparados pelo Browser propriamente dito.

Go Top