webview / webview

Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows).

Home Page:https://webview.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Calling Webview::eval on some JS code does not work.

kmrashad opened this issue · comments

What OS are you using (uname -a, or Windows version)?

MacOS Sonoma 14.2 ARM64

What programming language are you using (C/C++/Go/Rust)?

clang --version
Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: arm64-apple-darwin23.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

What did you expect to see and what you saw instead?

I want to execute following JS code and get return value. When running this code in WebInspector it return true.

When calling WebView::eval() with below js code it does not return anything!

Here is the bind call to getSource function

   w.bind("getSource", [this](std::string s) -> std::string {
        std::cout << "js result=" << s << std::endl;
        return s;
    });
  1. jsCode 1
elem = window.document.querySelector("input[formcontrolname='email']"); 
rect = elem.getBoundingClientRect(); 
ret = ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) );

webview.eval("getSource(jsCode1)");

Code does not return or fails, It is stuck here...

But these code works:

  1. jsCode 2
    webview.eval("getSource(window.document.querySelector("input[formcontrolname='email']").id)");

returns js result = "css-email-id"

  1. jsCode 3
    webview.eval("getSource(window.document.querySelector("input[formcontrolname='username']").id)");

returns js result = "css-user-id"

  1. jsCode 4
    webview.eval("getSource(window.document.querySelector("input[formcontrolname='username']"))");

Code does not return or fails, stuck like jsCode1

Can you please share a minimal, reproducible example?

@SteffenL

Here is a minimal example.

git log -1

commit 2405c2cd63f3d4b9bcd24f5ad6dfa13660178d7f (HEAD -> master, origin/master, origin/HEAD)
Author: Steffen André Langnes <steffenl.sw@gmail.com>
Date:   Wed Jan 10 11:52:29 2024 +0900

    Workaround for blank window with WebKit/DMA-BUF/NVIDIA/X11 (#1060)

    WebKit 2.42 along with X11 and NVIDIA GPU driver triggers bug:
    https://bugs.webkit.org/show_bug.cgi?id=261874

    The bug causes a blank window. Instead of waiting for the problem
    to be fixed, this work attempts to check for these conditions before
    setting the environment variable WEBKIT_DISABLE_DMABUF_RENDERER to 1.

    If the variable WEBKIT_DISABLE_DMABUF_RENDERER has already been set
    then the workaround is not applied.

CMake code used to compile:

add_executable(jsCallTest
        bind.cc
       webview/webview.cc
)
target_include_directories(jsCallTest PUBLIC temp/webview)
target_link_libraries(jsCallTest PUBLIC "-framework WebKit")

bind.cc

#include "webview.h"
#include <string>
#include <iostream>

constexpr const auto html =
    R"html(
<form>
  <label for="email">Email:</label><br>
  <input type="text" id="email" name="email"><br>
</form>
)html";

int main() {
  unsigned int count = 0;
  webview::webview w(true, nullptr);
  w.set_title("Bind Example");
  w.set_size(480, 320, WEBVIEW_HINT_NONE);

  w.bind("getSource", [&](const std::string & req) -> std::string {
    std::cout << "getSource result=" << req << '\n';
    return "{\"count\": " + req + "}";;
  });

  w.set_html(html);
  w.run();

  //"window.getSource(window.document.querySelector(\"input[name='email']\"))");
  //elem = window.document.querySelector("input[name='email']"); rect = elem.getBoundingClientRect(); ret = ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) )

  return 0;
}

webview/webview.cc

#include "webview.h"

case A

getSource(window.document.querySelector("input[name='email']"));

On WebInspector Console it returns:
Promise{ status: "pending"}

On C++ console returns:
getSource result=[{}] // Issue here, I don't get any result. Maybe it is because it returns an input tag!

case B

getSource(window.document.querySelector("input[name='email']").id);

On WebInspector Console it returns:
Promise{ status: "pending"}

On C++ console returns:
getSource result=["email"]. // This is okay as I get result and promise pending on console is not a bug.

case C

getSource(function() { elem = window.document.querySelector("input[name='email']");  
rect = elem.getBoundingClientRect();
ret = ( rect.top >= 0 && rect.left >= 0 && \
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && \
rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); return ret; })

On WebInspector Console it returns:
Promise{ status: "pending"}

On C++ console returns:
getSource result=[null] //Issue here, result is a boolean and it should be returned in C++ console.

Executing same function without getSource returns true from WebInspector console.

function() { elem = window.document.querySelector("input[name='email']");  
rect = elem.getBoundingClientRect();
ret = ( rect.top >= 0 && rect.left >= 0 && \
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && \
rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); return ret; })

Are you executing the JS code in the console?

case A

What behavior do you expect?

case B

Is this working as you expect?

case C

What behavior do you expect?

Are you executing the JS code in the console?

Yes. results under "WebInspector Console" is from js console and it prints Promise {status: pending}

case A

What behavior do you expect?

Instead of getSource result=[{}] on C++ console it should print information about tag.

case B

Is this working as you expect?

This is working as expected. getSource result=["email"]

case C

What behavior do you expect?

Instead of getSource result=[null] it should return getSource result=["true"] (boolean) as this is the value of "ret" variable in JS code.

Are you executing the JS code in the console?

Yes. results under "WebInspector Console" is from js console and it prints Promise {status: pending}

I believe that's the correct behavior.

case A

What behavior do you expect?

Instead of getSource result=[{}] on C++ console it should print information about tag.

Try to print JSON.stringify(window.document.querySelector("input[name='email']")) in the console. If you can't get the result you expect then that's the behavior of the underlying browser engine, and you'll need to change your approach.

case C

What behavior do you expect?

Instead of getSource result=[null] it should return getSource result=["true"] (boolean) as this is the value of "ret" variable in JS code.

You should explicitly invoke your function and pass the result to getSource().

@SteffenL

You should explicitly invoke your function and pass the result to getSource().

It worked when explicitly calling getSource()

Calling JSON.stringify(window.document.querySelector("input[name='email']")) doesn't work on Inspector's Console.
It shows this error: JSON.stringify cannot serialize cyclic structures.

closing this discussion as [solved]