Experimenting with the WebSDK

I’m experimenting with WebControlWrapper to see how it works (novice here!) I know it could be done with pure Xojo, but I want to learn how I could use JavaScripts.

I’ve added a HTML5 canvas to SetupHTML and a small javascript to draw some line:

[code]Function SetupHTML() As String
Dim source() as String

source.Append “<canvas id=”"" + self.ControlID + “”" width=""" + “580” + “”" height=""" + “380” + “”" style=""" + “border:10px solid #000000;” + “”">"
source.Append “<script type=”""+ “text/javascript” + “”">"
source.Append “function drawline© {”
source.Append " var ctx = c.getContext("""+ “2d” + “”");"
source.Append " ctx.moveTo(0,0);"
source.Append " ctx.lineTo(200,100);"
source.Append " ctx.stroke();"
source.Append “}”
source.Append “”
Return Join(source, “”)
End Function[/code]

In the Open of WebPage1, I’ve put:

dim javaSource as String = "drawline(Xojo.get('"+ self.ControlID + "'))" ExecuteJavaScript(javaSource)

The error I get is:

Could not execute returned javascript: Cannot read property 'setStyle' of undefined
Source: var langdir = document.getElementsByTagName('body')[0]; if(langdir) { langdir.removeAttribute('dir'); }
var langdir = document.getElementsByTagName('body')[0]; if(langdir) { langdir.setAttribute('lang','nl'); }

Xojo.createNamespace("example.abwebcanvas");
Xojo.controls['ErKsmMDV'].setStyle(null);
Xojo.controls['ErKsmMDV'].refresh();
document.getElementById('ErKsmMDV').style.minWidth = '600px';
document.getElementById('ErKsmMDV').style.minHeight = '400px';
document.getElementById('ErKsmMDV').style.minWidth = '600px';
document.getElementById('ErKsmMDV').style.minHeight = '400px';

Xojo.controls['ErKsmMDV'].setCursor('inherit');
Xojo.controls['ErKsmMDV'].refresh();
Xojo.controls['ErKsmMDV'].setEnabled(true);
Xojo.controls['ErKsmMDV'].refresh();
Xojo.controls['ErKsmMDV'].object().removeAttribute('title');
Xojo.controls['ErKsmMDV'].refresh();
Xojo.controls['ErKsmMDV'].setVisible(true);
Xojo.refreshControl('X7tdmEXn');
Xojo.controls['ErKsmMDV'].object().style.zIndex = '1';
Xojo.controls['ErKsmMDV'].refresh();
drawline(Xojo.get('ErKsmMDV'))
new frameworkObject('ErKsmMDV',['Close','Open','Shown']);
Xojo.controls['ErKsmMDV'].setEnabled(true);
Xojo.view.showPage('ErKsmMDV');
document.title = "Untitled";

Xojo.view.dismissLoader();

The test project if someone wants to dive into the full code:
http://gorgeousapps.com/ABWebCanvasTest.zip

Thanks in advance for helping me understand this!

Have you read the WebSdk docs?

Actually I did. But from reading your reply I must be missing something really basic here @Greg O’Lone :slight_smile:

Back to the book I guess…

I give up! And I’m really not a quitter but after 6 hours not finding something that is doable in html in 6 seconds I’m really frustrated. (mostly at myself for not finding it, but for me puzzeling time is over and it’s time to be productive again with the old html…).

Here is my latest try (resulting in a ‘syntax error’ in the browser, whatever that means in this context)

