I have a similar problem to the person in this post; I'm trying to extend the cefsimple.exe app included with the chromium embedded framework binaries to include a V8 handler. I implemented the OnContextCreated() method and made sure to extend RenderProcessHandler in the SimpleHandler class. I'm trying to implement a simple window bound variable called test_string; here's what my code looks like;
void SimpleHandler::OnContextCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context)
{
CefRefPtr<CefV8Value> object = context->GetGlobal();
object->SetValue("test_string", CefV8Value::CreateString("this is a test"), V8_PROPERTY_ATTRIBUTE_NONE);
}
But the program never arrives at any breakpoints I add within the method, and the variable is undefined on any webpages I load within the app. I saw that one of the solutions in the other thread is to enable the settings.single_process flag, which i've done, but my code still doesn't reach the breakpoint.
To be clear, I'm accessing the variable on pages with window.test_string.
Make sure that you are sending that CefApp to CefExecuteProcess.
CefRefPtr<SimpleApp> app(new SimpleApp);
// CEF applications have multiple sub-processes (render, plugin, GPU, etc)
// that share the same executable. This function checks the command-line and,
// if this is a sub-process, executes the appropriate logic.
int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
if (exit_code >= 0) {
// The sub-process has completed so return here.
return exit_code;
}
Found this solution here
Have you read through the General Usage guide? Some key points below
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-cefapp
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-processes
The single_process mode is not supported so I've never used it. In general I'd avoid it. The multi process architecture means you need to attach the debugger to the process. The Chromium guide is relevant to CEF in this instance.
https://www.chromium.org/developers/how-tos/debugging-on-windows#TOC-Attaching-to-the-renderer
you need to ensure your App is derived from CefRenderProcessHandler
not SimpleHandler!!!
class SimpleApp : public CefApp
, public CefRenderProcessHandler
{
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) OVERRIDE;
valdemar-rudolfovich says you need to pass instance of SimpleApp in
CefExecuteProcess
Related
I'm developing my project with Blazor Server-side.
While I develop, I used javascript code to implement things that hard to implement by C#.
However, I'm facing something weird situation. (I guess it is problem for javascript)
Suppose there are 2 users(A, B). When 'A' user do some action that call javascript code, if 'B' user into same page, 'A' users action affects to 'B' user.
I implemented web page that have 3d scene with threejs. As I explained above, when User 'A' move some object with mouse event(mousemove, mousedown..), if User 'B' accesses the same page, 3d objects of B are moved to the location where User 'A' moved.
Originally, when user access to web page I developed, 3d objects's position should be 0,0,0.
My Guess
I don't use prototype or class(use variable and functions globally. I'm new to javascript.. )
Javascript runs on server-side(share resources??, If then, how can I solve it)
I'm guessing the javascript would be problem, but if you have any other opinions, would you please share?
Edited
I've solved this problem using DotNetObjectReference.Create(this);
C#
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
//send created instance to javascript
var dotNetObjRef = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("SetObjectRef", dotNetObjRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public async Task enableSomething(bool bEnable)
{
var something = bEnable;
}
//== before edit
//[JSInvokable]
//public static async Task enableSomethingStatic(bool bEnable)
//{
// var something = bEnable;
//}
Javascript
var objectRef;
function SetObjectRef(ref) {
objectRef = ref;
}
//call c# function
objectRef.invokeMethodAsync("enableSomething", true);
It was problem of 'static' method as I guessed.
If you declare C# method called from javascript as 'static' and this method changes something of UI variable, this method can affect another users.
So I create instance of current page and send it javascript and when I need to call C# methods from javascript, I call methods using created instance.
Is there any problem or issue, please share it.
Sorry for my bad English.
JavaScript runs client side only. I don't see how two windows, let alone two users, would share data.
Almost for sure, the problem is that you are injecting a singleton service-- which means the server will use one instance for all users.
If so, you have two choices:
(1) add logic to your singleton service to incorporate users. (For example, a dictionary with UserID/Property name for key, and a column for Value)
(2) go to Startup.cs and change the suspect singleton service to .AddScoped(), which will create a new instance for each user.
For right now, I think the latter solution will solve your problem immediately. However, don't underestimate the value of Singletons-- they'll be very useful for other things.
Calling Javascript functions running inside Rhino from Java is easy enough - that after all is why Rhino was created. The thing I am having trouble establishing is this:
Context: I have a Phonegap CLI (v 6.3.3) Android project (API 19+) where I do a great deal of processing via loadable JavaScript running inside rhino
A Phonegap plugin - which I am creating at the same time as the actual Phonegap app - contains class called Storage which provides public, static, methods such as readFromFile(String fileName), writeToFile(String fileName,String data) etc.
What I want to be able to do is to call Storage.readFromFile etc from my loaded JavaScript code in Rhino.
Just how this should be done is not too clear to me. From the searches I have done thus far it involves using ScriptableObject.putProperty to pass the Java class in question, Storage in my case to JavaScript. However, how this should be done and then how it should be used at the JS end leaves me rather confused.
I would be most grateful to anyone here who might be able to point me in the right direction
Given that Rhino has less than 100 followers here it should perhaps come as little surprise that this question was not answered. In the mean time I have managed to find the solution myself and it turns out to be very simple. I share it below for the benefit of anyone else running into this thread.
My Storage class is very simple. It goes something like this
public class Storage
{
public static boolean haveFile(){}
public static boolean readFromFile(String fname){}
...
}
When I call Javascript from Java via Rhino I simply pass a new instance of the Storage class as the last of my function parameters
Context rhino = Context.enter();
Object[] functionParams = new Object[] {"Other parameters",new Storage()};
rhino.setOptimizationLevel(-1);
try
{
Scriptable scope = rhino.initStandardObjects();
String rhinoLog = "var log = Packages.io.vec.ScriptAPI.log;";
String code = /*Javascript code here* as shown separately below/;
rhino.evaluateString(scope, rhinoLog + code, "ScriptAPI", 1, null);
Function function = (Function) scope.get("jsFunction", scope);
Object jsResult = function.call(rhino,scope,scope,functionParams);
}
where the Javascript code is
function jsFunction(a,s)
{
//a - or a,b,c etc - here will be the "other" parameters
//s - will be the instance of the Java side Storage class passed above
//now you can do things like
s.writeToFile('fileName','fileData');
var fd = s.readFromFile('fileName');
s.dropFile('fileName');
...
}
I´m using code splitting in GWT to reduce the size of the initial JavaScript.
While my application initializes, I want to prefetch the other (bigger) part of my code as explained in the docs (www.gwtproject.org/doc/latest/DevGuideCodeSplitting.html).
private void doSth(final boolean prefetch) {
GWT.runAsync(new RunAsyncCallback() {
public void onFailure(Throwable caught) {
Log.error("Loading the code failed!");
}
public void onSuccess() {
if(prefetch)
return; //do nothing. just a prefetch
//here is the loaded code
}
});
}
But I cannot recognize a performance improvement. As I analyzed the browser logs, I recognized, that the request for loading the JavaScript is not marked as XHR. Does GWT load the code of a split point synchronously?
The performance improvement is in the initial downloaded code, assuming nothing else references that code. If anything else does the work of //here is the loaded code, then there will be either very little or no code to break out into a separately downloaded JS file.
This feature can be disabled in several ways, including by using dev mode or setting a compiler flag to skip this process. In this case, yes, the split point runs synchronously, since it makes no sense to wait. Additionally, after the file has been loaded once, it does not need to be loaded the next time the code is invoked within the same page load.
If your server is set to cache correctly, then after the first visit the savings is even smaller since there is no download to do - you only save the time taken to parse that code into the browser's JS VM.
But beyond that, we're going to need more information.
Here's a quick demo showing how the split point can be written with a little more meat to it, and letting you use your browser to notice how the split point code was brought in separately.
public class SampleEntryPoint implements EntryPoint {
public void onModuleLoad() {
Label label = new Label("Hello, World!");
label.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
GWT.runAsync(new RunAsyncCallback() {
public void onFailure(Throwable var1) {/*ignore*/}
public void onSuccess() {
Window.alert("Clicked, and loaded in split point!");
}
});
}
});
RootPanel.get().add(label);
}
}
Code and sample:
https://viola.colinalworth.com/proj/755e224e7f48a047703d44eb6903d926/project/client/SampleEntryPoint.java
Standalone sample:
https://viola.colinalworth.com:444/compiled/755e224e7f48a047703d44eb6903f76c/
When you load this page, the nocache file loads, as does the initial download (as seen through Chrome's inspector's Network tab):
Then, when you click the Label widget, the onClick fires which triggers the runAsync and downloads the extra split point (plus the "leftover" fragment):
After those two new entries have been added to your Network tab, you see the alert message appear. Subsequent clicks do not result in this slight delay, nor do they force this extra JS to download again.
Also note that these are not loaded as AJAX/XHR calls, but as a script tag to be added to the page. Clicking on the details in the Initiator column (not pictured) leads to this (formatted for readability):
function fb(a) {
var b, c, d;
d = (bb(), window);
b = d.document;
c = b.createElement('script');
(!!a.a || a.b) && cb(c, a.a, a.b);
eb(c, a.c);
(b.head || b.getElementsByTagName('head')[0]).appendChild(c);
return c
}
Getting through the obfuscated code, we see that a <script> tag is created, and appended to the <head> of the page.
Digging in deeper, we can find that the AsyncFragmentLoader.LoadingStrategy interface describes how to go get this fragment, and that com/google/gwt/core/AsyncFragmentLoader.gwt.xml wires this by default to XhrLoadingStrategy. However, both the xs and xsiframe linkers change this, to CrossSiteLoadingStrategy and ScriptTagLoadingStrategy respectively. And as of recent versions of GWT (you didn't specify, so I'm assuming you are using a recent version), the xsiframe linker is the default. From Core.gwt.xml:
<add-linker name="xsiframe" />
We can customize this by switching to the old linker, or just replacing the strategy. Note that switching the an XHR strategy will prevent cross-domain loading from working correctly (such as SuperDevMode), so be careful with this.
Much as AsyncFragmentLoader.gwt.xml wired the interface to XhrLoadingStrategy, and CrossSiteIframeLinker.gwt.xml changed it to ScriptTagLoadingStrategy, we can change it back. We create a rule that replaces LoadingStrategy with XhrLoadingStrategy, and list it after our GWT inherits statements in our .gwt.xml file:
<replace-with class="com.google.gwt.core.client.impl.XhrLoadingStrategy">
<when-type-is class="com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadingStrategy" />
</replace-with>
This is what the old default used to rely on as part of the std linker (com.google.gwt.core.linker.IFrameLinker), though this is no longer encouraged and may be removed in a later release.
I am refactoring a rather large JS file that contains many unrelated methods into something that will regroup the methods together according to their usage, and renaming some of them as needed (to prevent misleading names).
However, most of the web pages that actually use this code are spread across different code branches, preventing me from doing a simple find&replace. I could do it in all the different branches, but that requires doing maintenance in 30+ branches at the same time, or probably forgetting to perform the renaming once the change is merged in the other branches (by me or other team members).
If this was C#, I could just mark the method with [Obsolete] and it would flag the necessary changes as needed, so I am looking for something somewhat equivalent. I will still provide functionality with the old interface for a while by just redirecting the calls to the new methods, but I'd like to "force" people to switch to the new interface as they work on the pages for other reasons.
Is there any other way to do something similar, besides adding a debugger;
statement and a verbose comment to every method so that it breaks when developing but not in production?
There are a couple of things you can do in a transition period.
Add the #deprecated JSDoc flag.
Add a console warning message that indicates that the function is deprecated.
A sample:
/**
* #deprecated Since version 1.0. Will be deleted in version 3.0. Use bar instead.
*/
function foo() {
console.warn("Calling deprecated function!");
bar();
}
Here's what we've found for Visual Studio 2013 : http://msdn.microsoft.com/en-us/library/vstudio/dn387587.aspx
It's not tested yet as we haven't made the switch, but it looks promising.
In the meantime, I am inserting a flag at page load depending on context such as :
<%
#if DEBUG
Response.Write("<script type=\"text/javascript\"> Flags.Debug = true; </script>");
#endif
%>
and then I call a method that throws an error if the flag is true, or redirect to the new call if it is in release configuration.
function obsolete(oldFunc, newFunc) {
const wrapper = function() {
console.warn(`WARNING! Obsolete function called. Function ${oldFunc.name} has been deprecated, please use the new ${newFunc.name} function instead!`)
newFunc.apply(this, arguments)
}
wrapper.prototype = newFunc.prototype
return wrapper
}
I want only one folder choose dialog to be opened at any one time.
Once the user selected the folder an event will be fired inform the javaScript of the selected folder.
To open the dialog i included the code from the following gist in my project
DialogManager abstraction for FireBreath
pluginAPI cpp
I maintain a global pointer to the plugin so its functions can be called from any context
Q: is this the best way?
#include "DialogManagerWin.h"
pluginAPI * g_thePlugin;
I set it in the pluginAPI CTOR
g_thePlugin = this;
pluginAPI.h
This goes to pluginAPI
this is the event i want to give the javascript the selected folder
FB_JSAPI_EVENT(folderselected, 1, (const std::string&));
the API to call from javaScript:
calls the code from the gist to open the folder selection in another thread to avoid blocking and causing the browser to freeze.
void pluginAPI::SelectFolder(std::string initialFolderPath)
{
FB::PluginWindow* pluginWindow = pluginAPI::getPlugin()->GetWindow();
DialogManager* dlg_mgr = DialogManager::get();
dlg_mgr->OpenFolderDialog(m_host, pluginWindow, folderSelectorCallback);
return;
}
The callback
this callback will be called once the user selected a folder
void folderSelectorCallback(const std::string& folderSelected)
{
g_thePlugin->fire_folderselected(folderSelected);
return ;
}
First of all, there is a difference between the plugin and the root JSAPI object; you're maintaining a global pointer to the root JSAPI object.
No, this is not a good idea and you should never do this.
Secondly, what you probably want to do here is not to fire a JSAPI event but actually to just call an asynchronous callback. There are examples of this in FBTestPlugin and a blog post on the subject.
All you need to do is accept a const JSObjectPtr& callback argument to the js function and then pass that into the callback from the dialog abstraction.
If you're using the abstraction as it is in the gist, it'd look something like this:
void MyPluginAPI::someJavascriptMethod(const FB::JSObjectPtr& callback) {
PathCallback dlgCallback = boost::bind(MyPluginAPI::doCallback, this, callback, _1);
DialogManager::get()->OpenFolderDialog(m_host, getPlugin()->GetWindow(), dlgCallback);
}
void MyPluginAPI::doCallback(const FB::JSObjectPtr& callback, const std::string& path) {
callback->InvokeAsync("", FB::variant_list_of(path));
}
Haven't tested that code exactly, but that should be close.