Page 1 of 2
How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 11:27 am
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!

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 12:08 pm
by infratec
What should I do with this Macro
There is no code that I can execute, so I do nothing.
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 12:46 pm
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
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 1:57 pm
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
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 2:10 pm
by Caronte3D
Thank you very much, works nice! What would we do without you, gurus?
Anyway I think PB should have a simplest solution for that simple thing, like let WebViewExecuteScript to return a value or something so...

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 2:42 pm
by infratec
I added a feature request.
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 3:17 pm
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
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 3:20 pm
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>
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 5:05 pm
by mk-soft
Your code only for Windows ...
Update
- With ButtonGadget and ID
See
Update
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 5:19 pm
by Piero
Too much time passed since the last time I boasted I'm a mk-soft Fan
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 5:33 pm
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 ...
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 5:52 pm
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
Thanks again to both of you

Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 6:05 pm
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
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 6:22 pm
by mk-soft
Nice
Missing ...
Code: Select all
Enumeration CustomEvent #PB_Event_FirstCustomValue
#PB_Event_DataReceived
EndEnumeration
Re: How to get a JavaScript variable on a WebViewGadget from PB procedure?
Posted: Sun Jan 26, 2025 6:26 pm
by Caronte3D