Problema ao selecionar o elemento em um formulário de reserva de iframe

8

Estou tentando selecionar o campo de email neste formulário de reserva de iframe. Eventualmente, quero fazer outra coisa com o campo, mas por enquanto, como teste, só quero selecionar o elemento e alterar o espaço reservado.

Obtendo este erro para que eu não o selecione corretamente: TypeError não capturado: Não é possível definir a propriedade 'espaço reservado' de null em HTMLButtonElement.changeCopy

Você pode visualizar uma versão ao vivo do meu código aqui e ver o erro no console ao clicar no botão na parte superior: https://finnpegler.github.io/cart_recover/

Também incluí o código como um trecho abaixo, mas gera um erro diferente relacionado aos quadros de origem cruzada.

var iframe = document.getElementById("booking-widget-iframe");
var field = iframe.contentWindow.document.querySelector("booking[email]");

function changeCopy() {
field.placeholder = "hello";
}

document.getElementById("button").addEventListener("click", changeCopy)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test site for Cart Recover Tool</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css" />
<link href="https://fonts.googleapis.com/css?family=Bree+Serif|Open+Sans&display=swap" rel="stylesheet">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
</head>
<body>
Clicking this button should change the placeholder text in the email field below
<button id = "button">Click</button>
</body>

<script src="https://bettercleans.launch27.com/jsbundle"></script><iframe id="booking-widget-iframe" src="https://bettercleans.launch27.com/?w_cleaning" style="border:none;width:100%;min-height:2739px;overflow:hidden" scrolling="no"></iframe>
<script src="script.js"></script>

FinnPegler
fonte
1
Os navegadores bloquearão as tentativas de um quadro pai de manipular o conteúdo ou a estrutura de um quadro filho, se não forem da mesma origem, ou seja, não forem do mesmo domínio. No seu caso, a origem do quadro pai é finnpegler.github.io, mas a origem do quadro filho é bettercleans.launch27.com. Se você tiver acesso ao código-fonte js de bettercleans.launch27.com, poderá tentar solucionar o problema postando uma mensagem no quadro filho. Veja se esta publicação no SO ajuda você a stackoverflow.com/questions/25098021/…
Nivi M

Respostas:

6

O motivo pelo qual o campo é nulo é que, quando a variável foi configurada, o valor foi bloqueado. Tente abrir seu console JavaScript na página e cole

var iframe = document.getElementById("booking-widget-iframe");

Como na fonte, que deve funcionar, mas veja o que acontece quando você entra:

var field = iframe.contentWindow.document.querySelector("booking[email]");

Você deve receber algo como o seguinte erro:

Uncaught DOMException: Blocked a frame with origin "https://finnpegler.github.io" from accessing a cross-origin frame.
    at <anonymous>:1:34

Portanto, o problema não é field.placeholder = "hello";ser nulo, pois esse campo nunca foi definido porque foi bloqueado de uma origem de origem cruzada.

A maneira de corrigir isso: se você tiver acesso a https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4 , em algum lugar da fonte dessa página, digite o seguinte script:

<script>
addEventListener("message", function(e) {
    console.log(e.data);
    if(e.data["setIt"]) {
        document.querySelector("booking[email]").placeholder = e.data["setIt"];
         e.source.postMessage({
             hi:"I did it" 
         });
    }

});


</script>

Em sua fonte da página https://finnpegler.github.io/cart_recover/ , em algum lugar, digite o código:

<script>
var iframe;
addEventListener("load", function() {
    iframe = document.getElementById("booking-widget-iframe");
    iframe.contentWindow.postMessage({
        setIt: "hello"
    });

});
addEventListener("message", function(e) {
    console.log(e);
})
</script>

Aviso: código não testado, mas aqui está a idéia básica: com o JavaScript do lado do cliente, você não pode editar diretamente os elementos de um iframe; portanto, a maneira de se comunicar com ele é enviar uma mensagem para o iframe usando iframe.contentWindow.postMessage. No lado do iframe, você pode ler a mensagem que está chegando com o ouvinte "message" do ouvinte de eventos (ou pode fazer window.onmessage). Em seguida, você pode enviar dados ou texto JSON como uma mensagem para o iframe e lê-lo com e.data. Portanto, no exemplo acima (não testado), quando a página principal do github deseja alterar o valor do espaço reservado para uma quantidade específica, ela simplesmente envia um objeto JSON que contém os dados do espaço reservado para o iframe e, em seguida, no lado da fonte do iframe, lê essa mensagem recebida, verifica o JSON se ele possui a chave definida para definir o espaço reservado e, se possui essa chave,

Entre em contato se tiver mais alguma dúvida.

Aqui estão algumas referências:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/ comunicação entre janelas https://bl.ocks.org/pbojinov/8965299 https://www.ilearnjavascript.com/plainjs-postmessage-and-iframes/ https://medium.com/@Farzad_YZ/cross-domain -iframe-parent-communication-403912fff692

bluejayke
fonte
0

Primeiro, vamos esclarecer o que realmente está acontecendo. Para ajudar na análise, modifiquei seu script sem introduzir nenhum efeito colateral da seguinte maneira:

var iframe = document.getElementById( "booking-widget-iframe" );

console.log( `iframe: ${ iframe }` );
console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

function changeCopy() {
    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: started" );
    console.log( "-------------------------------------------------------------------------------" );

    var iframe = document.getElementById( "booking-widget-iframe" );

    console.log( `iframe: ${ iframe }` );
    console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
    console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
    console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

    var field = iframe.contentWindow.document.querySelector( "booking[email]" );
    field.placeholder = "hello";

    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: finished" );
    console.log( "-------------------------------------------------------------------------------" );
}

document.getElementById( "button" ).addEventListener( "click", changeCopy )

O carregamento do documento com o script acima provou o seguinte resultado: Executar saída do script

O que aprendemos com o resultado?

  1. Antes de clicar no botão, iframe.contentWindow.document.querySelector( "booking[email]" )avalia como null. Portanto, a variável fieldera essencialmente null.

  2. Por que iframe.contentWindow.document.querySelector( "booking[email]" )avaliar null antes de clicar no botão ?

    • Como o iframedocumento não foi carregado, o navegador (Safari) considerou subótimo executar políticas de segurança entre os quadros pai e filho.
  3. Até o momento eu pressionado no Click botão, o documentde #booking-widget-iframe(quadro filho) tinha carregado completamente, e aplicação de políticas de segurança entre o pai ea criança quadros foi habilitado. Conseqüentemente, a tentativa de acesso iframe.contentWindowfoi prontamente bloqueada devido à falha na conformidade com a política de quadros de origem cruzada.

Possíveis resoluções:

  • Para que os scripts no quadro pai possam ter acesso a objetos no quadro filho, os quadros pai e filho devem ser carregados a partir do mesmo domain(por exemplo, https://bettercleans.launch27.com ) e port(irrelevante para o caso em consideração )
  • Como alternativa, use pós-mensagens para interação entre os dois quadros, conforme documentado em Window.postMessage () .

Supondo que você possa aplicar a resolução, há outro problema que deve aparecer 🙂. iframe.contentWindow.document.querySelector("booking[email]")ainda seria null. A causa raiz do problema subsequente deveu-se a nenhum elemento nomeado bookingencontrado no documento de destino. Em outras palavras, o seletor "booking[email]"está errado.

Igwe Kalu
fonte