Merge branch 'webview-js-retval'
Integrate GSoC 2017 work by Jose Lorenzo on allowing returning values from JavaScript code via wxWebView::RunScript().
This commit is contained in:
70
include/wx/gtk/private/webkit.h
Normal file
70
include/wx/gtk/private/webkit.h
Normal file
@@ -0,0 +1,70 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/gtk/private/webkit.h
|
||||
// Purpose: wxWebKitGtk RAII wrappers declaration
|
||||
// Author: Jose Lorenzo
|
||||
// Created: 2017-08-21
|
||||
// Copyright: (c) 2017 Jose Lorenzo <josee.loren@gmail.com>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_GTK_PRIVATE_WEBKIT_H_
|
||||
#define _WX_GTK_PRIVATE_WEBKIT_H_
|
||||
|
||||
#include "wx/buffer.h"
|
||||
|
||||
#include <webkit2/webkit2.h>
|
||||
#include <JavaScriptCore/JSStringRef.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RAII wrapper of WebKitJavascriptResult taking care of freeing it
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxWebKitJavascriptResult
|
||||
{
|
||||
public:
|
||||
explicit wxWebKitJavascriptResult(WebKitJavascriptResult *r)
|
||||
: m_jsresult(r)
|
||||
{
|
||||
}
|
||||
|
||||
~wxWebKitJavascriptResult()
|
||||
{
|
||||
webkit_javascript_result_unref(m_jsresult);
|
||||
}
|
||||
|
||||
operator WebKitJavascriptResult *() const { return m_jsresult; }
|
||||
|
||||
private:
|
||||
WebKitJavascriptResult *m_jsresult;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxWebKitJavascriptResult);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// RAII wrapper of JSStringRef, also providing conversion to wxString
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxJSStringRef
|
||||
{
|
||||
public:
|
||||
explicit wxJSStringRef(JSStringRef r) : m_jssref(r) { }
|
||||
~wxJSStringRef() { JSStringRelease(m_jssref); }
|
||||
|
||||
wxString ToWxString() const
|
||||
{
|
||||
const size_t length = JSStringGetMaximumUTF8CStringSize(m_jssref);
|
||||
|
||||
wxCharBuffer str(length);
|
||||
|
||||
JSStringGetUTF8CString(m_jssref, str.data(), length);
|
||||
|
||||
return wxString::FromUTF8(str);
|
||||
}
|
||||
|
||||
private:
|
||||
JSStringRef m_jssref;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxJSStringRef);
|
||||
};
|
||||
|
||||
#endif // _WX_GTK_PRIVATE_WEBKIT_H_
|
@@ -114,7 +114,7 @@ public:
|
||||
virtual wxString GetSelectedSource() const wxOVERRIDE;
|
||||
virtual void ClearSelection() wxOVERRIDE;
|
||||
|
||||
virtual void RunScript(const wxString& javascript) wxOVERRIDE;
|
||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) wxOVERRIDE;
|
||||
|
||||
//Virtual Filesystem Support
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) wxOVERRIDE;
|
||||
@@ -160,6 +160,7 @@ private:
|
||||
#if wxUSE_WEBVIEW_WEBKIT2
|
||||
bool CanExecuteEditingCommand(const gchar* command) const;
|
||||
void SetupWebExtensionServer();
|
||||
bool RunScriptSync(const wxString& javascript, wxString* output = NULL);
|
||||
#endif
|
||||
|
||||
WebKitWebView *m_web_view;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "wx/msw/webview_missing.h"
|
||||
#include "wx/sharedptr.h"
|
||||
#include "wx/vector.h"
|
||||
#include "wx/msw/private.h"
|
||||
|
||||
struct IHTMLDocument2;
|
||||
struct IHTMLElement;
|
||||
@@ -121,7 +122,7 @@ public:
|
||||
virtual wxString GetSelectedSource() const wxOVERRIDE;
|
||||
virtual void ClearSelection() wxOVERRIDE;
|
||||
|
||||
virtual void RunScript(const wxString& javascript) wxOVERRIDE;
|
||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) wxOVERRIDE;
|
||||
|
||||
//Virtual Filesystem Support
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) wxOVERRIDE;
|
||||
@@ -143,6 +144,10 @@ public:
|
||||
void onActiveXEvent(wxActiveXEvent& evt);
|
||||
void onEraseBg(wxEraseEvent&) {}
|
||||
|
||||
// Establish sufficiently modern emulation level for the browser control to
|
||||
// allow RunScript() to return any kind of values.
|
||||
static bool MSWSetModernEmulationLevel(bool modernLevel = true);
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
||||
protected:
|
||||
|
@@ -112,7 +112,7 @@ public:
|
||||
virtual wxString GetSelectedSource() const wxOVERRIDE;
|
||||
virtual void ClearSelection() wxOVERRIDE;
|
||||
|
||||
void RunScript(const wxString& javascript) wxOVERRIDE;
|
||||
bool RunScript(const wxString& javascript, wxString* output = NULL) wxOVERRIDE;
|
||||
|
||||
//Virtual Filesystem Support
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) wxOVERRIDE;
|
||||
|
167
include/wx/private/jsscriptwrapper.h
Normal file
167
include/wx/private/jsscriptwrapper.h
Normal file
@@ -0,0 +1,167 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/private/jsscriptwrapper.h
|
||||
// Purpose: JS Script Wrapper for wxWebView
|
||||
// Author: Jose Lorenzo
|
||||
// Created: 2017-08-12
|
||||
// Copyright: (c) 2017 Jose Lorenzo <josee.loren@gmail.com>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_PRIVATE_JSSCRIPTWRAPPER_H_
|
||||
#define _WX_PRIVATE_JSSCRIPTWRAPPER_H_
|
||||
|
||||
#include "wx/regex.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helper for wxWebView::RunScript()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This class provides GetWrappedCode(), GetOutputCode() and GetCleanUpCode()
|
||||
// functions that should be executed in the backend-appropriate way by each
|
||||
// wxWebView implementation in order to actually execute the user-provided
|
||||
// JavaScript code, retrieve its result (if it executed successfully) and
|
||||
// perform the cleanup at the end.
|
||||
class wxJSScriptWrapper
|
||||
{
|
||||
public:
|
||||
wxJSScriptWrapper(const wxString& js, int* runScriptCount)
|
||||
: m_escapedCode(js)
|
||||
{
|
||||
// We assign the return value of JavaScript snippet we execute to the
|
||||
// variable with this name in order to be able to access it later if
|
||||
// needed.
|
||||
//
|
||||
// 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("__wxOut%i", (*runScriptCount)++);
|
||||
|
||||
// Adds one escape level if there is a single quote, double quotes or
|
||||
// escape characters
|
||||
wxRegEx escapeDoubleQuotes("(\\\\*)(['\"\n\r\v\t\b\f])");
|
||||
escapeDoubleQuotes.Replace(&m_escapedCode,"\\1\\1\\\\\\2");
|
||||
}
|
||||
|
||||
// Get the code to execute, its returned value will be either boolean true,
|
||||
// if it executed successfully, or the exception message if an error
|
||||
// occurred.
|
||||
//
|
||||
// Execute GetOutputCode() later to get the real output after successful
|
||||
// execution of this code.
|
||||
wxString GetWrappedCode() const
|
||||
{
|
||||
return wxString::Format
|
||||
(
|
||||
"try { var %s = eval(\"%s\"); true; } "
|
||||
"catch (e) { e.name + \": \" + e.message; }",
|
||||
m_outputVarName,
|
||||
m_escapedCode
|
||||
);
|
||||
}
|
||||
|
||||
// Get code returning the result of the last successful execution of the
|
||||
// code returned by GetWrappedCode().
|
||||
wxString GetOutputCode() const
|
||||
{
|
||||
#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT && defined(__WXOSX__)
|
||||
return wxString::Format
|
||||
(
|
||||
"if (typeof %s == 'object') JSON.stringify(%s);"
|
||||
"else if (typeof %s == 'undefined') 'undefined';"
|
||||
"else %s;",
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName
|
||||
);
|
||||
#elif wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
|
||||
return wxString::Format
|
||||
(
|
||||
"try {"
|
||||
"(%s == null || typeof %s != 'object') ? String(%s)"
|
||||
": JSON.stringify(%s);"
|
||||
"}"
|
||||
"catch (e) {"
|
||||
"try {"
|
||||
"function __wx$stringifyJSON(obj) {"
|
||||
"if (!(obj instanceof Object))"
|
||||
"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; }"
|
||||
"}",
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName
|
||||
);
|
||||
#else
|
||||
return m_outputVarName;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Execute the code returned by this function to let the output of the code
|
||||
// we executed be garbage-collected.
|
||||
wxString GetCleanUpCode() const
|
||||
{
|
||||
return wxString::Format("%s = undefined;", m_outputVarName);
|
||||
}
|
||||
|
||||
private:
|
||||
wxString m_escapedCode;
|
||||
wxString m_outputVarName;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxJSScriptWrapper);
|
||||
};
|
||||
|
||||
#endif // _WX_PRIVATE_JSSCRIPTWRAPPER_H_
|
@@ -117,6 +117,7 @@ public:
|
||||
wxWebView()
|
||||
{
|
||||
m_showMenu = true;
|
||||
m_runScriptCount = 0;
|
||||
}
|
||||
|
||||
virtual ~wxWebView() {}
|
||||
@@ -161,7 +162,7 @@ public:
|
||||
virtual void Print() = 0;
|
||||
virtual void RegisterHandler(wxSharedPtr<wxWebViewHandler> handler) = 0;
|
||||
virtual void Reload(wxWebViewReloadFlags flags = wxWEBVIEW_RELOAD_DEFAULT) = 0;
|
||||
virtual void RunScript(const wxString& javascript) = 0;
|
||||
virtual bool RunScript(const wxString& javascript, wxString* output = NULL) = 0;
|
||||
virtual void SetEditable(bool enable = true) = 0;
|
||||
void SetPage(const wxString& html, const wxString& baseUrl)
|
||||
{
|
||||
@@ -223,6 +224,10 @@ public:
|
||||
protected:
|
||||
virtual void DoSetPage(const wxString& html, const wxString& baseUrl) = 0;
|
||||
|
||||
// Count the number of calls to RunScript() in order to prevent
|
||||
// the_same variable from being used twice in more than one call.
|
||||
int m_runScriptCount;
|
||||
|
||||
private:
|
||||
static void InitFactoryMap();
|
||||
static wxStringWebViewFactoryMap::iterator FindFactory(const wxString &backend);
|
||||
|
Reference in New Issue
Block a user