Where to execute Javascript?

I am trying to create a custom WebControl that displays a canvas in which one can display 3D things using the Glowscript library (see glowscript.org). This seems like it should a simple thing to do, but I am hobbled by an inadequate understanding of both Javascript and the way that the Web SDK works behind the scenes.

The following code works great when it is the only thing in an HTML file:



If one opens this HTML file in a browser, it displays a spinning 3D cube.

So, following suggestions elsewhere on this forum, I created a new WebControlWrapper, and I overrode the HTMLHeader method to load the three libraries (so they only are loaded once per page), using the following code:

//Make sure the libraries only get added to the header once if not IsLibraryRegistered(CurrentSession,JavascriptNamespace,"jquery") then RegisterLibrary(CurrentSession,JavascriptNamespace,"jquery") dim sa() as string sa.Append "<script type=""text/javascript"" src=""http://www.glowscript.org/lib/jquery/2.1/jquery.min.js""></script>" sa.Append "<script type=""text/javascript"" src=""http://www.glowscript.org/lib/jquery/2.1/jquery-ui.custom.min.js""></script>" sa.Append "<script type=""text/javascript"" src=""http://www.glowscript.org/package/glow.2.5.min.js""></script>" return join(sa,EndOfLine.UNIX) end if

I then tried loading the remaining code in (a) the SetupHTML event or (b) in the Shown event (using me.ExecuteJavaScript). I also tried putting the

stuff in the SetupHTML and everything else in the Shown event (with and without the lines). Nothing works (the computer displays a blank screen, which is probably due to some kind a glowscript error).

I am probably making some kind of bonehead error, but I’d appreciate any suggestions about how to make this work. At this point, I just like to get the same spinning cube I do with the plain file. I’d also appreciate any insight about what the first line in the final Javascript is doing, as that might be related. Thanks!

The most likely problem is that the libraries have not reached the browser when you call the initialization code. Check out the LoadLibraries command for more info.

Thanks very much for your reply.

That is plausible. Would I LoadLibraries in the Shown event or in SetupJavaFramework event? Also, I had trouble understanding the Callback part of the LoadLibraries command. Where/how would I define this function? Must I load this function using a WebFile (as in the LoadLibraries example), which seems to be a lot of extra overhead, or can I just supply the code in a string constant somewhere?

I suppose this callback function could raise a server event that in turn could set a boolean property in the Xojo code to let me know that the code has been loaded.

I also suppose that I could load the fourth above as the callback function, but I’d eventually like to be able to modify this runtime, so it probably should not be in the Javascript framework. How might I best load that script for later replacement or modification?

Finally, I really don’t know what to do with the


Have you looked at the WebSDK docs? Some of your questions are answered in the quick start guide.

As far as the callback goes, that’s the name of a JavaScript function to call once all of the libraries have loaded.

There are also some examples in there showing how to load libraries.

Yes, I have indeed looked at the WebSDK docs. I am having these questions after reading the docs very carefully, looking at the examples, and trying multiple things. I am sure that the answers are all there somewhere, but I am missing some kind of mental model of what is going on that will help me interpret the docs and the examples. I am sorry to be such a newbie about this.

OK, I copied code over from the Load Libraries example. My SetupJavaFramework code now reads as follows:

[code]if CommonLibrary = nil then
CommonLibrary = new WebFile
CommonLibrary.Data = CommonLibraryCode
CommonLibrary.Session = Nil //Setting Session to Nil makes the WebFile available to all Sessions.
CommonLibrary.MIMEType = “text/javascript” //Some browsers require the mime type to be set.
end if

// Tell the browser to load the library from the WebFile we specified above, plus the other libraries we need,
// and then call a function within that library, once the browser’s got it.
dim lib1 as string = “http://www.glowscript.org/lib/jquery/2.1/jquery.min.js
dim lib2 as string = “http://www.glowscript.org/lib/jquery/2.1/jquery-ui.custom.min.js
dim lib3 as string = “http://www.glowscript.org/package/glow.2.5.min.js
LoadLibraries(“XojoCustom.tmoore.GSControl.LLCallback”, lib1, lib2, lib3, CommonLibrary.URL)
The code in CommonLibraryCode is:

