Restructure javascript result wrapper
This commit is contained in:
committed by
Tobias Taschner
parent
fd2920ff22
commit
2fe12ae6af
@@ -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,16 @@
|
|||||||
class wxJSScriptWrapper
|
class wxJSScriptWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxJSScriptWrapper(const wxString& js, int* runScriptCount)
|
enum OutputType {
|
||||||
: m_escapedCode(js)
|
JS_OUTPUT_STRING, // All return types are converted to a string
|
||||||
{
|
JS_OUTPUT_WEBKIT, // Some return types will be processed
|
||||||
// We assign the return value of JavaScript snippet we execute to the
|
JS_OUTPUT_IE, // Most return types will be processed
|
||||||
// variable with this name in order to be able to access it later if
|
JS_OUTPUT_RAW // The return types is returned as is
|
||||||
// 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(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,44 +67,42 @@ 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
|
|
||||||
{
|
{
|
||||||
#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT && defined(__WXOSX__)
|
case JS_OUTPUT_STRING:
|
||||||
return wxString::Format
|
code += wxASCII_STR(
|
||||||
(
|
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||||
wxASCII_STR("if (typeof %s == 'object') JSON.stringify(%s);"
|
"else if (typeof res == 'undefined') return 'undefined';"
|
||||||
"else if (typeof %s == 'undefined') 'undefined';"
|
"else return String(res);"
|
||||||
"else %s;"),
|
|
||||||
m_outputVarName,
|
|
||||||
m_outputVarName,
|
|
||||||
m_outputVarName,
|
|
||||||
m_outputVarName
|
|
||||||
);
|
);
|
||||||
#elif wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
|
break;
|
||||||
return wxString::Format
|
case JS_OUTPUT_WEBKIT:
|
||||||
(
|
code += wxASCII_STR(
|
||||||
wxASCII_STR("try {"
|
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||||
"(%s == null || typeof %s != 'object') ? String(%s)"
|
"else if (typeof res == 'undefined') return 'undefined';"
|
||||||
": JSON.stringify(%s);"
|
"else return res;"
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case JS_OUTPUT_IE:
|
||||||
|
code += wxASCII_STR(
|
||||||
|
"try {"
|
||||||
|
"return (res == null || typeof res != 'object') ? String(res)"
|
||||||
|
": JSON.stringify(res);"
|
||||||
"}"
|
"}"
|
||||||
"catch (e) {"
|
"catch (e) {"
|
||||||
"try {"
|
"try {"
|
||||||
@@ -162,33 +158,48 @@ public:
|
|||||||
"return \'{\' + objElements + \'}\';"
|
"return \'{\' + objElements + \'}\';"
|
||||||
"}"
|
"}"
|
||||||
"}"
|
"}"
|
||||||
"__wx$stringifyJSON(%s);"
|
"return __wx$stringifyJSON(res);"
|
||||||
"}"
|
"}"
|
||||||
"catch (e) { e.name + \": \" + e.message; }"
|
"catch (e) { return \"__wxexc:\" + e.name + \": \" + e.message; }"
|
||||||
"}"),
|
"}");
|
||||||
m_outputVarName,
|
break;
|
||||||
m_outputVarName,
|
case JS_OUTPUT_RAW:
|
||||||
m_outputVarName,
|
code += wxASCII_STR("return res;");
|
||||||
m_outputVarName,
|
break;
|
||||||
m_outputVarName
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
return m_outputVarName;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const wxString& GetUnwrappedOutputCode() { return m_outputVarName; }
|
code +=
|
||||||
|
wxASCII_STR("} catch (e) { return \"__wxexc:\" + e.name + \": \" + e.message; }"
|
||||||
|
"})()");
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
// Execute the code returned by this function to let the output of the code
|
// Extract the output value
|
||||||
// we executed be garbage-collected.
|
//
|
||||||
wxString GetCleanUpCode() const
|
// Returns true if executed successfully
|
||||||
|
// string of the result will be put into output
|
||||||
|
// 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);
|
||||||
};
|
};
|
||||||
|
@@ -371,76 +371,41 @@ bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType type) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::RunScriptSync(const wxString& javascript, wxString* output) const
|
bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output) const
|
||||||
{
|
{
|
||||||
__block bool scriptExecuted = false;
|
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING);
|
||||||
__block wxString outputStr;
|
|
||||||
__block bool scriptSuccess = false;
|
__block int scriptResult = -1;
|
||||||
|
__block wxString result;
|
||||||
|
|
||||||
// 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());
|
result.assign(wxCFStringRef(error.localizedDescription).AsString());
|
||||||
|
scriptResult = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ([obj isKindOfClass:[NSNumber class]])
|
if (obj)
|
||||||
{
|
result.assign(wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]));
|
||||||
NSNumber* num = (NSNumber*) obj;
|
scriptResult = 1;
|
||||||
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num));
|
|
||||||
if (numID == CFBooleanGetTypeID())
|
|
||||||
outputStr = num.boolValue ? "true" : "false";
|
|
||||||
else
|
|
||||||
outputStr = wxCFStringRef::AsString(num.stringValue);
|
|
||||||
}
|
}
|
||||||
else if (obj)
|
|
||||||
outputStr.assign(wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]));
|
|
||||||
|
|
||||||
scriptSuccess = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptExecuted = true;
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Wait for script exection
|
// Wait for script exection
|
||||||
while (!scriptExecuted)
|
while (scriptResult == -1)
|
||||||
wxYield();
|
wxYield();
|
||||||
|
|
||||||
if (output)
|
if (scriptResult == 0)
|
||||||
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)
|
if (output)
|
||||||
*output = result;
|
output->assign(result);
|
||||||
result.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
RunScriptSync(wrapJS.GetCleanUpCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.empty())
|
|
||||||
{
|
|
||||||
wxLogWarning(_("Error running JavaScript: %s"), result);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return true;
|
return wxJSScriptWrapper::ExtractOutput(result, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
||||||
|
Reference in New Issue
Block a user