Custom UI Components

Sciter offers three forms of DOM elements extensibility:

Behaviors

Behavior classes are defined in code as script classes derived from stock Element class.

Declarative behaviors assignment

Declarative behaviors assignment in CSS is made using prototype property:

selector {
    prototype: ClassName url(file.tis);
    /* ... other CSS properties */
}

where:

Behavior class declaration

Behavior is a class derived from stock Element class or other behavior class. Template of such class:

class MyWidget : Element
{
   // instance variables, each element will have its own copy of those
   this var foo = "foo";
   ...
   // class variables, shared by all instances of this class
   var bar = "bar";
   ...

   // life cycle methods:

   // behavior's "constructor", called when element gets this class
   function attached() { /* this is the element */ }

   // behavior's "destructor", called when element looses the class
   function detached() { /* this is the element */ }

   // virtual properties
   property baz(v) { ... }
   // and methods
   function boo() { ... }

   // event handlers:

   // any click
   event click (evt, that) { /* Note: this is the element generated click
                                that is the subsciber element - the
                                one that has MyWidget class. */ }

   // click event on <a class="next"> element
   event click $(a.next) (evt, that) { ... /* Note: this is the a.next
                                      element that generated click */  }
   ...
}

this environment variable

All methods, event handlers and properties are called by runtime with this variable set to the element this class is assigned to.

Aspects

Main problem with Behaviors is that at any given moment of time the element can have only one script class assigned. Aspects allows to overcome such problem by defining set of functions to be called when element gets into the DOM.

Declarative aspect assignment

Aspects are assigned by the aspect CSS property:

  aspect: function-name [ url(of-function-implementation-file) ];

Where "function-name" is fully qualified name of the “aspect” function that is aimed to configure/setup some additional functionality on the element. And the url(...) is file name where the function is defined.

Principles of aspect handling:

The “aspect” function is an ordinary script function that gets called:

  1. with this set to the DOM element satisfying the CSS rule.
  2. strictly once per life time of the DOM element.

The aspect CSS property uses non-standard inheritance – if the element has multiple matching rules with the aspect defined the used aspect property value is a list of all aspects from all matching rules. Thus if you have have these rules (example taken from the Plus engine):

[click] { aspect:Plus.Click; }
[dblclick] { aspect:Plus.DblClick; }

and the element defined in markup as

<b id="clickable" click="..." dblclick="...">text</b>

it will get two calls – Plus.Click() and Plus.DblClick() on it, as if you have the following in your CSS:

#clickable { aspect:"Plus.Click" "Plus.DblClick"; }

The aspect mechanism is actively used by Plus ( /samples/+plus/ ) and Lang ( /samples/+lang/ ) engines in Sciter SDK. Plus provides declarative data binding facilities "a la" AngularJS and Lang is about i18n support.

Parametrized aspect definitions

Aspect assignment can contain parameters defined in CSS:

#chart { aspect: MicroChart.Donut(fill: #f00 #0f0 #00f, thickness:0.2 ); }

This will call MicroChart.Donut function with single object parameter as if the following code is run:

const params = {
  fill: [ color(255,0,0), color(0,255,0), color(0,0,255) ],
  thickness: 0.2
};
MicroChart.Donut(params); // in fact as MicroChart.Donut.call(domElement,params);

If your aspect function supports parameters then it should have the following signature:

namespace MicroChart {
  function Donut(params = {}) {
    // do something with this element ...
  }
}

this way it can be assigned either with or without params in CSS.

Event Handlers

UI programming is all about handling of events of various kinds. In Sciter event handlers are ordinary functions that get assigned to elements in one of following ways:

Event functions

You can define event function in-place and assign it to the DOM element by shift operator:

// basic event handler
elem << event click () { ... }

Note the click name-token above, that is an event defintion having the following format: name[.namespace] [$(selector)] where:

Here is an example of "change" events handling coming from any <input type=text> element inside the document:

elem << event change $(input[type=text]) {
  // this is the input[type=text] so
  var changedValue = this.value;
  ...
}

Event namespaces are used for identification purposes, when you need, for example to unsubscribe particualr group of event handlers:

elem >> ".mygroup"; // remove all event handlers having .mygroup namespace.

Event handling with traditional functions

Element.on("name.namespace", "selector", function ) method of Element class can be used to attach function to the element to handle event given by "name".

And  Element.off(...) is used to unsubscribe event handlers.