Nexacro Platform Script Language

You will apply basic JavaScript syntax when developing a Nexacro-based app. Nexacro offers its own APIs to provide additional features that cannot be achieved with JavaScript. Scripts written in Nexacro can be executed in web browsers and mobile devices directly after they undergo the build process.

This chapter explains the syntactic elements and other noteworthy points that you need to know when writing a script in Nexacro.

Scope

Scope explains issues related to the range of accessible variables. Apps used in business often manipulate a number of screens simultaneously while one variable can be referred to by multiple screens. Therefore, the accurate use of scope lets you exactly access the resources that you want.

Local

If you write the below code on the first line of a Form script, the variable will be given local scope. If this is standard JavaScript code, the scope of the variable will be global. However, Nexacro works differently.

var value0 = 0;

You can find the syntactic differences between standard JavaScript and Nexacro by seeing the below code, which is generated as a result of the build process and will apply to web browsers. The above code will be included in a automatically-created function, making the scope of the variable local.

this.registerScript("TEST.xfdl", function() {
	var value0 = 0;
});

If you want to get a global variable in a Form script, do not use the keyword var when you declare a variable. However, there is a possibility that a global variable can affect the entire app. Therefore, you are recommended to define appropriate scope.

You do not need to define scope when you declare a variable within a function. You also do not need to define scope for a value delivered as a parameter.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
     obj.text = "button";
     var a = 3;
     trace(a); // 3
}

this

When designating the effective scope for items used in Application or the application form, you always need to use "this". You should designate a proper level of scope when referring to properties and Forms, as well as variables.

Variables within the Form are declared as follows:

this.formvalue = 4;

You need to designate the scope even when you declare a function. Moreover, you also need to designate the scope when you reference a variable in a function and the variable has been declared within the relevant Form.

this.formvalue = 4;

this.test = function()
{
     this.formvalue = 3;
     this.parent.value = 3;
     this.parent.parent.value = 3;
}

As for some methods like trace and alert, you can opt for either of the following types according to designated scope: one follows the basic JavaScript syntax while the other is additionally provided by Nexacro. That is to say, calling the alert method will vary markedly depending on whether you do not define scope or you designate scope by specifying this.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
	alert(e.button); // JavaScript
	this.alert(e.button); // Form.alert()
	nexacro.getApplication.alert(e.button); // Application.alert()
}

When declaring a function, you need to designate the scope so that it can be included as a member of a Form or an application.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

When using the eval function to access a Form, this should be used as well.

eval("this.formfunc()");

As presented below, you can declare a function without designating scope. However, such a function will be used globally and may become unsupported later. Therefore, this way of function declaration is not recommended.


function Button00_onclick(obj:nexacro.Button, e:nexacro.ClickEventInfo)

{

...

}

Global

If you do not define scope of a variable or function in a script written in Nexacro, the variable or function will treated as a global member. The below code is an example.

globalvar = 2; 
var globalvar2 = 3;

Even variables used in a function are treated as global when their scopes are not designated. However, variables defined by using the keyword var cannot be used outside a function.

this.test = function()
{
	trace(globalvar); //2
	trace(globalvar2); //3
	
	value = 4;
	var localvar = 5;
}


this.test = function()
{
	trace(value); // 4
	trace(localvar); // ReferenceError: localvar is not defined
}

When a Form includes a script file from outside, it will treat the script file as a function. Therefore, you should be careful when using the keyword var.


Please see the below two sample codes. Code 2 (includecode.xjs.js) shows how the variables defined in the includecode.xjs file are processed after generation. (The generated code may differ according to the version of the platform.)

$r_title(includecode.xjs)
bbb = "bbb";
var ccc = "ccc";
$r_title(includecode.xjs.js)
(function()
{
	return function(path)
	{
		var obj;

		// User Script
		this.registerScript(path, function() {
			bbb = "bbb";
			var ccc = "ccc";
		});

		this.loadIncludeScript(path);
		obj = null;
	};
}
)();

When you declare or call a function, you need to designate the associated scope. Test() and this.test() in the script below calls two different functions respectively. If you call test() without designating the scope, the function declared in global will be called.

this.Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
     test();
     this.test();
}

The functions designated without the scope shown as below will be treated as global.