XojoCustom.tmoore.GSControl.LLCallback = function() { alert('LibrariesLoaded'); }

My JavascriptNamespace is “tmoore.GSControl”

When I run this, the alert is never displayed. However, I have verified in the debugger that the LoadLibraries method is called. I don’t know why this yields a different result than the Load Libraries example. Any ideas?

Sorry, please ignore the previous message. I needed “Xojo.Custom.tmoore.GSControl.LLCallback()” as the first parameter (forgot the parentheses). Duh. This now works. Will continue playing around with things.

OK, I’m making some progress. Loading libraries as described above now works, and I was able to get the control to display and show the rotating cube by putting the following in the Shown event:

dim sa() as string sa.Append "window.__context = { glowscript_container: $(""#glowscript"").removeAttr(""id"") };" sa.Append "var scene = canvas();" sa.Append "var b = box();" sa.Append "function spin() {" sa.Append " b.rotate({angle:0.01, axis:vec(0,1,0)});" sa.Append " rate(100, spin);" // make spin a callback sa.Append " };" sa.Append "spin();" me.ExecuteJavaScript(join(sa, EndOfLine.UNIX))
It is good to have something finally working!

Instead of putting __context in the window object, please place it under your namespace so it doesn’t conflict with other controls.

Thanks for the suggestion. But I have no idea what this line of code actually does – I was simply told that it was necessary to make the glowscript code work. So I also don’t have any idea how to do what you suggest without breaking the glowscript library code. It appears to be some kind of jQuery statement (I think know that much), but does my control have a “__context” property?

It’s unfortunate if they put it there because that’ll mean that you can only have one per site.

Sorry, I am not sure what you mean by “one per site.” One GSControl per web app? per session? per window in the web app? per XojoCloud site?

I’m also having another problem. I’d like to be able to modify aspects of the code above in response to the user manipulating Xojo-created controls. But when I attempt to do something like myGSControl1.ExecuteJavascript(“b.color = color.red”) in response to a control action event, I get a “can’t find variable b” error. I also tried setting up everything except the final “spin();” call in a common library, and then doing a me.ExecuteJavascript(“spin();”) in the Shown event, and I got a “can’t find variable spin” error. I would have thought (particularly in the latter case) that the function spin() and the variable b would have global scope (like other libraries), but apparently not. How could I call the function “spin()” or change the properties of variable b later? I have no problem accessing functions from the glowscript library such as box() or cone(). What makes my library different?

You would be restricted to one GSControl per Xojo session as you are creating one canvas attached to the window per session. You can hijack the canvas of a Xojo webcanvas by running your code in the shown event of a webcanvas.

sa.Append "var scene = document.getelementbyid('" + <XojoWebCanvasName>.ControlID + "_canvas');"

I have built a few websdk controls that require a canvas this way.

I have no idea what GS uses “window.__context” for though.

Edit: Typo

[quote=345002:@Daniel Wilson]You would be restricted to one GSControl per Xojo session as you are creating one canvas attached to the window per session. You can hijack the canvas of a Xojo webcanvas by running your code in the shown event of a webcanvas.

sa.Append "var scene = document.getelementbyid('" + <XojoWebCanvasName>.ControlID + "_canvas');"

I have built a few websdk controls that require a canvas this way.

I have no idea what GS uses “window.__context” for though.

Edit: Typo[/quote]
As I’ve said before, taking over controls may cause you grief in the future. We sometimes refactor things causing control names to change.

Yes, I forgot to mention, being unexperienced in Javascript and HTML a hijack like this may save you some time if you are willing to tweak it between versions of Xojo but, the control should never be distributed.

I ended up building my own canvas control as I needed more control. It wasn’t too difficult. If you are still stuck I might be able to find time to upload an example.

Forum for Xojo Programming Language and IDE. Copyright © 2021 Xojo, Inc.