How to get a JavaScript variable on a WebViewGadget from PB procedure?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Caronte3D »

I know how to set the value but... how to read it directly from a PureBasic procedure?

This is the macro I use to set a text element by her ID:

Code: Select all

Macro SetTextElement(element, text)
        WebViewExecuteScript(0, element+~"=document.getElementById(\""+element+~"\"); "+element+~".textContent=\""+text+~"\";");
EndMacro
Thanks in advance! :D
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by infratec »

What should I do with this Macro :?:

There is no code that I can execute, so I do nothing.
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Caronte3D »

Sorry infratec, the Macro was only an example of the oposite (set a text element by ID) in case someone need it.
What I need is a way to obtain the text of an element (i.e: a button) by her ID.

I modified the example on the help to change the button text form PB (without clicking on the JS button), but... how to get that text (or another one) from JS to PB if I only know the element ID?

Code: Select all

  Html$ =  ~"<button id=\"displayInfo\">Display Info</button>\n"+
           ~"<script>\n"+
           ~"  const displayInfoElement=document.getElementById(\"displayInfo\");\n"+
           ~"  document.addEventListener(\"DOMContentLoaded\", () => {\n"+
           ~"    displayInfoElement.addEventListener(\"click\", () => {\n"+
           ~"      window.displayInfo(1000, 2000).then(result => {\n"+
           ~"      });\n"+
           ~"    });\n"+
           ~"  });\n"+
           ~"</script>";
  
  Macro SetTextElement(element, text)
          WebViewExecuteScript(0, element+~"=document.getElementById(\""+element+~"\"); "+element+~".textContent=\""+text+~"\";");
  EndMacro  
  

  Procedure mytimer()
    Static ii
    ii+1
    ;  WebViewExecuteScript(0, ~"incre=document.getElementById(\"increment2\"); incre.textContent=\"Hello from Callback "+Str(ii)+~"!\";");
    SetTextElement("displayInfo","MyText "+Str(ii))
  EndProcedure
  
  Procedure DisplayInfoCallback(JsonParameters$)
    ; Execute a script in the webview
    WebViewExecuteScript(0, ~"const element=document.getElementById(\"displayInfo\"); element.textContent=\"Hello from Callback !\";");
  EndProcedure

  OpenWindow(0, 100, 100, 400, 400, "Hello", #PB_Window_SystemMenu)

  WebViewGadget(0, 0, 0, 400, 400)
  SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
    
  BindWebViewCallback(0, "displayInfo", @DisplayInfoCallback())
  
  AddWindowTimer(0, 1, 1000)
  
  BindEvent(#PB_Event_Timer, @mytimer())


  Repeat 
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow

infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by infratec »

Save it as WebViewExecuteScriptWithStringResult.pbi

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf

DataSection
  IID_IUnknown:
  Data.l $00000000
  Data.w $0000, $0000
  Data.b $C0, $00, $00, $00, $00, $00, $00, $46
EndDataSection

Structure IUnknownBase_Structure
  *pVtbl
  *pQueryInterface
  *pAddRef
  *pRelease
  *pInvoke
  
  iRefCount.i
  hEvent.i
EndStructure

Structure ICoreWebView2ExecuteScriptCompletedHandler_Structure Extends IUnknownBase_Structure
  Result$
EndStructure

Procedure.l CoreWebView2CompletedHandler_QueryInterface(*this.IUnknownBase_Structure, *riid.IID, *ppvObject.Integer)
  If *ppvObject And *riid
    If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
      *this\iRefCount + 1
      *ppvObject\i = *this
    Else
      *ppvObject\i = 0
      ProcedureReturn #E_NOINTERFACE
    EndIf
  Else
    ProcedureReturn #E_POINTER
  EndIf
  ProcedureReturn #S_OK
EndProcedure

Procedure.l CoreWebView2CompletedHandler_AddRef(*this.IUnknownBase_Structure)
  ;Debug "CoreWebView2CompletedHandler_AddRef"
  *this\iRefCount + 1
  ProcedureReturn *this\iRefCount
EndProcedure

Procedure.l CoreWebView2CompletedHandler_Release(*this.IUnknownBase_Structure)
  ;Debug "CoreWebView2CompletedHandler_Release"
  *this\iRefCount - 1
  ProcedureReturn *this\iRefCount
EndProcedure

Procedure.l CoreWebView2ExecuteScriptCompletedHandler_Invoke(*this.ICoreWebView2ExecuteScriptCompletedHandler_Structure, errorCode.l, *returnObjectAsJson)
  Protected sResult.s, iCount
  
  ;Debug "CoreWebView2ExecuteScriptCompletedHandler_Invoke"
  
  If errorCode = #S_OK
    If *returnObjectAsJson
      *this\Result$ = PeekS(*returnObjectAsJson)
    EndIf
  EndIf
  
  If *this\hEvent
    SetEvent_(*this\hEvent)
  EndIf
  
  ProcedureReturn #S_OK
  
EndProcedure


Procedure.s WebViewExecuteScriptWithStringResult(WebGadget, JavaScript$)
  
  Protected Result$
  Protected Controller.ICoreWebView2Controller, Core.ICoreWebView2
  Protected *ExecuteScriptCompletedHandler.ICoreWebView2ExecuteScriptCompletedHandler_Structure
  Protected hEvent
  
  
  If GadgetType(WebGadget) = #PB_GadgetType_WebView
    
    Controller = GetGadgetAttribute(WebGadget, #PB_WebView_ICoreController)
    If Controller
      
      If Controller\get_CoreWebView2(@Core) = #S_OK And Core <> #Null
        
        hEvent = CreateEvent_(0, 0, 0, 0)
        If hEvent
          
          *ExecuteScriptCompletedHandler = AllocateMemory(SizeOf(ICoreWebView2ExecuteScriptCompletedHandler_Structure))
          If *ExecuteScriptCompletedHandler
            *ExecuteScriptCompletedHandler\pVtbl = *ExecuteScriptCompletedHandler + OffsetOf(IUnknownBase_Structure\pQueryInterface)
            *ExecuteScriptCompletedHandler\pQueryInterface = @CoreWebView2CompletedHandler_QueryInterface()
            *ExecuteScriptCompletedHandler\pAddRef = @CoreWebView2CompletedHandler_AddRef()
            *ExecuteScriptCompletedHandler\pRelease = @CoreWebView2CompletedHandler_Release()
            *ExecuteScriptCompletedHandler\pInvoke = @CoreWebView2ExecuteScriptCompletedHandler_Invoke()
            
            *ExecuteScriptCompletedHandler\hEvent = hEvent
            
            If Core\ExecuteScript(JavaScript$, *ExecuteScriptCompletedHandler) = #S_OK
              
              While WaitForSingleObject_(hEvent, 0) <> #WAIT_OBJECT_0
                WindowEvent()
              Wend
              
              Result$ = *ExecuteScriptCompletedHandler\Result$
            EndIf
            
            FreeMemory(*ExecuteScriptCompletedHandler)
          EndIf
          
          CloseHandle_(hEvent)
        EndIf
        
        Core\Release()
      EndIf
    EndIf
    
  EndIf
  
  ProcedureReturn Result$
  
EndProcedure



CompilerIf #PB_Compiler_IsMainFile
  
  Define event, Html$
  
  
  Html$ =  "<div id='pb'>string</div>"
  
  
  OpenWindow(0, 0, 0, 1000, 600, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  
  WebViewGadget(0, 0, 0, 400, 400)
  SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
  
  AddWindowTimer(0, 0, 3000)
  
  Repeat 
    Event = WaitWindowEvent()
    If Event = #PB_Event_Timer
      RemoveWindowTimer(0, 0)
      Debug WebViewExecuteScriptWithStringResult(0, "document.getElementById('pb').textContent;")
    EndIf
    
  Until Event = #PB_Event_CloseWindow
  
CompilerEndIf

Code: Select all

IncludeFile "WebViewExecuteScriptWithStringResult.pbi"


Html$ =  ~"<button id=\"displayInfo\">Display Info</button>\n"+
           ~"<script>\n"+
           ~"  const displayInfoElement=document.getElementById(\"displayInfo\");\n"+
           ~"  document.addEventListener(\"DOMContentLoaded\", () => {\n"+
           ~"    displayInfoElement.addEventListener(\"click\", () => {\n"+
           ~"      window.displayInfo(1000, 2000).then(result => {\n"+
           ~"      });\n"+
           ~"    });\n"+
           ~"  });\n"+
           ~"</script>";
  
  Macro SetTextElement(element, text)
          WebViewExecuteScript(0, element+~"=document.getElementById(\""+element+~"\"); "+element+~".textContent=\""+text+~"\";");
  EndMacro  
  

  Procedure mytimer()
    Static ii
    ii+1
    ;  WebViewExecuteScript(0, ~"incre=document.getElementById(\"increment2\"); incre.textContent=\"Hello from Callback "+Str(ii)+~"!\";");
    SetTextElement("displayInfo","MyText "+Str(ii))
    
  EndProcedure
  
  Procedure DisplayInfoCallback(JsonParameters$)
    ; Execute a script in the webview
    WebViewExecuteScript(0, ~"const element=document.getElementById(\"displayInfo\"); element.textContent=\"Hello from Callback !\";");
  EndProcedure

  OpenWindow(0, 100, 100, 400, 400, "Hello", #PB_Window_SystemMenu)

  WebViewGadget(0, 0, 0, 400, 400)
  SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
    
  BindWebViewCallback(0, "displayInfo", @DisplayInfoCallback())
  
  AddWindowTimer(0, 1, 1000)
  
  BindEvent(#PB_Event_Timer, @mytimer())

  
  AddWindowTimer(0, 0, 500)
  Repeat
    Event = WaitWindowEvent()
    If Event = #PB_Event_Timer
      Debug WebViewExecuteScriptWithStringResult(0, "document.getElementById('displayInfo').textContent")
    EndIf
  Until Event = #PB_Event_CloseWindow
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Caronte3D »

Thank you very much, works nice! What would we do without you, gurus? :D
Anyway I think PB should have a simplest solution for that simple thing, like let WebViewExecuteScript to return a value or something so... :wink:
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by infratec »

I added a feature request.
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by mk-soft »

Over callback ...

Update
- With ButtonGadget

Code: Select all

; TOP

Html$ =  ~"<input type=\"text\" id=\"userInput\" name=\"userInput\">\n"+
         ~"<button id=\"buttonGetData\">Get Data</button>\n"+
         ~"<script>\n"+
         ~"  const buttonGetDataElement=document.getElementById(\"buttonGetData\");\n"+
         ~"  document.addEventListener(\"DOMContentLoaded\", () => {\n"+
         ~"    buttonGetData.addEventListener(\"click\", () => {\n"+
         ~"      var id = \"userInput\";"+
         ~"      var userInput = document.getElementById(id).value;"+
         ~"      window.getData(id, userInput);"+
         ~"    });\n"+
         ~"  });\n"+
         ~"</script>";

Procedure GetDataJS(JsonParameters$)
  ParseJSON(0, JsonParameters$)
  Debug "ID: " + GetJSONString(GetJSONElement(JSONValue(0), 0))
  Debug "Value: " + GetJSONString(GetJSONElement(JSONValue(0), 1))
  
  ;Debug JsonParameters$
  ProcedureReturn 0
EndProcedure


OpenWindow(0, 100, 100, 400, 250, "Hello", #PB_Window_SystemMenu)

WebViewGadget(0, 0, 0, 400, 200, #PB_WebView_Debug)
SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
ButtonGadget(1, 10, 210, 120, 25, "Get Data")
BindWebViewCallback(0, "getData", @GetDataJS())

Repeat 
  Select WaitWindowEvent()
    Case #PB_Event_Gadget 
      If EventGadget() = 1
        id.s = ~"\"userInput\""
        script.s = ~"window.getData(" + id + ", document.getElementById(" + id +").value)"
        WebViewExecuteScript(0, script)
      EndIf
      
    Case #PB_Event_CloseWindow
      Break
      
  EndSelect
ForEver
Last edited by mk-soft on Sun Jan 26, 2025 5:03 pm, edited 2 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by infratec »

But for this you need a JS function.

My code returns a value by an id of any element.
Look at the example with <div>
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by mk-soft »

Your code only for Windows ...

Update
- With ButtonGadget and ID

See Update
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Piero
Addict
Addict
Posts: 865
Joined: Sat Apr 29, 2023 6:04 pm
Location: Italy

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Piero »

Too much time passed since the last time I boasted I'm a mk-soft Fan
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by mk-soft »

@infratec

What I still notice about your code is that when you call your function, the PB events are all deleted until the result is there.
It is better to respond to the data with a callback so that the program is still operable.

For Linux, I also solved these with a callback.
See: Linux WebGadget Extensions

P.S.
Is that first that I try out the new WebViewGadget functions.
Need to do more with JavaScript. There is certainly more ...
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Caronte3D »

mk-soft wrote: Sun Jan 26, 2025 5:33 pm Is that first that I try out the new WebViewGadget functions.
Need to do more with JavaScript. There is certainly more ...
Me too! Indeed I think this can solve the "obsolete look" of the PB programs UI 8)

Thanks again to both of you :wink:
infratec
Always Here
Always Here
Posts: 7577
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by infratec »

A bit extended to show when and how you get the result:

Code: Select all

EnableExplicit


Procedure GetDataCallback(JsonParameters$)
  
  PostEvent(#PB_Event_DataReceived, EventWindow(), EventGadget(), 0, UTF8(JsonParameters$))
  
  ProcedureReturn #Null
  
EndProcedure



Define Html$, *Data

Html$ = "<div id='userInput'>test</div>"

OpenWindow(0, 100, 100, 400, 250, "Hello", #PB_Window_SystemMenu)

WebViewGadget(0, 0, 0, 400, 200, #PB_WebView_Debug)
SetGadgetItemText(0, #PB_WebView_HtmlCode, Html$)
ButtonGadget(1, 10, 210, 120, 25, "Get Data")
BindWebViewCallback(0, "getData", @GetDataCallback())

Repeat 
  Select WaitWindowEvent()
    Case #PB_Event_DataReceived
      If EventGadget() = 0
        *Data = EventData()
        If *Data
          Debug PeekS(*Data, -1, #PB_UTF8)
          FreeMemory(*Data)
        EndIf
      EndIf
      
    Case #PB_Event_Gadget
      If EventGadget() = 1
        WebViewExecuteScript(0, "window.getData(document.getElementById('userInput').textContent)")
      EndIf
      
    Case #PB_Event_CloseWindow
      Break
      
  EndSelect
ForEver
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by mk-soft »

Nice :wink:

Missing ...

Code: Select all

Enumeration CustomEvent #PB_Event_FirstCustomValue
  #PB_Event_DataReceived
EndEnumeration
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Caronte3D
Addict
Addict
Posts: 1355
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?

Post by Caronte3D »

Image
Post Reply