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_UIDelegate;
|
||||
|
||||
bool RunScriptSync(const wxString& javascript, wxString* output = NULL) const;
|
||||
};
|
||||
|
||||
class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory
|
||||
|
@@ -24,18 +24,16 @@
|
||||
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(wxASCII_STR("__wxOut%i"), (*runScriptCount)++);
|
||||
enum OutputType {
|
||||
JS_OUTPUT_STRING, // All return types are converted to a string
|
||||
JS_OUTPUT_WEBKIT, // Some return types will be processed
|
||||
JS_OUTPUT_IE, // Most return types will be processed
|
||||
JS_OUTPUT_RAW // The return types is returned as is
|
||||
};
|
||||
|
||||
wxJSScriptWrapper(const wxString& js, OutputType outputType)
|
||||
: m_escapedCode(js), m_outputType(outputType)
|
||||
{
|
||||
// Adds one escape level.
|
||||
const char *charsNeededToBeEscaped = "\\\"\n\r\v\t\b\f";
|
||||
for (
|
||||
@@ -69,44 +67,42 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Get the code to execute, its returned value will be either the value,
|
||||
// if it executed successfully, or the exception message prefixed with
|
||||
// "__wxexc:" if an error occurred.
|
||||
//
|
||||
// Execute GetOutputCode() later to get the real output after successful
|
||||
// execution of this code.
|
||||
// Either use SetOutput() to specify the script result or access it directly
|
||||
// Using GetOutputRef()
|
||||
//
|
||||
// Execute ExtractOutput() later to get the real output after successful
|
||||
// execution of this code or the proper error message.
|
||||
wxString GetWrappedCode() const
|
||||
{
|
||||
return wxString::Format
|
||||
(
|
||||
wxASCII_STR("try { var %s = eval(\"%s\"); true; } "
|
||||
"catch (e) { e.name + \": \" + e.message; }"),
|
||||
m_outputVarName,
|
||||
m_escapedCode
|
||||
);
|
||||
}
|
||||
wxString code = wxString::Format(
|
||||
wxASCII_STR("(function () { try { var res = eval(\"%s\"); "),
|
||||
m_escapedCode);
|
||||
|
||||
// Get code returning the result of the last successful execution of the
|
||||
// code returned by GetWrappedCode().
|
||||
wxString GetOutputCode() const
|
||||
switch (m_outputType)
|
||||
{
|
||||
#if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT && defined(__WXOSX__)
|
||||
return wxString::Format
|
||||
(
|
||||
wxASCII_STR("if (typeof %s == 'object') JSON.stringify(%s);"
|
||||
"else if (typeof %s == 'undefined') 'undefined';"
|
||||
"else %s;"),
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName
|
||||
case JS_OUTPUT_STRING:
|
||||
code += wxASCII_STR(
|
||||
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||
"else if (typeof res == 'undefined') return 'undefined';"
|
||||
"else return String(res);"
|
||||
);
|
||||
#elif wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
|
||||
return wxString::Format
|
||||
(
|
||||
wxASCII_STR("try {"
|
||||
"(%s == null || typeof %s != 'object') ? String(%s)"
|
||||
": JSON.stringify(%s);"
|
||||
break;
|
||||
case JS_OUTPUT_WEBKIT:
|
||||
code += wxASCII_STR(
|
||||
"if (typeof res == 'object') return JSON.stringify(res);"
|
||||
"else if (typeof res == 'undefined') return 'undefined';"
|
||||
"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) {"
|
||||
"try {"
|
||||
@@ -162,33 +158,48 @@ public:
|
||||
"return \'{\' + objElements + \'}\';"
|
||||
"}"
|
||||
"}"
|
||||
"__wx$stringifyJSON(%s);"
|
||||
"return __wx$stringifyJSON(res);"
|
||||
"}"
|
||||
"catch (e) { e.name + \": \" + e.message; }"
|
||||
"}"),
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName,
|
||||
m_outputVarName
|
||||
);
|
||||
#else
|
||||
return m_outputVarName;
|
||||
#endif
|
||||
"catch (e) { return \"__wxexc:\" + e.name + \": \" + e.message; }"
|
||||
"}");
|
||||
break;
|
||||
case JS_OUTPUT_RAW:
|
||||
code += wxASCII_STR("return res;");
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
// we executed be garbage-collected.
|
||||
wxString GetCleanUpCode() const
|
||||
// Extract the output value
|
||||
//
|
||||
// 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:
|
||||
wxString m_escapedCode;
|
||||
wxString m_outputVarName;
|
||||
OutputType m_outputType;
|
||||
|
||||
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;
|
||||
__block wxString outputStr;
|
||||
__block bool scriptSuccess = false;
|
||||
wxJSScriptWrapper wrapJS(javascript, wxJSScriptWrapper::JS_OUTPUT_STRING);
|
||||
|
||||
__block int scriptResult = -1;
|
||||
__block wxString result;
|
||||
|
||||
// Start script execution
|
||||
[m_webView evaluateJavaScript:wxCFStringRef(javascript).AsNSString()
|
||||
[m_webView evaluateJavaScript:wxCFStringRef(wrapJS.GetWrappedCode()).AsNSString()
|
||||
completionHandler:^(id _Nullable obj, NSError * _Nullable error) {
|
||||
if (error)
|
||||
{
|
||||
outputStr.assign(wxCFStringRef(error.localizedFailureReason).AsString());
|
||||
result.assign(wxCFStringRef(error.localizedDescription).AsString());
|
||||
scriptResult = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ([obj isKindOfClass:[NSNumber class]])
|
||||
{
|
||||
NSNumber* num = (NSNumber*) obj;
|
||||
CFTypeID numID = CFGetTypeID((__bridge CFTypeRef)(num));
|
||||
if (numID == CFBooleanGetTypeID())
|
||||
outputStr = num.boolValue ? "true" : "false";
|
||||
else
|
||||
outputStr = wxCFStringRef::AsString(num.stringValue);
|
||||
if (obj)
|
||||
result.assign(wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]));
|
||||
scriptResult = 1;
|
||||
}
|
||||
else if (obj)
|
||||
outputStr.assign(wxCFStringRef::AsString([NSString stringWithFormat:@"%@", obj]));
|
||||
|
||||
scriptSuccess = true;
|
||||
}
|
||||
|
||||
scriptExecuted = true;
|
||||
}];
|
||||
|
||||
// Wait for script exection
|
||||
while (!scriptExecuted)
|
||||
while (scriptResult == -1)
|
||||
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 (scriptResult == 0)
|
||||
{
|
||||
if (output)
|
||||
*output = result;
|
||||
result.clear();
|
||||
}
|
||||
|
||||
RunScriptSync(wrapJS.GetCleanUpCode());
|
||||
}
|
||||
|
||||
if (!result.empty())
|
||||
{
|
||||
wxLogWarning(_("Error running JavaScript: %s"), result);
|
||||
output->assign(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
else
|
||||
return wxJSScriptWrapper::ExtractOutput(result, output);
|
||||
}
|
||||
|
||||
bool wxWebViewWebKit::AddScriptMessageHandler(const wxString& name)
|
||||
|
Reference in New Issue
Block a user