Only following the example and trying to mimic CefCSharp, i.e. functions from the API are functions that return a JavaScript promise.
Client code looks like this: (C++ code something like this)
- Code: Select all
ptr->AddJavaScriptExecute(
"API = {};"
"API.getData = () => new Promise(function(resolve, reject) { API.getDataInternal(resolve, reject); } );"
);
ptr->AddJavaScriptFunction( "API.getDataInternal",
[&](const TXString& name, const std::vector<TVariant>& args, IJSFunctionCallbackContext* context)
{
TXString result = "return data to JavaScript";
std::vector<TVariant> callArgs;
callArgs.push_back( result ); // add the arguments to be passed to the 'resolve' function
context->Call( args[0], callArgs ); // this relies on the call from the Promise above: args[0] = <the resolve function>; args[1] = <the reject function>;
});
The JavaScript side is something like this:
- Code: Select all
API.getData().then(function(response) {
alert("Success!", response);
});
From the CEF side, its not much different than the example in the documentation. Just careful passing around parameters, so the callbacks to the Renderer process can look it up for the actual execution.
The script and functions that need to be executed and created are being added with a separate message to the Renderer process -- packaged, unpackages and executed inside the V8Context after the message and at OnContextCreated.
- Code: Select all
void CJavaScriptDelegate::ProcesPackage(const CJavaScriptPackage& package, CefRefPtr<CefV8Context> context)
{
for(const auto& code : package.farrCode)
{
CefRefPtr<CefV8Value> ret;
CefRefPtr<CefV8Exception> ex;
context->Eval( code.operator const wchar_t*(), "", 0, ret, ex );
}
for(const auto& itVar : package.fmapVariables)
{
CefRefPtr<CefV8Value> value = CJavaScriptDelegate::GetCefV8Value( itVar.second );
TString name;
CefRefPtr<CefV8Value> object = this->GetOrCreateObject( context, itVar.first, name );
object->SetValue( name.operator const wchar_t*(), value, V8_PROPERTY_ATTRIBUTE_NONE );
}
for(const auto& it : package.fmapFunctions)
{
TXString functionName;
CefRefPtr<CefV8Value> object = this->GetOrCreateObject( context, it.first, functionName );
const wchar_t* szFunctionName = functionName;
const CJavaScriptPackage::SFunctionCallback& callbacKData = it.second;
CefRefPtr<CefV8Handler> funcHandler( new CJavaScriptV8Handler( callbacKData.fRendererCallback ) );
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction( szFunctionName, funcHandler );
object->SetValue( szFunctionName, func, V8_PROPERTY_ATTRIBUTE_NONE );
}
}
CefRefPtr<CefV8Value> CJavaScriptDelegate::GetOrCreateObject(CefRefPtr<CefV8Context> context, const TString& qualifiedName, TString& outName)
{
CefRefPtr<CefV8Value> resultObject = context->GetGlobal();
outName.Clear();
TStringSTLArray nameTokens;
TStringExt::Tokenize( qualifiedName, nameTokens, "." );
size_t tokensCnt = nameTokens.size();
if ( tokensCnt <= 1 )
{
outName = qualifiedName;
}
else
{
// find sub-objects for all but the last one
for(size_t iToken=0; iToken<tokensCnt-1; iToken++)
{
const wchar_t* szName = nameTokens[ iToken ];
if ( resultObject->HasValue( szName ) )
{
resultObject = resultObject->GetValue( szName );
}
else
{
CefRefPtr<CefV8Value> subObj = CefV8Value::CreateObject( nullptr, nullptr );
resultObject->SetValue( szName, subObj, V8_PROPERTY_ATTRIBUTE_NONE );
resultObject = subObj;
}
}
// and the last one goes out as a name
outName = nameTokens[ tokensCnt - 1 ];
}
return resultObject;
}