Merge branch 'webview_runscript_improvements' of https://github.com/TcT2k/wxWidgets
Add WebView::RunScriptAsync() for running scripts asynchronously. See https://github.com/wxWidgets/wxWidgets/pull/2316
This commit is contained in:
@@ -27,6 +27,8 @@ typedef struct _WebKitWebView WebKitWebView;
|
|||||||
// wxWebViewWebKit
|
// wxWebViewWebKit
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class wxWebKitRunScriptParams;
|
||||||
|
|
||||||
class WXDLLIMPEXP_WEBVIEW wxWebViewWebKit : public wxWebView
|
class WXDLLIMPEXP_WEBVIEW wxWebViewWebKit : public wxWebView
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -119,13 +121,15 @@ public:
|
|||||||
virtual wxString GetSelectedSource() const wxOVERRIDE;
|
virtual wxString GetSelectedSource() const wxOVERRIDE;
|
||||||
virtual void ClearSelection() wxOVERRIDE;
|
virtual void ClearSelection() wxOVERRIDE;
|
||||||
|
|
||||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const wxOVERRIDE;
|
|
||||||
#if wxUSE_WEBVIEW_WEBKIT2
|
#if wxUSE_WEBVIEW_WEBKIT2
|
||||||
|
virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const wxOVERRIDE;
|
||||||
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool AddUserScript(const wxString& javascript,
|
virtual bool AddUserScript(const wxString& javascript,
|
||||||
wxWebViewUserScriptInjectionTime injectionTime = wxWEBVIEW_INJECT_AT_DOCUMENT_START) wxOVERRIDE;
|
wxWebViewUserScriptInjectionTime injectionTime = wxWEBVIEW_INJECT_AT_DOCUMENT_START) wxOVERRIDE;
|
||||||
virtual void RemoveAllUserScripts() wxOVERRIDE;
|
virtual void RemoveAllUserScripts() wxOVERRIDE;
|
||||||
|
#else
|
||||||
|
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const wxOVERRIDE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//Virtual Filesystem Support
|
//Virtual Filesystem Support
|
||||||
@@ -151,6 +155,11 @@ public:
|
|||||||
//create-web-view signal and so we need to send a new window event
|
//create-web-view signal and so we need to send a new window event
|
||||||
bool m_creating;
|
bool m_creating;
|
||||||
|
|
||||||
|
#if wxUSE_WEBVIEW_WEBKIT2
|
||||||
|
// This method needs to be public to make it callable from a callback
|
||||||
|
void ProcessJavaScriptResult(GAsyncResult *res, wxWebKitRunScriptParams* params) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) wxOVERRIDE;
|
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) wxOVERRIDE;
|
||||||
|
|
||||||
@@ -173,7 +182,6 @@ private:
|
|||||||
bool CanExecuteEditingCommand(const gchar* command) const;
|
bool CanExecuteEditingCommand(const gchar* command) const;
|
||||||
void SetupWebExtensionServer();
|
void SetupWebExtensionServer();
|
||||||
GDBusProxy *GetExtensionProxy() const;
|
GDBusProxy *GetExtensionProxy() const;
|
||||||
bool RunScriptSync(const wxString& javascript, wxString* output = NULL) const;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
WebKitWebView *m_web_view;
|
WebKitWebView *m_web_view;
|
||||||
|
@@ -88,7 +88,7 @@ public:
|
|||||||
|
|
||||||
virtual bool SetUserAgent(const wxString& userAgent) wxOVERRIDE;
|
virtual bool SetUserAgent(const wxString& userAgent) wxOVERRIDE;
|
||||||
|
|
||||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const wxOVERRIDE;
|
virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const wxOVERRIDE;
|
||||||
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool AddUserScript(const wxString& javascript,
|
virtual bool AddUserScript(const wxString& javascript,
|
||||||
@@ -113,8 +113,6 @@ private:
|
|||||||
|
|
||||||
void OnTopLevelParentIconized(wxIconizeEvent& event);
|
void OnTopLevelParentIconized(wxIconizeEvent& event);
|
||||||
|
|
||||||
bool RunScriptSync(const wxString& javascript, wxString* output = NULL) const;
|
|
||||||
|
|
||||||
wxDECLARE_DYNAMIC_CLASS(wxWebViewEdge);
|
wxDECLARE_DYNAMIC_CLASS(wxWebViewEdge);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -94,7 +94,7 @@ public:
|
|||||||
virtual void SetEditable(bool enable = true) wxOVERRIDE;
|
virtual void SetEditable(bool enable = true) wxOVERRIDE;
|
||||||
virtual bool IsEditable() const wxOVERRIDE;
|
virtual bool IsEditable() const wxOVERRIDE;
|
||||||
|
|
||||||
bool RunScript(const wxString& javascript, wxString* output = NULL) const wxOVERRIDE;
|
virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const wxOVERRIDE;
|
||||||
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool AddScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
virtual bool RemoveScriptMessageHandler(const wxString& name) wxOVERRIDE;
|
||||||
virtual bool AddUserScript(const wxString& javascript,
|
virtual bool AddUserScript(const wxString& javascript,
|
||||||
@@ -118,8 +118,6 @@ private:
|
|||||||
|
|
||||||
WX_NSObject m_navigationDelegate;
|
WX_NSObject m_navigationDelegate;
|
||||||
WX_NSObject m_UIDelegate;
|
WX_NSObject m_UIDelegate;
|
||||||
|
|
||||||
bool RunScriptSync(const wxString& javascript, wxString* output = NULL) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory
|
class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory
|
||||||
|
@@ -24,18 +24,17 @@
|
|||||||
class wxJSScriptWrapper
|
class wxJSScriptWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxJSScriptWrapper(const wxString& js, int* runScriptCount)
|
enum OutputType
|
||||||
: m_escapedCode(js)
|
|
||||||
{
|
{
|
||||||
// We assign the return value of JavaScript snippet we execute to the
|
JS_OUTPUT_STRING, // All return types are converted to a string
|
||||||
// variable with this name in order to be able to access it later if
|
JS_OUTPUT_WEBKIT, // Some return types will be processed
|
||||||
// needed.
|
JS_OUTPUT_IE, // Most return types will be processed
|
||||||
//
|
JS_OUTPUT_RAW // The return types is returned as is
|
||||||
// Note that we use a different name for it for each call to
|
};
|
||||||
// RunScript() (which creates a new wxJSScriptWrapper every time) to
|
|
||||||
// avoid any possible conflict between different calls.
|
|
||||||
m_outputVarName = wxString::Format(wxASCII_STR("__wxOut%i"), (*runScriptCount)++);
|
|
||||||
|
|
||||||
|
wxJSScriptWrapper(const wxString& js, OutputType outputType)
|
||||||
|
: m_escapedCode(js), m_outputType(outputType)
|
||||||
|
{
|
||||||
// Adds one escape level.
|
// Adds one escape level.
|
||||||
const char *charsNeededToBeEscaped = "\\\"\n\r\v\t\b\f";
|
const char *charsNeededToBeEscaped = "\\\"\n\r\v\t\b\f";
|
||||||
for (
|
for (
|
||||||
@@ -69,126 +68,139 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the code to execute, its returned value will be either boolean true,
|
// Get the code to execute, its returned value will be either the value,
|
||||||
// if it executed successfully, or the exception message if an error
|
// if it executed successfully, or the exception message prefixed with
|
||||||
// occurred.
|
// "__wxexc:" if an error occurred.
|
||||||
//
|
//
|
||||||
// Execute GetOutputCode() later to get the real output after successful
|
// Either use SetOutput() to specify the script result or access it directly
|
||||||
// execution of this code.
|
// Using GetOutputRef()
|
||||||
|
//
|
||||||
|
// Execute ExtractOutput() later to get the real output after successful
|
||||||
|
// execution of this code or the proper error message.
|
||||||
wxString GetWrappedCode() const
|
wxString GetWrappedCode() const
|
||||||
{
|
{
|
||||||
return wxString::Format
|
wxString code = wxString::Format(
|
||||||
(
|
wxASCII_STR("(function () { try { var res = eval(\"%s\"); "),
|
||||||
wxASCII_STR("try { var %s = eval(\"%s\"); true; } "
|
m_escapedCode);
|
||||||
"catch (e) { e.name + \": \" + e.message; }"),
|
|
||||||
m_outputVarName,
|
|
||||||
m_escapedCode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get code returning the result of the last successful execution of the
|
switch (m_outputType)
|
||||||
// code returned by GetWrappedCode().
|
{
|
||||||
wxString GetOutputCode() const
|
case JS_OUTPUT_STRING:
|
||||||
{
|
code += wxASCII_STR(
|
||||||
#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT && defined(__WXOSX__)
|
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||||
return wxString::Format
|
"else if (typeof res == 'undefined') return 'undefined';"
|
||||||
(
|
"else return String(res);"
|
||||||
wxASCII_STR("if (typeof %s == 'object') JSON.stringify(%s);"
|
);
|
||||||
"else if (typeof %s == 'undefined') 'undefined';"
|
break;
|
||||||
"else %s;"),
|
case JS_OUTPUT_WEBKIT:
|
||||||
m_outputVarName,
|
code += wxASCII_STR(
|
||||||
m_outputVarName,
|
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||||
m_outputVarName,
|
"else if (typeof res == 'undefined') return 'undefined';"
|
||||||
m_outputVarName
|
"else return res;"
|
||||||
);
|
);
|
||||||
#elif wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
|
break;
|
||||||
return wxString::Format
|
case JS_OUTPUT_IE:
|
||||||
(
|
code += wxASCII_STR(
|
||||||
wxASCII_STR("try {"
|
|
||||||
"(%s == null || typeof %s != 'object') ? String(%s)"
|
|
||||||
": JSON.stringify(%s);"
|
|
||||||
"}"
|
|
||||||
"catch (e) {"
|
|
||||||
"try {"
|
"try {"
|
||||||
"function __wx$stringifyJSON(obj) {"
|
"return (res == null || typeof res != 'object') ? String(res)"
|
||||||
"if (!(obj instanceof Object))"
|
": JSON.stringify(res);"
|
||||||
"return typeof obj === \"string\""
|
|
||||||
"? \'\"\' + obj + \'\"\'"
|
|
||||||
": \'\' + obj;"
|
|
||||||
"else if (obj instanceof Array) {"
|
|
||||||
"if (obj[0] === undefined)"
|
|
||||||
"return \'[]\';"
|
|
||||||
"else {"
|
|
||||||
"var arr = [];"
|
|
||||||
"for (var i = 0; i < obj.length; i++)"
|
|
||||||
"arr.push(__wx$stringifyJSON(obj[i]));"
|
|
||||||
"return \'[\' + arr + \']\';"
|
|
||||||
"}"
|
|
||||||
"}"
|
|
||||||
"else if (typeof obj === \"object\") {"
|
|
||||||
"if (obj instanceof Date) {"
|
|
||||||
"if (!Date.prototype.toISOString) {"
|
|
||||||
"(function() {"
|
|
||||||
"function pad(number) {"
|
|
||||||
"return number < 10"
|
|
||||||
"? '0' + number"
|
|
||||||
": number;"
|
|
||||||
"}"
|
|
||||||
"Date.prototype.toISOString = function() {"
|
|
||||||
"return this.getUTCFullYear() +"
|
|
||||||
"'-' + pad(this.getUTCMonth() + 1) +"
|
|
||||||
"'-' + pad(this.getUTCDate()) +"
|
|
||||||
"'T' + pad(this.getUTCHours()) +"
|
|
||||||
"':' + pad(this.getUTCMinutes()) +"
|
|
||||||
"':' + pad(this.getUTCSeconds()) +"
|
|
||||||
"'.' + (this.getUTCMilliseconds() / 1000)"
|
|
||||||
".toFixed(3).slice(2, 5) + 'Z\"';"
|
|
||||||
"};"
|
|
||||||
"}());"
|
|
||||||
"}"
|
|
||||||
"return '\"' + obj.toISOString(); + '\"'"
|
|
||||||
"}"
|
|
||||||
"var objElements = [];"
|
|
||||||
"for (var key in obj)"
|
|
||||||
"{"
|
|
||||||
"if (typeof obj[key] === \"function\")"
|
|
||||||
"return \'{}\';"
|
|
||||||
"else {"
|
|
||||||
"objElements.push(\'\"\'"
|
|
||||||
"+ key + \'\":\' +"
|
|
||||||
"__wx$stringifyJSON(obj[key]));"
|
|
||||||
"}"
|
|
||||||
"}"
|
|
||||||
"return \'{\' + objElements + \'}\';"
|
|
||||||
"}"
|
|
||||||
"}"
|
|
||||||
"__wx$stringifyJSON(%s);"
|
|
||||||
"}"
|
"}"
|
||||||
"catch (e) { e.name + \": \" + e.message; }"
|
"catch (e) {"
|
||||||
"}"),
|
"try {"
|
||||||
m_outputVarName,
|
"function __wx$stringifyJSON(obj) {"
|
||||||
m_outputVarName,
|
"if (!(obj instanceof Object))"
|
||||||
m_outputVarName,
|
"return typeof obj === \"string\""
|
||||||
m_outputVarName,
|
"? \'\"\' + obj + \'\"\'"
|
||||||
m_outputVarName
|
": \'\' + obj;"
|
||||||
);
|
"else if (obj instanceof Array) {"
|
||||||
#else
|
"if (obj[0] === undefined)"
|
||||||
return m_outputVarName;
|
"return \'[]\';"
|
||||||
#endif
|
"else {"
|
||||||
|
"var arr = [];"
|
||||||
|
"for (var i = 0; i < obj.length; i++)"
|
||||||
|
"arr.push(__wx$stringifyJSON(obj[i]));"
|
||||||
|
"return \'[\' + arr + \']\';"
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
"else if (typeof obj === \"object\") {"
|
||||||
|
"if (obj instanceof Date) {"
|
||||||
|
"if (!Date.prototype.toISOString) {"
|
||||||
|
"(function() {"
|
||||||
|
"function pad(number) {"
|
||||||
|
"return number < 10"
|
||||||
|
"? '0' + number"
|
||||||
|
": number;"
|
||||||
|
"}"
|
||||||
|
"Date.prototype.toISOString = function() {"
|
||||||
|
"return this.getUTCFullYear() +"
|
||||||
|
"'-' + pad(this.getUTCMonth() + 1) +"
|
||||||
|
"'-' + pad(this.getUTCDate()) +"
|
||||||
|
"'T' + pad(this.getUTCHours()) +"
|
||||||
|
"':' + pad(this.getUTCMinutes()) +"
|
||||||
|
"':' + pad(this.getUTCSeconds()) +"
|
||||||
|
"'.' + (this.getUTCMilliseconds() / 1000)"
|
||||||
|
".toFixed(3).slice(2, 5) + 'Z\"';"
|
||||||
|
"};"
|
||||||
|
"}());"
|
||||||
|
"}"
|
||||||
|
"return '\"' + obj.toISOString(); + '\"'"
|
||||||
|
"}"
|
||||||
|
"var objElements = [];"
|
||||||
|
"for (var key in obj)"
|
||||||
|
"{"
|
||||||
|
"if (typeof obj[key] === \"function\")"
|
||||||
|
"return \'{}\';"
|
||||||
|
"else {"
|
||||||
|
"objElements.push(\'\"\'"
|
||||||
|
"+ key + \'\":\' +"
|
||||||
|
"__wx$stringifyJSON(obj[key]));"
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
"return \'{\' + objElements + \'}\';"
|
||||||
|
"}"
|
||||||
|
"}"
|
||||||
|
"return __wx$stringifyJSON(res);"
|
||||||
|
"}"
|
||||||
|
"catch (e) { return \"__wxexc:\" + e.name + \": \" + e.message; }"
|
||||||
|
"}");
|
||||||
|
break;
|
||||||
|
case JS_OUTPUT_RAW:
|
||||||
|
code += wxASCII_STR("return res;");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
code +=
|
||||||
|
wxASCII_STR("} catch (e) { return \"__wxexc:\" + e.name + \": \" + e.message; }"
|
||||||
|
"})()");
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxString& GetUnwrappedOutputCode() { return m_outputVarName; }
|
// Extract the output value
|
||||||
|
//
|
||||||
// Execute the code returned by this function to let the output of the code
|
// Returns true if executed successfully
|
||||||
// we executed be garbage-collected.
|
// string of the result will be put into output
|
||||||
wxString GetCleanUpCode() const
|
// Returns false when an exception occurred
|
||||||
|
// string will be the exception message
|
||||||
|
static bool ExtractOutput(const wxString& result, wxString* output)
|
||||||
{
|
{
|
||||||
return wxString::Format(wxASCII_STR("%s = undefined;"), m_outputVarName);
|
if (output)
|
||||||
|
*output = result;
|
||||||
|
|
||||||
|
if (result.starts_with(wxASCII_STR("__wxexc:")))
|
||||||
|
{
|
||||||
|
if (output)
|
||||||
|
output->Remove(0, 8);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxString m_escapedCode;
|
wxString m_escapedCode;
|
||||||
wxString m_outputVarName;
|
OutputType m_outputType;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(wxJSScriptWrapper);
|
wxDECLARE_NO_COPY_CLASS(wxJSScriptWrapper);
|
||||||
};
|
};
|
||||||
|
@@ -138,7 +138,7 @@ public:
|
|||||||
wxWebView()
|
wxWebView()
|
||||||
{
|
{
|
||||||
m_showMenu = true;
|
m_showMenu = true;
|
||||||
m_runScriptCount = 0;
|
m_syncScriptResult = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~wxWebView() {}
|
virtual ~wxWebView() {}
|
||||||
@@ -191,7 +191,8 @@ public:
|
|||||||
virtual wxString GetUserAgent() const;
|
virtual wxString GetUserAgent() const;
|
||||||
|
|
||||||
// Script
|
// Script
|
||||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const = 0;
|
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const;
|
||||||
|
virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const;
|
||||||
virtual bool AddScriptMessageHandler(const wxString& name)
|
virtual bool AddScriptMessageHandler(const wxString& name)
|
||||||
{ wxUnusedVar(name); return false; }
|
{ wxUnusedVar(name); return false; }
|
||||||
virtual bool RemoveScriptMessageHandler(const wxString& name)
|
virtual bool RemoveScriptMessageHandler(const wxString& name)
|
||||||
@@ -267,15 +268,16 @@ protected:
|
|||||||
bool QueryCommandEnabled(const wxString& command) const;
|
bool QueryCommandEnabled(const wxString& command) const;
|
||||||
void ExecCommand(const wxString& command);
|
void ExecCommand(const wxString& command);
|
||||||
|
|
||||||
// Count the number of calls to RunScript() in order to prevent
|
void SendScriptResult(void* clientData, bool success,
|
||||||
// the_same variable from being used twice in more than one call.
|
const wxString& output) const;
|
||||||
mutable int m_runScriptCount;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void InitFactoryMap();
|
static void InitFactoryMap();
|
||||||
static wxStringWebViewFactoryMap::iterator FindFactory(const wxString &backend);
|
static wxStringWebViewFactoryMap::iterator FindFactory(const wxString &backend);
|
||||||
|
|
||||||
bool m_showMenu;
|
bool m_showMenu;
|
||||||
|
mutable int m_syncScriptResult;
|
||||||
|
mutable wxString m_syncScriptOutput;
|
||||||
wxString m_findText;
|
wxString m_findText;
|
||||||
static wxStringWebViewFactoryMap m_factoryMap;
|
static wxStringWebViewFactoryMap m_factoryMap;
|
||||||
|
|
||||||
@@ -294,6 +296,7 @@ public:
|
|||||||
m_actionFlags(flags), m_messageHandler(messageHandler)
|
m_actionFlags(flags), m_messageHandler(messageHandler)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
bool IsError() const { return GetInt() == 0; }
|
||||||
|
|
||||||
const wxString& GetURL() const { return m_url; }
|
const wxString& GetURL() const { return m_url; }
|
||||||
const wxString& GetTarget() const { return m_target; }
|
const wxString& GetTarget() const { return m_target; }
|
||||||
@@ -319,6 +322,7 @@ wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_NEWWINDOW, wxWebVie
|
|||||||
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent );
|
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent );
|
||||||
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
|
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
|
||||||
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
|
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
|
||||||
|
wxDECLARE_EXPORTED_EVENT( WXDLLIMPEXP_WEBVIEW, wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent);
|
||||||
|
|
||||||
typedef void (wxEvtHandler::*wxWebViewEventFunction)
|
typedef void (wxEvtHandler::*wxWebViewEventFunction)
|
||||||
(wxWebViewEvent&);
|
(wxWebViewEvent&);
|
||||||
|
@@ -485,6 +485,10 @@ public:
|
|||||||
Process a @c wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED event
|
Process a @c wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED event
|
||||||
only available in wxWidgets 3.1.5 or later. For usage details see
|
only available in wxWidgets 3.1.5 or later. For usage details see
|
||||||
AddScriptMessageHandler().
|
AddScriptMessageHandler().
|
||||||
|
@event{wxEVT_WEBVIEW_SCRIPT_RESULT(id, func)}
|
||||||
|
Process a @c wxEVT_WEBVIEW_SCRIPT_RESULT event
|
||||||
|
only available in wxWidgets 3.1.6 or later. For usage details see
|
||||||
|
RunScriptAsync().
|
||||||
@endEventTable
|
@endEventTable
|
||||||
|
|
||||||
@since 2.9.3
|
@since 2.9.3
|
||||||
@@ -710,6 +714,11 @@ public:
|
|||||||
/**
|
/**
|
||||||
Runs the given JavaScript code.
|
Runs the given JavaScript code.
|
||||||
|
|
||||||
|
@note Because of various potential issues it's recommended to use
|
||||||
|
RunScriptAsync() instead of this method. This is especially true
|
||||||
|
if you plan to run code from a webview event and will also prevent
|
||||||
|
unintended side effects on the UI outside of the webview.
|
||||||
|
|
||||||
JavaScript code is executed inside the browser control and has full
|
JavaScript code is executed inside the browser control and has full
|
||||||
access to DOM and other browser-provided functionality. For example,
|
access to DOM and other browser-provided functionality. For example,
|
||||||
this code
|
this code
|
||||||
@@ -764,9 +773,32 @@ public:
|
|||||||
@NULL if it is not needed. This parameter is new since wxWidgets
|
@NULL if it is not needed. This parameter is new since wxWidgets
|
||||||
version 3.1.1.
|
version 3.1.1.
|
||||||
@return @true if there is a result, @false if there is an error.
|
@return @true if there is a result, @false if there is an error.
|
||||||
|
|
||||||
|
@see RunScriptAsync()
|
||||||
*/
|
*/
|
||||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const = 0;
|
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Runs the given JavaScript code asynchronously and returns the result
|
||||||
|
via a @c wxEVT_WEBVIEW_SCRIPT_RESULT.
|
||||||
|
|
||||||
|
The script result value can be retrieved via wxWebViewEvent::GetString().
|
||||||
|
If the execution fails wxWebViewEvent::IsError() will return @true. In this
|
||||||
|
case additional script execution error information maybe available
|
||||||
|
via wxWebViewEvent::GetString().
|
||||||
|
|
||||||
|
@param javascript JavaScript code to execute.
|
||||||
|
@param clientData Arbirary pointer to data that can be retrieved from
|
||||||
|
the result event.
|
||||||
|
|
||||||
|
@note The IE backend does not support async script execution.
|
||||||
|
|
||||||
|
@since 3.1.6
|
||||||
|
@see RunScript()
|
||||||
|
*/
|
||||||
|
virtual void RunScriptAsync(const wxString& javascript, void* clientData = NULL) const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Add a script message handler with the given name.
|
Add a script message handler with the given name.
|
||||||
|
|
||||||
@@ -1279,6 +1311,10 @@ public:
|
|||||||
Process a @c wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED event
|
Process a @c wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED event
|
||||||
only available in wxWidgets 3.1.5 or later. For usage details see
|
only available in wxWidgets 3.1.5 or later. For usage details see
|
||||||
wxWebView::AddScriptMessageHandler().
|
wxWebView::AddScriptMessageHandler().
|
||||||
|
@event{wxEVT_WEBVIEW_SCRIPT_RESULT(id, func)}
|
||||||
|
Process a @c wxEVT_WEBVIEW_SCRIPT_RESULT event
|
||||||
|
only available in wxWidgets 3.1.6 or later. For usage details see
|
||||||
|
wxWebView::RunScriptAsync().
|
||||||
@endEventTable
|
@endEventTable
|
||||||
|
|
||||||
@since 2.9.3
|
@since 2.9.3
|
||||||
@@ -1323,6 +1359,14 @@ public:
|
|||||||
@since 3.1.5
|
@since 3.1.5
|
||||||
*/
|
*/
|
||||||
const wxString& GetMessageHandler() const;
|
const wxString& GetMessageHandler() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns true the script execution failed. Only valid for events of type
|
||||||
|
@c wxEVT_WEBVIEW_SCRIPT_RESULT
|
||||||
|
|
||||||
|
@since 3.1.6
|
||||||
|
*/
|
||||||
|
bool IsError() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -122,6 +122,7 @@ public:
|
|||||||
void OnTitleChanged(wxWebViewEvent& evt);
|
void OnTitleChanged(wxWebViewEvent& evt);
|
||||||
void OnFullScreenChanged(wxWebViewEvent& evt);
|
void OnFullScreenChanged(wxWebViewEvent& evt);
|
||||||
void OnScriptMessage(wxWebViewEvent& evt);
|
void OnScriptMessage(wxWebViewEvent& evt);
|
||||||
|
void OnScriptResult(wxWebViewEvent& evt);
|
||||||
void OnSetPage(wxCommandEvent& evt);
|
void OnSetPage(wxCommandEvent& evt);
|
||||||
void OnViewSourceRequest(wxCommandEvent& evt);
|
void OnViewSourceRequest(wxCommandEvent& evt);
|
||||||
void OnViewTextRequest(wxCommandEvent& evt);
|
void OnViewTextRequest(wxCommandEvent& evt);
|
||||||
@@ -159,6 +160,7 @@ public:
|
|||||||
void OnRunScriptArrayWithEmulationLevel(wxCommandEvent& evt);
|
void OnRunScriptArrayWithEmulationLevel(wxCommandEvent& evt);
|
||||||
#endif
|
#endif
|
||||||
void OnRunScriptMessage(wxCommandEvent& evt);
|
void OnRunScriptMessage(wxCommandEvent& evt);
|
||||||
|
void OnRunScriptAsync(wxCommandEvent& evt);
|
||||||
void OnRunScriptCustom(wxCommandEvent& evt);
|
void OnRunScriptCustom(wxCommandEvent& evt);
|
||||||
void OnAddUserScript(wxCommandEvent& evt);
|
void OnAddUserScript(wxCommandEvent& evt);
|
||||||
void OnSetCustomUserAgent(wxCommandEvent& evt);
|
void OnSetCustomUserAgent(wxCommandEvent& evt);
|
||||||
@@ -233,6 +235,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
wxMenuItem* m_script_message;
|
wxMenuItem* m_script_message;
|
||||||
wxMenuItem* m_script_custom;
|
wxMenuItem* m_script_custom;
|
||||||
|
wxMenuItem* m_script_async;
|
||||||
wxMenuItem* m_selection_clear;
|
wxMenuItem* m_selection_clear;
|
||||||
wxMenuItem* m_selection_delete;
|
wxMenuItem* m_selection_delete;
|
||||||
wxMenuItem* m_find;
|
wxMenuItem* m_find;
|
||||||
@@ -492,6 +495,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||||||
m_script_array_el = script_menu->Append(wxID_ANY, "Return array changing emulation level");
|
m_script_array_el = script_menu->Append(wxID_ANY, "Return array changing emulation level");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
m_script_async = script_menu->Append(wxID_ANY, "Return String async");
|
||||||
m_script_message = script_menu->Append(wxID_ANY, "Send script message");
|
m_script_message = script_menu->Append(wxID_ANY, "Send script message");
|
||||||
m_script_custom = script_menu->Append(wxID_ANY, "Custom script");
|
m_script_custom = script_menu->Append(wxID_ANY, "Custom script");
|
||||||
m_tools_menu->AppendSubMenu(script_menu, _("Run Script"));
|
m_tools_menu->AppendSubMenu(script_menu, _("Run Script"));
|
||||||
@@ -551,6 +555,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||||||
Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &WebFrame::OnTitleChanged, this, m_browser->GetId());
|
Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &WebFrame::OnTitleChanged, this, m_browser->GetId());
|
||||||
Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &WebFrame::OnFullScreenChanged, this, m_browser->GetId());
|
Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &WebFrame::OnFullScreenChanged, this, m_browser->GetId());
|
||||||
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebFrame::OnScriptMessage, this, m_browser->GetId());
|
Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &WebFrame::OnScriptMessage, this, m_browser->GetId());
|
||||||
|
Bind(wxEVT_WEBVIEW_SCRIPT_RESULT, &WebFrame::OnScriptResult, this, m_browser->GetId());
|
||||||
|
|
||||||
// Connect the menu events
|
// Connect the menu events
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnSetPage, this, setPage->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnSetPage, this, setPage->GetId());
|
||||||
@@ -596,6 +601,7 @@ WebFrame::WebFrame(const wxString& url) :
|
|||||||
#endif
|
#endif
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnRunScriptMessage, this, m_script_message->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnRunScriptMessage, this, m_script_message->GetId());
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnRunScriptCustom, this, m_script_custom->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnRunScriptCustom, this, m_script_custom->GetId());
|
||||||
|
Bind(wxEVT_MENU, &WebFrame::OnRunScriptAsync, this, m_script_async->GetId());
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnAddUserScript, this, addUserScript->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnAddUserScript, this, addUserScript->GetId());
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnSetCustomUserAgent, this, setCustomUserAgent->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnSetCustomUserAgent, this, setCustomUserAgent->GetId());
|
||||||
Bind(wxEVT_MENU, &WebFrame::OnClearSelection, this, m_selection_clear->GetId());
|
Bind(wxEVT_MENU, &WebFrame::OnClearSelection, this, m_selection_clear->GetId());
|
||||||
@@ -924,6 +930,14 @@ void WebFrame::OnScriptMessage(wxWebViewEvent& evt)
|
|||||||
wxLogMessage("Script message received; value = %s, handler = %s", evt.GetString(), evt.GetMessageHandler());
|
wxLogMessage("Script message received; value = %s, handler = %s", evt.GetString(), evt.GetMessageHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebFrame::OnScriptResult(wxWebViewEvent& evt)
|
||||||
|
{
|
||||||
|
if (evt.IsError())
|
||||||
|
wxLogError("Async script execution failed: %s", evt.GetString());
|
||||||
|
else
|
||||||
|
wxLogMessage("Async script result received; value = %s", evt.GetString());
|
||||||
|
}
|
||||||
|
|
||||||
void WebFrame::OnSetPage(wxCommandEvent& WXUNUSED(evt))
|
void WebFrame::OnSetPage(wxCommandEvent& WXUNUSED(evt))
|
||||||
{
|
{
|
||||||
m_browser->SetPage
|
m_browser->SetPage
|
||||||
@@ -1199,6 +1213,11 @@ void WebFrame::OnRunScriptMessage(wxCommandEvent& WXUNUSED(evt))
|
|||||||
RunScript("window.wx.postMessage('This is a web message');");
|
RunScript("window.wx.postMessage('This is a web message');");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebFrame::OnRunScriptAsync(wxCommandEvent& WXUNUSED(evt))
|
||||||
|
{
|
||||||
|
m_browser->RunScriptAsync("function f(a){return a;}f('Hello World!');");
|
||||||
|
}
|
||||||
|
|
||||||
void WebFrame::OnRunScriptCustom(wxCommandEvent& WXUNUSED(evt))
|
void WebFrame::OnRunScriptCustom(wxCommandEvent& WXUNUSED(evt))
|
||||||
{
|
{
|
||||||
wxTextEntryDialog dialog
|
wxTextEntryDialog dialog
|
||||||
|
@@ -50,6 +50,7 @@ wxDEFINE_EVENT( wxEVT_WEBVIEW_NEWWINDOW, wxWebViewEvent );
|
|||||||
wxDEFINE_EVENT( wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent );
|
wxDEFINE_EVENT( wxEVT_WEBVIEW_TITLE_CHANGED, wxWebViewEvent );
|
||||||
wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
|
wxDEFINE_EVENT( wxEVT_WEBVIEW_FULLSCREEN_CHANGED, wxWebViewEvent);
|
||||||
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
|
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, wxWebViewEvent);
|
||||||
|
wxDEFINE_EVENT( wxEVT_WEBVIEW_SCRIPT_RESULT, wxWebViewEvent);
|
||||||
|
|
||||||
wxStringWebViewFactoryMap wxWebView::m_factoryMap;
|
wxStringWebViewFactoryMap wxWebView::m_factoryMap;
|
||||||
|
|
||||||
@@ -224,6 +225,51 @@ wxString wxWebView::GetUserAgent() const
|
|||||||
return userAgent;
|
return userAgent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxWebView::RunScript(const wxString& javascript, wxString* output) const
|
||||||
|
{
|
||||||
|
m_syncScriptResult = -1;
|
||||||
|
m_syncScriptOutput.clear();
|
||||||
|
RunScriptAsync(javascript);
|
||||||
|
|
||||||
|
// Wait for script exection
|
||||||
|
while (m_syncScriptResult == -1)
|
||||||
|
wxYield();
|
||||||
|
|
||||||
|
if (m_syncScriptResult && output)
|
||||||
|
*output = m_syncScriptOutput;
|
||||||
|
return m_syncScriptResult == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxWebView::RunScriptAsync(const wxString& WXUNUSED(javascript),
|
||||||
|
void* WXUNUSED(clientData)) const
|
||||||
|
{
|
||||||
|
wxLogError(_("RunScriptAsync not supported"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxWebView::SendScriptResult(void* clientData, bool success,
|
||||||
|
const wxString& output) const
|
||||||
|
{
|
||||||
|
// If currently running sync RunScript(), don't send an event, but use
|
||||||
|
// the scripts result directly
|
||||||
|
if (m_syncScriptResult == -1)
|
||||||
|
{
|
||||||
|
if (!success)
|
||||||
|
wxLogWarning(_("Error running JavaScript: %s"), output);
|
||||||
|
m_syncScriptOutput = output;
|
||||||
|
m_syncScriptResult = success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxWebViewEvent evt(wxEVT_WEBVIEW_SCRIPT_RESULT, GetId(), "", "",
|
||||||
|
wxWEBVIEW_NAV_ACTION_NONE);
|
||||||
|
evt.SetEventObject(const_cast<wxWebView*>(this));
|
||||||
|
evt.SetClientData(clientData);
|
||||||
|
evt.SetInt(success);
|
||||||
|
evt.SetString(output);
|
||||||
|
HandleWindowEvent(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
wxWebView* wxWebView::New(const wxString& backend)
|
wxWebView* wxWebView::New(const wxString& backend)
|
||||||
{
|
{
|
||||||
|
@@ -1231,6 +1231,13 @@ wxString wxWebViewWebKit::GetPageText() const
|
|||||||
return wxString();
|
return wxString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class wxWebKitRunScriptParams
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const wxWebViewWebKit* webKitCtrl;
|
||||||
|
void* clientData;
|
||||||
|
};
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -1238,80 +1245,55 @@ static void wxgtk_run_javascript_cb(GObject *,
|
|||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
g_object_ref(res);
|
wxWebKitRunScriptParams* params = static_cast<wxWebKitRunScriptParams*>(user_data);
|
||||||
|
params->webKitCtrl->ProcessJavaScriptResult(res, params);
|
||||||
GAsyncResult** res_out = static_cast<GAsyncResult**>(user_data);
|
|
||||||
*res_out = res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
// Run the given script synchronously and return its result in output.
|
void wxWebViewWebKit::ProcessJavaScriptResult(GAsyncResult *res, wxWebKitRunScriptParams* params) const
|
||||||
bool wxWebViewWebKit::RunScriptSync(const wxString& javascript, wxString* output) const
|
|
||||||
{
|
{
|
||||||
GAsyncResult *result = NULL;
|
|
||||||
webkit_web_view_run_javascript(m_web_view,
|
|
||||||
javascript.utf8_str(),
|
|
||||||
NULL,
|
|
||||||
wxgtk_run_javascript_cb,
|
|
||||||
&result);
|
|
||||||
|
|
||||||
GMainContext *main_context = g_main_context_get_thread_default();
|
|
||||||
|
|
||||||
while ( !result )
|
|
||||||
g_main_context_iteration(main_context, TRUE);
|
|
||||||
|
|
||||||
wxGtkError error;
|
wxGtkError error;
|
||||||
wxWebKitJavascriptResult js_result
|
wxWebKitJavascriptResult js_result
|
||||||
(
|
(
|
||||||
webkit_web_view_run_javascript_finish
|
webkit_web_view_run_javascript_finish
|
||||||
(
|
(
|
||||||
m_web_view,
|
m_web_view,
|
||||||
result,
|
res,
|
||||||
error.Out()
|
error.Out()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Match g_object_ref() in wxgtk_run_javascript_cb()
|
if ( js_result )
|
||||||
g_object_unref(result);
|
|
||||||
|
|
||||||
if ( !js_result )
|
|
||||||
{
|
{
|
||||||
if ( output )
|
wxString scriptResult;
|
||||||
*output = error.GetMessage();
|
if ( wxGetStringFromJSResult(js_result, &scriptResult) )
|
||||||
return false;
|
{
|
||||||
|
wxString scriptOutput;
|
||||||
|
bool success = wxJSScriptWrapper::ExtractOutput(scriptResult, &scriptOutput);
|
||||||
|
SendScriptResult(params->clientData, success, scriptOutput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendScriptResult(params->clientData, false, error.GetMessage());
|
||||||
|
|
||||||
return wxGetStringFromJSResult(js_result, output);
|
delete params;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output) const
|
void wxWebViewWebKit::RunScriptAsync(const wxString& javascript, void* clientData) const
|
||||||
{
|
{
|
||||||
wxJSScriptWrapper wrapJS(javascript, &m_runScriptCount);
|
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING);
|
||||||
|
|
||||||
// This string is also used as an error indicator: it's cleared if there is
|
// Collect parameters for access from the callback
|
||||||
// no error or used in the warning message below if there is one.
|
wxWebKitRunScriptParams* params = new wxWebKitRunScriptParams;
|
||||||
wxString result;
|
params->webKitCtrl = this;
|
||||||
if ( RunScriptSync(wrapJS.GetWrappedCode(), &result)
|
params->clientData = clientData;
|
||||||
&& result == wxS("true") )
|
|
||||||
{
|
|
||||||
if ( RunScriptSync(wrapJS.GetOutputCode(), &result) )
|
|
||||||
{
|
|
||||||
if ( output )
|
|
||||||
*output = result;
|
|
||||||
result.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunScriptSync(wrapJS.GetCleanUpCode());
|
webkit_web_view_run_javascript(m_web_view,
|
||||||
}
|
wrapJS.GetWrappedCode().utf8_str(),
|
||||||
|
NULL,
|
||||||
if ( !result.empty() )
|
wxgtk_run_javascript_cb,
|
||||||
{
|
params);
|
||||||
wxLogWarning(_("Error running JavaScript: %s"), result);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
||||||
|
@@ -831,74 +831,46 @@ void wxWebViewEdge::MSWSetBrowserExecutableDir(const wxString & path)
|
|||||||
wxWebViewEdgeImpl::ms_browserExecutableDir = path;
|
wxWebViewEdgeImpl::ms_browserExecutableDir = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewEdge::RunScriptSync(const wxString& javascript, wxString* output) const
|
void wxWebViewEdge::RunScriptAsync(const wxString& javascript, void* clientData) const
|
||||||
{
|
{
|
||||||
bool scriptExecuted = false;
|
|
||||||
if (!m_impl->m_webView)
|
if (!m_impl->m_webView)
|
||||||
return false;
|
{
|
||||||
|
SendScriptResult(clientData, false, "");
|
||||||
|
return; // TODO: postpone execution
|
||||||
|
}
|
||||||
|
|
||||||
|
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING);
|
||||||
|
|
||||||
// Start script execution
|
// Start script execution
|
||||||
HRESULT executionResult = m_impl->m_webView->ExecuteScript(javascript.wc_str(), Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
|
HRESULT executionResult = m_impl->m_webView->ExecuteScript(wrapJS.GetWrappedCode().wc_str(), Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
|
||||||
[&scriptExecuted, &executionResult, output](HRESULT error, PCWSTR result) -> HRESULT
|
[this, clientData](HRESULT error, PCWSTR result) -> HRESULT
|
||||||
{
|
{
|
||||||
// Handle script execution callback
|
// Handle script execution callback
|
||||||
if (error == S_OK)
|
if (error == S_OK)
|
||||||
{
|
{
|
||||||
if (output)
|
wxString scriptDecodedResult;
|
||||||
output->assign(result);
|
// Try to decode JSON string or return original
|
||||||
|
// result if it's not a valid JSON string
|
||||||
|
if (!wxJSON::DecodeString(result, &scriptDecodedResult))
|
||||||
|
scriptDecodedResult = result;
|
||||||
|
|
||||||
|
wxString scriptExtractedOutput;
|
||||||
|
bool success = wxJSScriptWrapper::ExtractOutput(scriptDecodedResult, &scriptExtractedOutput);
|
||||||
|
SendScriptResult(clientData, success, scriptExtractedOutput);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
executionResult = error;
|
{
|
||||||
|
SendScriptResult(clientData, false, wxString::Format("%s (0x%08lx)",
|
||||||
scriptExecuted = true;
|
wxSysErrorMsgStr(error), error));
|
||||||
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}).Get());
|
}).Get());
|
||||||
|
|
||||||
// Wait for script exection
|
|
||||||
while (!scriptExecuted)
|
|
||||||
wxYield();
|
|
||||||
|
|
||||||
if (FAILED(executionResult))
|
if (FAILED(executionResult))
|
||||||
{
|
{
|
||||||
if (output)
|
SendScriptResult(clientData, false, wxString::Format("%s (0x%08lx)",
|
||||||
output->Printf("%s (0x%08lx)", wxSysErrorMsgStr(executionResult), executionResult);
|
wxSysErrorMsgStr(executionResult), executionResult));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxWebViewEdge::RunScript(const wxString& javascript, wxString* output) const
|
|
||||||
{
|
|
||||||
wxJSScriptWrapper wrapJS(javascript, &m_runScriptCount);
|
|
||||||
|
|
||||||
// This string is also used as an error indicator: it's cleared if there is
|
|
||||||
// no error or used in the warning message below if there is one.
|
|
||||||
wxString result;
|
|
||||||
if (RunScriptSync(wrapJS.GetWrappedCode(), &result)
|
|
||||||
&& result == wxS("true"))
|
|
||||||
{
|
|
||||||
if (RunScriptSync(wrapJS.GetUnwrappedOutputCode() + ";", &result))
|
|
||||||
{
|
|
||||||
if (output)
|
|
||||||
// Try to decode JSON string or return original
|
|
||||||
// result if it's not a valid JSON string
|
|
||||||
if (!wxJSON::DecodeString(result, output))
|
|
||||||
*output = result;
|
|
||||||
result.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunScriptSync(wrapJS.GetCleanUpCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.empty())
|
|
||||||
{
|
|
||||||
wxLogWarning(_("Error running JavaScript: %s"), result);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewEdge::AddScriptMessageHandler(const wxString& name)
|
bool wxWebViewEdge::AddScriptMessageHandler(const wxString& name)
|
||||||
|
@@ -1045,40 +1045,25 @@ bool wxWebViewIE::RunScript(const wxString& javascript, wxString* output) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxJSScriptWrapper wrapJS(javascript, &m_runScriptCount);
|
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_IE);
|
||||||
|
|
||||||
wxAutomationObject scriptAO(scriptDispatch);
|
wxAutomationObject scriptAO(scriptDispatch);
|
||||||
wxVariant varResult;
|
wxVariant varResult;
|
||||||
|
|
||||||
wxString err;
|
bool success = false;
|
||||||
if ( !CallEval(wrapJS.GetWrappedCode(), scriptAO, &varResult) )
|
wxString scriptOutput;
|
||||||
{
|
if ( CallEval(wrapJS.GetWrappedCode(), scriptAO, &varResult) )
|
||||||
err = _("failed to evaluate");
|
success = wxJSScriptWrapper::ExtractOutput(varResult.MakeString(), &scriptOutput);
|
||||||
}
|
else
|
||||||
else if ( varResult.IsType("bool") && varResult.GetBool() )
|
scriptOutput = _("failed to evaluate");
|
||||||
{
|
|
||||||
if ( output != NULL )
|
|
||||||
{
|
|
||||||
if ( CallEval(wrapJS.GetOutputCode(), scriptAO, &varResult) )
|
|
||||||
*output = varResult.MakeString();
|
|
||||||
else
|
|
||||||
err = _("failed to retrieve execution result");
|
|
||||||
}
|
|
||||||
|
|
||||||
CallEval(wrapJS.GetCleanUpCode(), scriptAO, &varResult);
|
if (!success)
|
||||||
}
|
wxLogWarning(_("Error running JavaScript: %s"), scriptOutput);
|
||||||
else // result available but not the expected "true"
|
|
||||||
{
|
|
||||||
err = varResult.MakeString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !err.empty() )
|
if (success && output)
|
||||||
{
|
*output = scriptOutput;
|
||||||
wxLogWarning(_("Error running JavaScript: %s"), varResult.MakeString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
|
void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
|
||||||
|
@@ -371,76 +371,28 @@ bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType type) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::RunScriptSync(const wxString& javascript, wxString* output) const
|
void wxWebViewWebKit::RunScriptAsync(const wxString& javascript, void* clientData) const
|
||||||
{
|
{
|
||||||
__block bool scriptExecuted = false;
|
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING);
|
||||||
__block wxString outputStr;
|
|
||||||
__block bool scriptSuccess = false;
|
|
||||||
|
|
||||||
// Start script execution
|
// Start script execution
|
||||||
[m_webView evaluateJavaScript:wxCFStringRef(javascript).AsNSString()
|
[m_webView evaluateJavaScript:wxCFStringRef(wrapJS.GetWrappedCode()).AsNSString()
|
||||||
completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
|
completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
outputStr.assign(wxCFStringRef(error.localizedFailureReason).AsString());
|
SendScriptResult(clientData, false, wxCFStringRef(error.localizedDescription).AsString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ([obj isKindOfClass:[NSNumber class]])
|
wxString scriptResult;
|
||||||
{
|
if (obj)
|
||||||
NSNumber* num = (NSNumber*) obj;
|
scriptResult = wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]);
|
||||||
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num));
|
wxString scriptOutput;
|
||||||
if (numID == CFBooleanGetTypeID())
|
bool success = wxJSScriptWrapper::ExtractOutput(scriptResult, &scriptOutput);
|
||||||
outputStr = num.boolValue ? "true" : "false";
|
|
||||||
else
|
|
||||||
outputStr = wxCFStringRef::AsString(num.stringValue);
|
|
||||||
}
|
|
||||||
else if (obj)
|
|
||||||
outputStr.assign(wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]));
|
|
||||||
|
|
||||||
scriptSuccess = true;
|
SendScriptResult(clientData, success, scriptOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptExecuted = true;
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Wait for script exection
|
|
||||||
while (!scriptExecuted)
|
|
||||||
wxYield();
|
|
||||||
|
|
||||||
if (output)
|
|
||||||
output->assign(outputStr);
|
|
||||||
|
|
||||||
return scriptSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output) const
|
|
||||||
{
|
|
||||||
wxJSScriptWrapper wrapJS(javascript, &m_runScriptCount);
|
|
||||||
|
|
||||||
// This string is also used as an error indicator: it's cleared if there is
|
|
||||||
// no error or used in the warning message below if there is one.
|
|
||||||
wxString result;
|
|
||||||
if (RunScriptSync(wrapJS.GetWrappedCode(), &result)
|
|
||||||
&& result == wxS("true"))
|
|
||||||
{
|
|
||||||
if (RunScriptSync(wrapJS.GetOutputCode() + ";", &result))
|
|
||||||
{
|
|
||||||
if (output)
|
|
||||||
*output = result;
|
|
||||||
result.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunScriptSync(wrapJS.GetCleanUpCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.empty())
|
|
||||||
{
|
|
||||||
wxLogWarning(_("Error running JavaScript: %s"), result);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
||||||
|
@@ -35,6 +35,17 @@ public:
|
|||||||
: m_browser(wxWebView::New()),
|
: m_browser(wxWebView::New()),
|
||||||
m_loaded(new EventCounter(m_browser, wxEVT_WEBVIEW_LOADED))
|
m_loaded(new EventCounter(m_browser, wxEVT_WEBVIEW_LOADED))
|
||||||
{
|
{
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
if (wxWebView::IsBackendAvailable(wxWebViewBackendEdge))
|
||||||
|
{
|
||||||
|
// The blank page does not have an empty title with edge
|
||||||
|
m_blankTitle = "about:blank";
|
||||||
|
// Edge does not support about: url use a different URL instead
|
||||||
|
m_alternateHistoryURL = "about:blank";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
m_alternateHistoryURL = "about:";
|
||||||
}
|
}
|
||||||
|
|
||||||
~WebViewTestCase()
|
~WebViewTestCase()
|
||||||
@@ -53,13 +64,33 @@ protected:
|
|||||||
if(i % 2 == 1)
|
if(i % 2 == 1)
|
||||||
m_browser->LoadURL("about:blank");
|
m_browser->LoadURL("about:blank");
|
||||||
else
|
else
|
||||||
m_browser->LoadURL("about:");
|
m_browser->LoadURL(m_alternateHistoryURL);
|
||||||
ENSURE_LOADED;
|
ENSURE_LOADED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnScriptResult(const wxWebViewEvent& evt)
|
||||||
|
{
|
||||||
|
m_asyncScriptResult = (evt.IsError()) ? 0 : 1;
|
||||||
|
m_asyncScriptString = evt.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunAsyncScript(const wxString& javascript)
|
||||||
|
{
|
||||||
|
m_browser->Bind(wxEVT_WEBVIEW_SCRIPT_RESULT, &WebViewTestCase::OnScriptResult, this);
|
||||||
|
m_asyncScriptResult = -1;
|
||||||
|
m_browser->RunScriptAsync(javascript);
|
||||||
|
while (m_asyncScriptResult == -1)
|
||||||
|
wxYield();
|
||||||
|
m_browser->Unbind(wxEVT_WEBVIEW_SCRIPT_RESULT, &WebViewTestCase::OnScriptResult, this);
|
||||||
|
}
|
||||||
|
|
||||||
wxWebView* const m_browser;
|
wxWebView* const m_browser;
|
||||||
EventCounter* const m_loaded;
|
EventCounter* const m_loaded;
|
||||||
|
wxString m_blankTitle;
|
||||||
|
wxString m_alternateHistoryURL;
|
||||||
|
int m_asyncScriptResult;
|
||||||
|
wxString m_asyncScriptString;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
||||||
@@ -88,7 +119,7 @@ TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
|||||||
|
|
||||||
//Test title after loading a url, we yield to let events process
|
//Test title after loading a url, we yield to let events process
|
||||||
LoadUrl();
|
LoadUrl();
|
||||||
CHECK(m_browser->GetCurrentTitle() == "");
|
CHECK(m_browser->GetCurrentTitle() == m_blankTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("URL")
|
SECTION("URL")
|
||||||
@@ -97,7 +128,7 @@ TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
|||||||
|
|
||||||
//After first loading about:blank the next in the sequence is about:
|
//After first loading about:blank the next in the sequence is about:
|
||||||
LoadUrl();
|
LoadUrl();
|
||||||
CHECK(m_browser->GetCurrentURL() == "about:");
|
CHECK(m_browser->GetCurrentURL() == m_alternateHistoryURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("History")
|
SECTION("History")
|
||||||
@@ -336,9 +367,9 @@ TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
|||||||
CHECK(m_browser->RunScript("function f(a){return a;}f(false);", &result));
|
CHECK(m_browser->RunScript("function f(a){return a;}f(false);", &result));
|
||||||
CHECK(result == "false");
|
CHECK(result == "false");
|
||||||
|
|
||||||
CHECK(m_browser->RunScript("function f(){var person = new Object();person.name = 'Foo'; \
|
CHECK(m_browser->RunScript("function f(){var person = new Object();person.lastName = 'Bar'; \
|
||||||
person.lastName = 'Bar';return person;}f();", &result));
|
person.name = 'Foo';return person;}f();", &result));
|
||||||
CHECK(result == "{\"name\":\"Foo\",\"lastName\":\"Bar\"}");
|
CHECK(result == "{\"lastName\":\"Bar\",\"name\":\"Foo\"}");
|
||||||
|
|
||||||
CHECK(m_browser->RunScript("function f(){ return [\"foo\", \"bar\"]; }f();", &result));
|
CHECK(m_browser->RunScript("function f(){ return [\"foo\", \"bar\"]; }f();", &result));
|
||||||
CHECK(result == "[\"foo\",\"bar\"]");
|
CHECK(result == "[\"foo\",\"bar\"]");
|
||||||
@@ -381,6 +412,21 @@ TEST_CASE_METHOD(WebViewTestCase, "WebView", "[wxWebView]")
|
|||||||
CHECK(!m_browser->RunScript("x.y.z"));
|
CHECK(!m_browser->RunScript("x.y.z"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("RunScriptAsync")
|
||||||
|
{
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
// IE doesn't support async script execution
|
||||||
|
if (!wxWebView::IsBackendAvailable(wxWebViewBackendEdge))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
RunAsyncScript("function f(a){return a;}f('Hello World!');");
|
||||||
|
CHECK(m_asyncScriptResult == 1);
|
||||||
|
CHECK(m_asyncScriptString == "Hello World!");
|
||||||
|
|
||||||
|
RunAsyncScript("int main() { return 0; }");
|
||||||
|
CHECK(m_asyncScriptResult == 0);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("SetPage")
|
SECTION("SetPage")
|
||||||
{
|
{
|
||||||
m_browser->SetPage("<html><body>text</body></html>", "");
|
m_browser->SetPage("<html><body>text</body></html>", "");
|
||||||
|
Reference in New Issue
Block a user