Page 1 of 1

Adv. javascript support -- function keyword

PostPosted: Wed Aug 22, 2007 6:34 pm
by agiletortoise
I'd like to be able to take advantage of some of the more advanced features of Javascript in Servoy. I don't know if this is planned for 4.0, but it would be very powerful if we could extend objects with Prototypes -- or at least declare and assign functions in our code.

For example, I have several generic bit of functionality I want to extend certain forms with -- such as remembering last size/position for dialog forms. If I could extend the form onLoad, I could write a global method like:

Code: Select all
var frm = argument[0];
frm.get_last_size = function{ return [frm.size_w,frm.size_h]; };
frm.get_last_position = function{ return [frm.position_x,frm.position_y]; };


Right now, the Servoy method editor blocks the use of the "function" keyword (even in a literal string!).

It would open up a lot of options to overcome this limitation. Thanks,

greg.

PostPosted: Wed Aug 22, 2007 10:02 pm
by goldcougar
You can use this..

Code: Select all
var simpleScript = new Script('application.output("Do something");');
// and then later to execute the script
simpleScript();

PostPosted: Thu Aug 23, 2007 12:43 am
by agiletortoise
That doesn't really help much, because the best I can tell, I can't return a value from, or pass arguments to, that Script object.

If I put a "return" in the Script object string, I get an "invalid return" exception.

g.

PostPosted: Thu Aug 23, 2007 1:57 am
by goldcougar
You can't directly pass in parameters, or return, but you can use globals, like..

Code: Select all
var simpleScript = new Script('globals.myGlobal = [frm.position_x,frm.position_y]');
// and then later to execute the script
simpleScript();
//then reference globals.myGlobal to get the return value.

Re: Adv. javascript support -- function keyword

PostPosted: Mon Oct 22, 2007 6:26 pm
by troy
agiletortoise wrote:Right now, the Servoy method editor blocks the use of the "function" keyword (even in a literal string!).

True. However, the method editor does not block the use of the "Function" keyword. So....define your function using the new Function constructor. A decent definition of how it is used may be found here, about half-way down the page.

So, following is a simple add function example.
Code: Select all
//adding
var add=new Function('a','b','return a+b')
application.output(add(8,3)) //returns 11

How about we create a function that is used in the definition of another function?
Code: Select all
//any arithmetic operation
var compute=new Function('myOperator','return new Function("a", "b", "return a" + myOperator + "b")')

var multiply=compute('*')
var divide=compute('/')
var subtract=compute('-')

application.output(multiply(8,3)) //returns 24
application.output(divide(8,4)) //returns 2
application.output(subtract(8,3)) //returns 5

And now, what I read as your original need, prototyping. We'll extend Array's default functionality by writing a numeric sort funtion.
Code: Select all
//prototyping any (established) object
Array.prototype.sortNum = new Function('return this.sort(new Function ("a","b","return a-b"))')

var tmp = [5,9,12,18,56,1,10,42,30,7,97,53,33,35,27]

tmp = tmp.sort()   // returns alphabetical sort: 1,10,12,18,27,30,33,35,42,5,53,56,7,9,97
tmp = tmp.sortNum() // returns numerical sort: 1,5,7,9,10,12,18,27,30,33,35,42,53,56,97

A few considerations:
1. Since the actual body of the function is essentially a string (contained within quotes), if your body includes quotes, you need to be creative in stringing together your code in such a way that there is only one type of quote used in each substring, with the other type surrounding it. For example,
Code: Select all
var copyStyles = function(destDoc, sourceDoc)
{
   var links = sourceDoc.getElementsByTagName('link');

   for(var i = 0; i < links.length; i++)
      if(links[i].rel.toLowerCase() == 'stylesheet')
         destDoc.write('<link type="text/css" rel="stylesheet" href="' + links[i].href + '"></link>');
}
turns into
Code: Select all
var copyStyles = new Function('destDoc', 'sourceDoc',
                           "var links = sourceDoc.getElementsByTagName('link');" +
                           "for(var i = 0; i < links.length; i++)" +
                              "if(links[i].rel.toLowerCase() == 'stylesheet')" +
                                 "destDoc.write(" +
                                    "'<link type=" +
                                    '"text/css" rel="stylesheet" href="' +
                                    "' + links[i].href + '" +
                                    '">' +
                                    "</link>');"
                           )
