Working with JavaScript in Morfik applications

Sometimes there are situations that one might prefer to use JavaScript directly inside a Morfik application. For instance, you might have a requirement to integrate with a library that was written in JavaScript.

Morfik provides the ability for you to call hand-written JavaScript from within your Morfik high level code. You can also access Morfik code from within native JavaScript. The idea is to fill in the gaps between currently missing features in the supported OO languages and JavaScript. Using the combination of these two we can benefit from using JavaScript specific features within Morfik projects.

While this is a powerful technique, it should be used sparingly, because when using it you lose all benefits gained by using Morfik compiler, such as error checking and cross-browser compatibility.

Writing Native JavaScript Functions

To define a Native JavaScript Function you add JavaScript directive to a standard function declaration and then insert the native JavaScript code inside a specially formatted comment block that directly follow the declaration of the function. The following example shows a Native JavaScript Function:

FX Code

Procedure ShowMessage(s : String);  Javascript;
(*!
    alert(s);
*)


The JavaScript directive tells the compiler that this is a JavaScript routine. The compiler leaves the code it finds inside the specially formatted comment and does not do any type of error checking or perform referential integrity. The embedded JavaScript code does get obfuscated; however, the function name gets obfuscated by default. You can change this behaviour by adding [’Obfuscate=false’]; just before JavaScript directive.

The example below shows how to set opacity for a browser element. You can copy the code into your Morfik code and call the functions by passing the DOMHandle of any visual control together with an opacity value (in the range of 0-100) to set the element’s opacity, regardless of browser.

FX Code

Procedure SetElementOpacity(element:THTML_ElementExt; opacity: Integer); ['Obfuscate=false']; JavaScript; (*!
    var object = element.style;
    object.opacity = (opacity / 100);
    object.MozOpacity = (opacity / 100);
    object.KhtmlOpacity = (opacity / 100);
    object.filter = "alpha(opacity=" + opacity + ")";
*)
 
Function GetElementOpacity(element:THTML_ElementExt): Integer; ['Obfuscate=false']; JavaScript; (*!
    var object = element.style;
    return (object.opacity);
*)
 
Procedure Content.Button1Click(Event: TDOMEvent);
Begin
    SetElementOpacity(Button1.DOMHandle, 35);
End;

Calling Morfik high-level code from JavaScript

As mentioned above, from time to time you may drop down to JavaScript to perform various operations. In those cases you may want to call a Morfik function or method.

The code sample below shows how to call Morfik Functions from JavaScript.

FX Code

Function AFunctionToCall(x, y: Integer; s: String) : Integer; ['Obfuscate=false','Optimize=false'];
Begin
  Result := x+y;
End;
 
Function GetFuncResult: Integer; JavaScript; (*!
  this.return AFunctionToCall(34, 26, "hello");
*)


There are two key points about the code above that you need to bear in mind. First, the need to make sure that the compiler does not obfuscate the function name by placing the compiler tag 'Obfuscate=false'at the end of the function declaration.

Secondly, the Morfik optimizer is designed to remove code that does not get called anywhere in the application. The optimizer does not analyse any code written in JavaScript. Therefore, it will not see the fact that the function AFunctionToCall is actually used. So, it will remove it. To stop the optimizer from taking the function out, the compiler tag 'Optimize=false' is added in the declaration above. Calling Morfik class methods from JavaScript is more complicated. The complication is caused by the fact that we need to make sure that self/this is set up properly. The code below shows how to open a form from JavaScript.

FX Code

Function MakeMethodPointer (o,m: Pointer): Pointer; JavaScript; (*!
  if(m)
    return function(){
      return m.apply(o, arguments);
    }
  else
    return null;
*)
 
Procedure OpenFormInJavaScript(OpenFormProc : Pointer); JavaScript; (*!
  OpenFormProc('about','popup','');
*)
 
Procedure Content.Button2Click(Event: TDOMEvent);
Begin
    OpenFormInJavaScript(MakeMethodPointer(Xapp, @Xapp.OpenForm));
End;


The complication is caused by the fact that we need to create a special pointer where an instance of an object and its method are bundled together. MakeMethodPointer function just does that. It will return a pointer to the method instance by creating an anonymous JavaScript function that takes care of object method invocation.

Using JavaScript Associative Arrays and Hashmaps

The following is an example of how to implement an associative array in Morfik using JavaScript.

FX Code

function CreateJSArray : TArray; Javascript;
(*!
    var x = {"x" : 22, "y" : false, "z" : "hello"};
    return x;
*)
 
Procedure Content.Button3Click(Event: TDOMEvent);
Var
    MyJSrray : TArray;
Begin
    MyJSrray := CreateJSArray;
 
    ShowMessage(MyJSrray['x']);
    ShowMessage(MyJSrray['y']);
    ShowMessage(MyJSrray['z']);
End;


As you can see we have defined a function called "CreateJSArray" for which the body is written in JavaScript. It returns a native JavaScript Array object (TArray). So we prepare the associative Array inside the "CreateJSArray" function and then consume its content based on the array keys within our normal Pascal environment. Since TArray has all the javascript Array methods defined you can execute any of its routines inside your Morfik code

See Also

Back to top