Button00_onclick = function(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

function Button00_onclick(obj:nexacro.Button, e:nexacro.ClickEventInfo)
{
...
}

You need to designate the scope of a method like transaction(), of which there are two variants: one belongs to the Application object and the other to the Form object.


//application

nexacro.getApplication().exit("");

nexacro.getApplication().transaction("");


//Form

this.close("");

this.go("");

this.transaction("");

If you want to use a certain variable in the scope of an application, the best practice is to register it in AppVariables instead of declaring it as a global variable.

nexacro.getApplication().addVariable("aaa", "TEST");
trace(nexacro.getApplication().aaa); // TEST

Expr

The expr script used in a Grid component can be applied without designating the scope as it is processed based on an internally bound Dataset within Nexacro. However, you should designate the scope to access an unbound Dataset directly.

To use expr in a bound Dataset shown, you do not need to use this as shown here.

<Cell text="expr:Column00"/>
<Cell text="expr:Column00.min"/>
<Cell text="expr:currow"/>
<Cell text="expr:rowposition"/>
<Cell text="expr:getSumNF('col0')"/>
Dataset.filterstr = "Column00=='test'";
Dataset.filter("Column00=='test'");

If you want to designate a Grid object, cell object or bound Dataset component as scope defined within an expr script, you need to use the below variables or selectors.

Grid: comp
Dataset: dataset
Cell: this
<Cell text="expr:this.col"/> <!-- cell -->
<Cell text="expr:dataset.rowcount"/> <!-- binded dataset -->
<Cell text="expr:comp.currentcell"/> <!-- grid -->
<Cell text="expr:dataset.parent.func1()"/> <!-- form -->
<Cell text="expr:comp.parent.func1()"/> <!-- form -->

There are no specific indicators for Forms, so you can use comp.parent or dataset.parent if necessary.

If you use this instead of comp.parent.func() when you access a function in a Form, it will be processed as an error. In an expr script, this means cell.

<Cell text="expr:this.func01()"/>

If a component has expr and text as its property at the same time, the getDisplayText property, which returns the text displayed on the screen, can be used.

this.Button00.text = "text";
this.Button00.expr = "1+1";

trace(this.Button00.text); // "text"
trace(this.Button00.expr); // "1+1"
trace(this.Button00.getDisplayText()); // "2"

lookup

The lookup method is designed to be used when it is difficult to access with the designated scope. For example, you can look up objects or functions with ID names or function names.

The lookup method is used in the actual code as follows.

Form.lookup( strid );
nexacro.getApplication().lookup( strid );
[Component].addEventHandlerLookup( eventid, funcid, target );

Here are additional examples.

// it returns an object relevant to objectid after lookup in this
var obj = this.lookup("objectid");

// it returns a function relevant to fn_onclick after lookup in this
this.lookup("fn_onclick")();

// Event handler handles a function relevant to fn_onclick after lookup in this
btn00.addEventHandlerLookup( "onclick", "fn_onclick", this );

Event Handler

Event handlers to deal with events can be added in the Properties window when using Nexacro Studio, or they can be added within scripts by using methods provided for each component and object as described in this section.

Method

Methods to add/set/delete event handlers are provided in order to handle events within scripts:

addEventHandler( eventid, funcobj, target )
addEventHandlerLookup( eventid, funcstr, target )
setEventHandler( eventid, funcobj, target )
setEventHandlerLookup( eventid, functstr, target )
removeEventHandler( eventid, funcobj, target )
removeEventHandlerLookup( eventid, funcstr, target )

Use appropriate methods to process events according to the scope of functions.

this.btn00.setEventHandler("onclick", this.fn_onclick, this);
this.dataset00.addEventHandlerLookup("onrowposchange", "fn_onchange", this);

It is recommended to use the addEventHandlerLookup, setEventHandlerLookup and removeEventHandlerLookup methods only when they are really necessary since they are likely to affect the performance of an app.

When you create an event through the Properties pane of Nexacro Studio, the event will be written in the form of a string as presented below.

<Button id="Button00" ... onclick="Button00_onclick"/>

The build process will convert the above code into the below JavaScript code by adding the selector this.

this.Button00.addEventHandler("onclick", this.Button00_onclick, this);

Object Type

You can set the object type when you set arguments to the event handler functions. Type is provided internally on Nexacro Studio for development convenience, which is not the JavaScript's standard grammar.

this.Button00_onclick = function(obj:nexacro.Button,e:nexacro.ClickEventInfo)
{
	trace(obj.text);
}

Based on the input type value, Nexacro Studio supports the Intellisense function.

When you convert the relevant code to JavaScript code, delete the type value.

this.Button00_onclick = function(obj,  e)
{
	trace(obj.text);
}

Even though you do not designate the object type, it does not have any effect on executing the app.

The object type is not supported in other functions except the event handler function, where it can have an effect on the app's action.

Setting Property Values

General Properties

You can apply the text property to a button component as follows.

this.Button00.text = "text";
trace(this.Button00.text);

You can use the form of the set_ function used in previous versions as is.

You don't need to modify any scripts you've already created when you change the SDK version applied to the project.

(O) this.Button00.set_text("text");

(O) this.Button00.text = "text";


However, the set_ function may not be supported with respect to the new features.

To set the property value of an object that you've added yourself, use as follows:

<Button myprop="333">

Button00.myprop = "333";

Button00.mytext = "text";

Dynamic Properties

You can import property values using the existing method, but in case of objects whose property values change dynamically, a special get method is provided. For four properties in system objects - CursorX, CursorY, ScreenWidth, and ScreenHeight - you should use these additional methods:

nexacro.System.getCursorX();
nexacro.System.getCursorY();
nexacro.System.getScreenWidth();
nexacro.System.getScreenHeight();

Depending on component types, some properties which are not used cannot be adjusted. For example, if the calendar component type is not spin, you cannot adjust the properties below.

this.Calendar.spindownbutton
this.Calendar.spinupbutton

In the calendar component, the spindownbutton property refers the control property, and the property itself is output as a character string [object ButtonControl].

Other Change Items

Nexacro Methods

Although Nexacro used to support methods not supported by ECMAScript by modifying them, it no longer does. Instead, such functions are now provided as Nexacro methods.

For example, the floor, ceil and round methods that supported two parameters in the math object are no longer available. If you want to use any of these methods, you must use the corresponding Nexacro methods.

//Math.floor( v, digit );
nexacro.floor( v, digit );

//Math.ceil( v, digit );
nexacro.ceil( v, digit );

//Math.round( v, digit );
nexacro.round( v, digit );

Some of object names used as reserved words in JavaScript have been changed.

//new Image();
new nexacro.Image();

Other component class names in TypeDefinition (not duplicated with reserved words) have been changed, such as nexacro.Button. However, you can use the button in the same way you did before.

this.button00 = new Button();
or
this.button00 = new nexacro.Button();

Some of the properties and objects have been changed as they collide with reserved words.


Component.class → Component.cssclass

Export.export() → Export.exportData()

VirtualFile.delete() → VirtualFile.remove()

Operational Mode Change

Some of the items previously not supported by JavaScript, or working differently, have been changed.

<> Comparison operator not supported

<> Comparison operator is no longer supported. If you want to compare other values, use the operator "!=".

Character string processing method change within the switch statement

In the previous version, case "2" and case 2 were processed in the same way within the switch statement. In the present version, these are treated as different values.

Regular expression /g option applying method change

If you apply “replace” to the regular expression instead of the /g option, only one item will be changed. You need to apply the /g option to change entire items.

Restrictions on Object Names

You cannot create a ChildName identical to names of methods/properties or the container members. For example, you cannot designate a button component's ID as "text" since a Form has the text property. The button cannot be created in the following case.

<Form text="formtext">
     <Layouts>
          <Layout>               
               <Button id="text'>

For invisible objects such as Datasets you cannot designate their IDs as property names, such as length, since they are treated as array members. In the following example, the columns cannot be created.

<Objects>
     <Dataset id="Dataset00">
          <ColumnInfo>
               <Column id="length" type="STRING" size="256"/>
          </ColumnInfo>

Restrictions on Variable or Function Names

If a variable or function includes an underbar (_) at the beginning its name, it can collide with the variables or functions registered in the Nexacro libraries. The collision can result in the failure to load the application or cause the app to behave differently from your intention.

For example, the below script will fail to be loaded, and thus nothing will appear on the screen. The reason is that a variable is declared with the name _is_loading, which equals the name of a variable in the Nexacro libraries.

this._is_loading = true;
this.Button00_onclick = function(obj:Button,  e:nexacro.ClickEventInfo)
{
	trace(this._is_loading);
}

Even if a variable or function does not include an underbar (_) in its name, it can collide with the variables or functions registered in the Nexacro libraries.

For example, the below script will fail to create a component, and thus nothing will appear on the screen. The reason is that a function is declared with the name createComponent, which equals the name of a function in the Nexacro libraries.

this.createComponent = function()
{
	trace('createComponent ');
}

Restrictions on External Modules with Window Object

You are sometimes required to register external libraries or JavaScript files as modules. If those modules include a window object, however, loading the relevant project may lead to an error in Nexacro Studio.

Nexacro Studio analyzes and processes the code of the modules when loading a project. If Studio finds a window object in this process, an error will occur because the development tool does not support the object. To avoid such an error, you need to add a branch at the top of the code block as presented below, causing Studio not to process a window object.

if( system.navigatorname != "nexacro DesignMode") 
{	
	if (typeof JSON !== 'object') {
		JSON = {};
	}

	(function () {
...
		})  (window)		
	};