Working with JavaScript in Morfik applications
From Morfik Wiki
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.
Contents |
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); *)
| BX Code |
|---|
Private Javascript Sub ShowMessageX(s As String) /*! alert(s); */ |
| CX Code |
|---|
private javascript void ShowMessageX(String s) /*! 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 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;
| BX Code |
|---|
Private Javascript Sub SetElementOpacity(element As THTML_ElementExt, opacity As Integer) :{"Obfuscate=false"} /*! var object = element.style; object.opacity = (opacity / 100); object.MozOpacity = (opacity / 100); object.KhtmlOpacity = (opacity / 100); object.filter = "alpha(opacity=" + opacity + ")"; */ Private Javascript Function GetElementOpacity(element As THTML_ElementExt) As Integer :{"Obfuscate=false"} /*! var object = element.style; return (object.opacity); */ Published Message Sub Button1Click(Event As TDOMEvent) SetElementOpacity(Button1.DOMHandle(), 35) End Sub |
| CX Code |
|---|
private javascript void SetElementOpacity(THTML_ElementExt element, Integer opacity) ["Obfuscate=false"] /*! var object = element.style; object.opacity = (opacity / 100); object.MozOpacity = (opacity / 100); object.KhtmlOpacity = (opacity / 100); object.filter = "alpha(opacity=" + opacity + ")"; */ private javascript Integer GetElementOpacity(THTML_ElementExt element) ["Obfuscate=false"] /*! var object = element.style; return (object.opacity); */ published message void Button1Click(TDOMEvent Event) { SetElementOpacity(Button1.DOMHandle(), 35); } |
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; (*! return AFunctionToCall(34, 26, "hello"); *)
| BX Code |
|---|
Private Function AFunctionToCall(x As Integer, y As Integer, s As String) As Integer :{"Obfuscate=false", "Optimize=false"} result = x + y End Function Private Javascript Function GetFuncResult As Integer /*! return AFunctionToCall(34, 26, "hello"); */ |
| CX Code |
|---|
private Integer AFunctionToCall(Integer x, Integer y, String s) ["Obfuscate=false", "Optimize=false"] { result = x + y; } private javascript Integer GetFuncResult() /*! 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(getSimpleMethodPointer(Xapp, @Xapp.OpenForm)); End;
| BX Code |
|---|
Private Javascript Function MakeMethodPointer(o As Pointer, m As Pointer) As Pointer /*! if(m) return function(){ return m.apply(o, arguments); } else return null; */ Private Javascript Sub OpenFormInJavaScript(OpenFormProc As Pointer) /*! OpenFormProc('about','popup',''); */ Published Message Sub Button2Click(Event As TDOMEvent) OpenFormInJavaScript(MakeMethodPointer(XApp, Ref XApp.OpenForm)) End Sub |
| CX Code |
|---|
private javascript Pointer MakeMethodPointer(Pointer o, Pointer m) /*! if(m) return function(){ return m.apply(o, arguments); } else return null; */ private javascript void OpenFormInJavaScript(Pointer OpenFormProc) /*! OpenFormProc('about','popup',''); */ published message void Button2Click(TDOMEvent Event) { OpenFormInJavaScript(MakeMethodPointer(XApp, &XApp.OpenForm)); } |
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;
| BX Code |
|---|
Private Javascript Function CreateJSArray As TArray /*! var x = {"x" : 22, "y" : false, "z" : "hello"}; return x; */ Published Message Sub Button3Click(Event As TDOMEvent) Dim MyJSrray As TArray MyJSrray = CreateJSArray() ShowMessage(MyJSrray("x")) ShowMessage(MyJSrray("y")) ShowMessage(MyJSrray("z")) End Sub |
| CX Code |
|---|
private javascript TArray CreateJSArray() /*! var x = {"x" : 22, "y" : false, "z" : "hello"}; return x; */ published message void Button3Click(TDOMEvent Event) { TArray MyJSrray; MyJSrray = CreateJSArray(); ShowMessage(MyJSrray["x"]); ShowMessage(MyJSrray["y"]); ShowMessage(MyJSrray["z"]); } |
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