in SetupHTML:

  Dim source() as String  
  source.Append "<canvas id=""" + self.ControlID + """ width=""" + "580" + """ height=""" + "380" + """ style=""" + "border:10px solid #000000;" + """></canvas>"  
  Return Join(source, "")

In SetupJavaScriptFramework:

  Dim source() as String
  source.Append "<script>"
  source.Append "function drawline() {"
  ' commented this all out just in case the syntax error was here...
  'source.Append "   var c = document.getElementById('" + self.ControlID + "');"
  'source.Append "   var ctx = c.getContext(""""2d"""");"
  'source.Append "   ctx.moveTo(0,0);"
  'source.Append "   ctx.lineTo(200,100);"
  'source.Append "   ctx.stroke();"
  source.Append "}"
  source.Append "</script>"
  Return Join(source, "")

In Shown event:

  dim javaSource as String = "drawline()"
  ExecuteJavaScript(javaSource)

Result:

Could not execute returned javascript: syntax error
Source: var langdir = document.getElementsByTagName('body')[0]; if(langdir) { langdir.removeAttribute('dir'); }
var langdir = document.getElementsByTagName('body')[0]; if(langdir) { langdir.setAttribute('lang','nl'); }

Xojo.createNamespace("example.abwebcanvas");
<script>function drawline() {}</script>
new frameworkObject('QbIbAE3Q',['Close','Open','Shown']);
Xojo.controls['QbIbAE3Q'].setEnabled(true);
Xojo.view.showPage('QbIbAE3Q');
document.title = "Untitled";

Xojo.view.dismissLoader();

And I get It’s me and not Xojo, but this way seems so logic to me, I have no idea how to do it otherwise :frowning:

First of all, in your SetupJavascriptFramework event, don’t include the tags. You should only be returning javascript code there.

More importantly, the reason for your namespace is for you to put your code in there, so your function should be defined like this:

XojoCustom.example.abwebcanvas.drawline = function() {

And when you go to call it, do this:

ExecuteJavascript("XojoCustom.example.abwebcanvas.drawline()")

Also since you haven’t specifically said so, make sure you add the following code to SetupCSS:

styles(0).value("visibility") = "visible"

Otherwise the control will not be visible.

[quote=127807:@Alain Bailleul]The test project if someone wants to dive into the full code:
http://gorgeousapps.com/ABWebCanvasTest.zip
[/quote]

All I had to do was to comment out the executejavascript in the Open event of ABWebCanvas1 and the JavaScript error went away :

dim javaSource as String = "drawline(Xojo.get('"+ self.ControlID + "'))" //ExecuteJavaScript(javaSource)

I am not a specialist of JavaScript but somehow I am not sure your code is right.

Why not have a look at http://www.p01.org/releases/Drawing_lines_in_JavaScript/

Could be also that you forgot Me. in front of ExecuteJavascript. This works perfectly :

me.ExecuteJavaScript("alert(""I am an alert box"");")

Thanks a lot Greg! Sorry for sounding so angry in my post, but it was driving me nuts.

I have been close several times from your solution, but had a wrong assumption about the namespace. I thought when I defined JavascriptNamespace, Xojo would take care of the rest and I didn’t need to repeat it any more.

On the script tags, I had mixed (browser) errors that gave me the impression they were needed, but it was the namespacing.

Yes, forgot to mention I did use the visibility thing.

Made the changes you suggested and now it works like a charm.

Thanks again!

Thanks for the link Michael. I’ll check it out.

I know it worked without the ExecuteJavaScript() statement, but that was the line I needed to get working (and understand) in the first place :slight_smile:

We really can’t tell what you need to do in terms of Javascript. The namespace is there so we can define it on the client side and help developers to not crash into one another with their controls (and we reserve the right to start validating them in the future, so make sure you register one and start using that), but it is still up to you to use it properly. Otherwise we’d have to analyze your code at runtime and risk getting it completely wrong. :stuck_out_tongue:

OK, I am trying to do a very similar thing to what Alain was doing, and with the help that Greg offered in this thread (thanks Greg!), I think that I’ve got it mostly working. But I have a couple of questions about namespaces and where to put stuff.

(1) I need to define some global variables (e.g. x, y) in the javascript that I set up in SetupJavaScriptFramework. Do I need to put them in the namespace somehow? “var XojoCustom.example.abwebcanvas.x = 0;” produces a javascript error “Unexpected “”.”"". Simply declaring the global variable as “x” seems to work, but am I going to get in trouble for this?

(2) For the function names, is there some way to collapse XojoCustom.example.abwebcanvas.drawdot() into something simpler, using some kind of “using” clause or something analogous? Function names like this make the javascript very hard to read. (I guess that I could use a “replaceAll” method in the Xojo code to expand some abbreviation in the javascript code before I send it out, but am I missing something simpler?)

(3) I don’t understand when I should be putting javascript into (a) PageSource objects, (b) WebControlWrappers, and/or © ExecuteJavascript methods. Right now, vaguely following the pattern in this thread, I set up my global variables and javascript function declarations in the SetupJavascriptFramework event of a WebControlWrapper, and use the ExecuteJavacript method of that control to call those functions when necessary. That all seems to work, but I am afraid that because I don’t understand why that works that this is going to bite me later. When would I put javascript code into a PageSource object? What kind of code should go in the SetupJavascriptFramework? What kind of code should go in an ExecuteJavascript method? How does it matter whether I use the ExecuteJavascript method of the control, another control (say, a button), or the window? Would code in any of those places still see the javascript I set up in either the PageSource object or the SetupJavascriptFramework event?

Thank you very much for any clarification.

  1. Don’t use globals. If you and another developer do that same thing you’ll overwrite each other’s values.

  2. Please register your own namespace and stop using “example”. That’s reserved for us to make example projects and you may conflict with us in the future.

  3. When defining namespaced variables like this:

var XojoCustom.example.abwebcanvas.x = 0;

Don’t use “var”.

  1. DONT modify the xojo framework with replace all. User namespaces are generated on the fly and don’t exist until runtime. The rest of the framework is off-limits.

  2. To make your code easier to read, you can define a temporary variable:

var s = XojoCustom.yourName.yourControl;

Then you can use “s” from then on in your methods. You’ll need to hang up your code and send it all at once though because as soon as ExecuteJavascript finishes, this variable will go out of scope.

  1. PageSource and controls were the way for users to inject code when the framework was introduced in 2010. WebControlWrapper was added in 2012 as a supported way for developers to add and exchange controls and provided a way for these controls to appear in the layout editor. It certainly is the way forward for building controls.

As far as ExecuteJavascript goes, this method is for sending any commands to the browser and you will likely use it with both PageSource and WebSDK code.

Greg, thank you very much for your comments. Here are some questions/comments about your replies.

  1. What are my alternatives to globals for storing values on the client side that must persist between calls to the javascript functions? These are values that the various javascript functions refer to, and must be on the client side because they are used in tight, CPU-intensive loops that would take too much time to communicate back and forth between the server (this is the whole point for doing computations on the client side).

What I am trying to do is write a physics simulation animation where the client side handles the calculations behind the animation and draws the moving object(s), and the server side handles the user interface for controlling the animation. So, for example, I have a javascript function that moves a physical object a certain distance and then draws it in a javascript canvas, and then sets things up so that browser calls the same function 1/30 of a second later. I need global variables to store the object’s position and velocity between calls to this function. I also need a boolean global variable that the user interface can set to indicate to the javascript that it should stop the animation.

  1. I understand about registering the namespace. I was simply using this as an example namespace already used in this thread.

  2. I don’t understand this. Isn’t “var” how one declares variables in javascript? Or are you saying that

XojoCustom.yourName.yourControl.x = 0;

is how one can define a namespaces numerical variable? Can I namespace my globals this way to avoid collisions with other people?

  1. I would never modify the Xojo framework this way: I wouldn’t even think of doing that, as I am sure that it would break lots of stuff. What I was suggesting was that I could write my own javascript code with “^^” or something like that standing as a shortcut for “XojoCustom.yourName.yourControl.” and then do a replaceAll on my own javascript code before sending the code string to SetupJavascriptFramework. This would just make the code more readable in the IDE.

  2. Thank you – I didn’t know that this was possible in javascript (I am a javascript newbie). But I am not sure that I can use it unless I can define a global variable, because I need for the javascript to be executing continuously and asynchronously with the user interface (as described above).

  3. Thank you – this explanation is helpful and enlightening.

PS. I should say that I am not trying to create a WebControl that I would distribute to other people, but simply trying to make sure that I know how to write these simulation animations in a way that plays nice with the Xojo framework.

I understand. But if you ever want to use other people’s WebSDK controls, or more importantly if you use any of our example projects, you run the risk of things getting overwritten in the XojoCustom.example namespace.

If one of our examples did this:

XojoCustom.example.version = 42;

to define a “global” version variable for our examples, your control would also be using that same namespace and could potentially overwrite the property and cause bad things to happen… Or vice-versa. We might unknowingly overwrite something of yours.

Using your own namespace will save you (and us) a lot of grief in the future, especially if one day you think “hey, this control is pretty awesome, others might want to use this…”

Registering a namespace with us is free. It’s just a matter of sending an email to tech support so we can verify that your choice hasn’t already been used. And it’s a good way to shorten that code by using a 3 or 4 character namespace instead of “example.” Instructions on what to do are in the WebSDK docs which are in the Extras folder next to the IDE on your hard drive.

Thanks very much for your reply, Greg. I completely understand about the importance of using namespaces. But just to be clear, to declare a global-type variable that all my javascript functions can reference and whose value will persist between function calls, I can and should declare it this way

XojoCustom.MyName.MyControl.x = 0;

rather than

var XojoCustom.MyName.MyControl.x;

Then within each javascript function, I can define a local variable

var s = XojoCustom.MyName.MyControl;

and then write stuff like

s.x += s.vx;

to update the value of XojoCustom.MyName.MyControl.x. Have I got this right?

  1. Yes, don’t use var with the namespaced variables.
  2. For a “global” property for all of your controls, you could also define it one level up:
XojoCustom.myName.x = 4;
  1. Yes, you can define a variable like “s” and point it at an object like XojoCustom.MyName.MyControl and use the short name instead, but only during that specific call to ExecuteJavascript. If you need it to persist through several lines of javascript code, be sure to send all of the lines at the same time, even if you have to join them together to do so.

Thank you very much! I’ll give it a try.