2. Functions defined using the constructor are generally compiled when invoked, which may lead to slower than optimal performance. Although I'm not sure how Rhino handles this.
3. Servoy clearly went out of their way to disable our abilitiy to use functions. Not that that is necessarily reason enough not to use them, it is just a 'warning'.
4. When prototyping, your additions to established objects are similar to globals in that they are persistent until you enter layout mode, quit servoy, etc.

PostPosted: Mon Oct 22, 2007 6:52 pm
by IT2Be
No help now, I know.
But we have been told that Servoy 4.0 will be your friend :)

More Advanced Javascript capabilities planned?

PostPosted: Wed Jan 30, 2008 4:43 am
by Thomas Parry
Since the original post I wonder what there will be in 4.x for the use of the Rhino prototype.

For that matter does anyone know the actual Rhino javascript version in use by Servoy? I think I remember seeing someplace someone suggesting that the javascript is a little ancient and could use a later version.

I am of course hoping that objects and similar could be created so that as developers we are able to better manage our code. For example if we could crate a base class and then some specialized classes without having to repeat methods all over the place like now then I think we can improve our efficiency.

PostPosted: Fri Feb 01, 2008 6:54 pm
by Thomas Parry
I have been playing with Troy's code and want to make it clear that the sample prototype only works as he says in the parentheses "established object". To clarify, this means use an established Servoy object. It does not work for your own.

For example the following code snippet shows that any "established object" can exploit the prototype:

Code: Select all
Array.prototype.add = new Function('a','b','return a+b');
var tmp = [];//any instance of an array will do - we will make it empty
var result = tmp.add(2,7);
application.output('result=' + result);

String.prototype.mult = new Function('x', 'y', 'return x * y');
var temp = '';//any old string will do, but make it empty to conserve resources

var z = temp.mult(5, 9);
application.output('z=' + z);


I reused his example of the Array then used String to show you that it can be applied to other established objects. Also note that the
Code: Select all
var temp = '';
merely instantiates a new object of that type so that we can then use the new function created.

However if one tries this:

Code: Select all
var MyObject = new Object();
MyObject.prototype.add = new Function('a','b','return a+b');


then you will find that at execution that the "prototype" is not defined.

However if we then do this:
Code: Select all
var MyObject = new Object();
MyObject.add = new Function('a','b','return a+b');
application.output(MyObject.add(8,3)) //returns 11


Then the code executes ok. However we have not created a prototype! Only a new function in the Object called MyObject.
This is still useful but not as useful as in creating real prototypes. (If you leave off the var in front of the MyObject declaration then it should be a global).

SO if Servoy could come up with an "empty" established Object, rather than mess around with other objects such as the Array and String that I used here, that has prototype already then we as users could extend it???

Perhaps the adoption of the latest Rhino in release 4.x will allow some other freedoms?

Re: Adv. javascript support -- function keyword

PostPosted: Tue Sep 09, 2008 7:27 pm
by mxvanzant
This worked for me - note the use of the eval() function as well as splitting "function" into "...f" + "unction...":

Code: Select all
jsLib = new Object();
jsLib.exceptionCodes = new Object();
jsLib.exceptionCodes.missingData = "missingData";

var vcode = "jsLib.exception = f" + "unction (code, text) { \
  if(text.length > 5 && text.substring(0,5) == 'i18n:') \
    text = i18n.getI18NMessage(text); \
  this.code = code; \
  this.text = text; \
} \
";
eval(vcode);


Code: Select all
//can now be used like this:
var vex = new jsLib.exception(jsLib.exceptionCodes.missingData, "i18n:lbl.my_message_here");
throw vex;
...

Re: Adv. javascript support -- function keyword

PostPosted: Wed Jul 07, 2010 11:44 am
by BulldogBen
Is prototyping supported in Servoy 5?

Relating to this post of mine: http://www.servoy.com/forum/viewtopic.php?f=3&t=14433...

I am interested in writing a parent method (called Journal), then specialising it for various uses such as Journal.Transfer or Jourlal.VATReturn, etc.

Before I go to the trouble of learning JavaScript prototyping, inheritance, etc I'd like to know the current limitations of Servoy 5.1

With thanks

Ben