Model-View-Whatever, the Plus engine for Sciter.

October 20, 2013

Preface

I would say that human history is a history of reinventing "wheels" of various kinds.

This time we see concept of data binding reincarnated with slightly pathetic name Model-View-Controller. Of course, as many people as many meaning they give to the MVC abbreviation but, nevertheless, it is all around basic idea of data binding – you have data (the Model these days) declaratevily bound with UI "controls" (the View). I believe Microsoft’s VisualBasic 4 and its IDE was the very first usable implementation of the idea. There was no Controller concept at that moment so their implementation was quite limiting – while you can implement 90% of your data editing needs using simple declarations you will spend 90% of your design time fighting with the rest of 10% of needed functionality.

The Plus framework for Sciter.

The Plus framework you can find in Sciter SDK is quite compact (400 LOC) and relatively simple implementation of that old data binding concept with controller means.

Note, the Plus is not an attempt to solve every html/css/script UI problem as AngularJS does. It is just a data binding mechanism with the concept of @observing functions (controllers in my interpretation).

Basics

Model in Plus interpretation is some tiscript namespace object that contains data variables (and optionally functions) to be bound with particular container in HTML DOM.

For example if you declare this script:

namespace Data {
  var correspondent = "world"; // variable to be bound
} 

and corresponding markup:

<section model="Data">
   Whom to greet: <input name="correspondent"> ?
   <p>The greeting: Hello <output name="correspondent">!</p>
</section>

and include in your document "plus.css" file you will get live data binding between Data.correspondent data variable and two DOM elements: two ways with input[name=correspondent] and one way (only view) binding with output[name=correspondent]. So when you type something in that input you will see the data also rendered in output element.  To see this alive load sdk/samples/+plus/demos/0-basic-variable-binding.htm in sciter.exe from its SDK.

The model and name DOM attributes.

Note that <section> element contains model="Data" attribute. It instructs the Plus engine to establish data binding between content of this section and members of namsepace Data {} in script. Name of the bound namespace can be any suitable, not just Data.

Any DOM element inside that section[model] may have name attribute defined. On binding initialization the Plus will try to find data element in the model with that name and if such data variable is found it will made two or one way (for <output> elements) binding between .value of that DOM element and the data variable. The name can be compound – may contain ‘.‘ (dot)-separated list of names. This way  you can bind DOM elements with object fields inside the model:

namespace Contact {
  var name = { first: "Albert", last: "Einshtein" };
  var phone = "....";
  ... 
}

and markup:

<form model="Contact" id="contact-details"> 
  <label for="name.first">First name></label> <input name="name.first">
  <label for="name.last">Last name></label> <input name="name.last">
  ...
</form>

Celsius to Fahrenheit convertor.

Controllers, the @observing function decorator.

File plus.tis (the Plus engine implementation) contains declaration of function decorator named @observing. With that decorator you can define functions that will be triggered (called by the engine) when variable(s) they are observing change.

As an example let’s define simple Celsius to Fahrenheit conversion tool that should work in two directions – when you define celcius value it will calculate its fahrenheit representation. And vice versa. Something similar to the form on the right:

First we will define our Data namespace:

      include "../plus.tis"; // model below uses @observing decorator defined in plus.tis  
      namespace Data // our model
      {  
        var celsius = 0; 
        var fahrenheit = 32;
        
        // this function is observing 'celsius' and calculates 'fahrenheit'
        @observing "celsius"
          function toFahrenheit() {
            fahrenheit = celsius * 9 / 5 + 32;
          }
        // this function is observing 'fahrenheit' and calculates 'celsius'
        @observing "fahrenheit"
          function toCelcius() {
            celsius = (fahrenheit - 32) * 5 / 9;
          }        
      }    

Note two functions above: function toFahrenheit() is observing celcius variable. When celcius variable will change, for example as a result of changes in <input|number(celsius)> field, the toFahrenheit() function will be triggered and will set value of fahrenheit variable. As we have another input bound with the fahrenheit variable:

<body model="Data">
  <p><input|number(celsius)>°C and <input|number(fahrenheit)>°F</p>
</body>

we will see in it results of calculation. This works in both directions – from fahrenheit to celcius and from celcius to fahrenheit.

To see this alive load sdk/samples/+plus/demos/1-basic-function-binding.htm sample in sciter.exe.

That’s it for now. In the next article I’ll explain use of repeatable attribute to bind arrays of objects with rpepatable sections and other samples. If you don’t want to wait check other samples in sdk/samples/+plus/demos/ folder of the SDK. They are self descriptive.

TIScript vs JavaScript.Harmony (ECMAScript 6), Part I

June 29, 2013

Filed under: Script,Web Application Techologies — Andrew @ 11:04 am

Variables, block scope

As we know local variables in JavaScript are declared in function scope. That creates many problems and surprises for people who came to JS from other languages using the same Java/C/C++ notation.

Consider sample that follows. Here we create array of 10 functions, each of them shall return idx value it was created with.

var farr = [];
for(var i = 0; i < 10; ++i) {
  var idx = i; 
  farr[idx] = function() { return idx; }
}

If you call functions from the farr array in JavaScript you will get these results:

console.log( farr[5]() ); // -> 9
console.log( farr[2]() ); // -> 9

Surprise? I think so.

And if you run the same code in TIScript you will get results you expect:

stdout.println( farr[5]() ); // -> 5
stdout.println( farr[2]() ); // -> 2

That’s because TIScript uses block scope – all variables declared inside some block { ... } are local to that block.

To "fix" that initial design mistake (IMO) authors of ECMAScript.6 introduced new keyword let that allows to define variables in block scope, so for that sample to work properly you will do this:

var farr = [];
for(var i = 0; i < 10; ++i) {
  let idx = i; // note the 'let' here. idx is in block scope now. 
  farr[idx] = function() { return idx; }
}

Not that perfect of course but at least something.

Constants

TIScript from the beginning supported const keyword – declaration of read only variables:

const mask = "*.tis";

Any attempt to change value of the mask generates an error in TIScript: for local constants – at compile time and for global constants – at runtime.

In JavaScript ‘const’ is introduced in ECMAScript.6 with exactly same meaning.

Default parameters

From the very beginning TIScript supports definition of default values of function parameters:

function person( name = "anonymous", age = null ) {
   return { name: name, 
            age:age };
}

We can call such function without any parameters:

var p = person(); // p.name ->  "anonymous", p.age -> null

ECMAScript.6 introduces exactly the same feature – parameters may have default values in JavaScript when browsers will catch up ECMAScript.6.

Rest parameters

In TIScript when you define function as this:

function foo( a, b, r.. ) { stdout.println(a,b,r) }

and call it as:

foo( 1,2,3,4 );

The r variable will be set to an array [3,4] and a and b will get 1 and 2 values correspondingly.

ECMAScript.6 uses slightly different syntax for the same feature:

function foo( a, b, ...r ) { console.log(a,b,r) } 

Array comprehensions

ECMAScript.6 officially introduces feature named "array comprehensions" – mechanism that allows to declare/initialize arrays using kinda declarative syntax. Array comprehensions came to JS from Python I believe. While in Python notation they probably look OK but in JS syntax the comprehensions are not readable most of the time.

Let’s say we have an array:

var numbers = [1, 2, 3, 21, 22, 30];

and we want to create another array that will have only even numbers. With the comprehensions we can define it as:

var evens = [i for (i of numbers) if (i % 2 === 0)]; 

Not quite readable in my opinion.

In TIScript I would write it as:

var evens = numbers.filter( :i: i % 2 === 0 );

- shorter and so more readable.

TIScript has no array comprehensions at the moment and probably will not have them until I’ll see really good use of them.

Promises/A+ implementation in Sciter2

April 28, 2013

Filed under: Sciter,Script,Source code,Web Application Techologies — Andrew @ 2:22 pm

The Promises, as a concept, is generalization of callback mechanism. This pattern is quite popular these days so Sciter2 SDK contains now (sdk/samples/+promise/) pretty simple (60 lines of code) implementation of the Promises.

The promise is an object that:

  1. maintins list/chain of callback function pairs [onsuccess:function, onfailure:function] by providing .then(onsuccess, onfailure) method;
  2. promise object provides the way to "execute" the chain, either succes or failure callbacks (if an error occurs);
  3. each callback function in the chain receives input (parameters) from output (return [values]) of previous callback in the chain.

To create the promise in Sciter simply do this:

var oath = promise();

The promise() function and promise object

The promise() function in my implementation returns function/object that has .then() method defined on it. So to attach callback functions to the promise you will do this:

oath.then( function( data ) { return [data+1] } ) // #1
    .then( function( data ) { return [data+2] } ) // #2
    .then( function( data ) { stdout.println("success:", data)}, // #3 
           function( reason ) { stderr.println("error:", reason)} );

Now we have promise in variable oath that has three onsuccess functions assigned to it.

When time comes for the promise to be fulfilled, our code will do it by invoking the promise (as it is a function) with its first parameter set to true and with additional parameters that will be passed to the first callback in the chain:

oath(true, 1);

This will call first callback with 1 in data. It will return 1 + 1 -> 2.
That 2 value will be passed to second callback that will return 2 + 2 -> 4.
And finally last callback will just do println:

success:4

To reject the promise we just need to call it with first parameter set to false:

oath(false, "something went wrong!");

This will call our sole onerror callback and we will get:

error: something went wrong!

The promise.when() function, parallel execution

The promise has also defined static function promise.when(...)  that accepts list of promises and return another promise that will be fullfilled/rejected when all input promises will be completed.

function printBandC(b,c) { stdout.println(b,c) }

var BandC = 
    promise.when( self.request(#get-json, urlB),
                  self.request(#get-json, urlC)).then(printBandC);

There are quite many articles about the subject, just google for “Promises JavaScript”

Here is the full source of promise.tis module:

(more…)

Q.tis – micro port of jQuery for Sciter.

March 30, 2013

Filed under: HTML and CSS,Sciter,Script,Source code — Andrew @ 11:04 pm

I’ve published today Sciter 2.0.2.2 with q.tis – micro-port of essential jQuery features.
Here is the list of supported functions.

It is just enough to put include "t.tis"; in your code and any existing DOM function that returns array of elements will
“automagically” produce the q-collection.

In my implementation I am using the fact that functions like Element.selectAll("selector") return array object that is instanceof ElementList.
ElementList as any class is extensible in run-time. So I’ve just added bunch of function ElementList.jqueryMethod() {} to bring that functionality to the Sciter.

The beauty of the approach is that you can use as the q() function (analog of $() in jQuery) as Sciter’s standard $$() to write something like this:

var itemsWithLinks = $$(ul.topics > li).$has(a:link);

to get list of list items that have <a>’s inside.
The same but in classic style and without use of “stringizers”:

var itemsWithLinks = q("ul.topics > li").has("a:link");

You may also find handy jquery-alike event handling. Methods element.on(), element.off(), element.one() and element.trigger() are available as for q-collections as for DOM element instances.

Sciter 2.0.2.0 is out with new TIScript features

March 23, 2013

Filed under: Sciter,Script — Andrew @ 3:50 pm

One of such features added in 2.0.2.0 is support of member variables declarations in classes.

By using this var name = value construction you can define member (instance) variables:

This code:

class Foo {
  this var one = 1, // member variable
           two = 2; // member variable

  function sum() { return this.one + this.two; }
}

var foo = new Foo();
stdout << foo.sum() << "\n";

will output ’3′ even there is no constructor is defined in the class.
Each instance of the class is born with those this.one and this.two variables having their initial values.

If there is other class that inherits such Foo class then it gets member variables declared in its super class as the ones declared in the class iself.

This code:

class Bar: Foo {
  this var three = 3; // member variable

  function sum() { return this.three + super.sum(); }
}

var bar = new Bar();
stdout << bar.sum() << "\n";

will ouput ’6′ as the bar instance contains this.one, this.two and this.three variables.

Making TIScript syntax compatible with CSS.

March 18, 2013

Filed under: HTML and CSS,Sciter,Script — Andrew @ 6:51 pm

Time to time when I need to define some CSS constructs in script I feel myself non-comfortable – CSS and JavaScript/TIScript use different syntax’es.

Consider this code in JavaScript:

  function switchState() 
  {
    element.style.backgroundColor = "rgb(126,0,0)";
    element.style.transform = "rotate(45deg) translate(10px,10px)";
  }

Not so aesthetically pleasing. And not so effective as string parsing is involved.

And yet if for example you will need to get current rotation angle from style, increment it by some value and write it back then you will need to implement non trivial parsing using CSS rules and opposite toString translation for changed rule.

I’ve explored quite many JS frameworks that are capable working with styles – all they have good chunk of parsing CSS code.

But browser already parses the CSS and builds internal structures that represent CSS values. Code is there, why not to reuse it?

One way of dealing with this is to expose CSS internal structures using so called CSSOM. But that’s really too much work and result is still too narrative I would say.

Ideally that should look like this:

  function switchState() 
  {
    element.style.set {
      background-color: rgb(126,0,0),
      transform: rotate(45deg) translate(10px,10px) 
    }
  }

And in principle JS syntax can be extended to support such constructions without conflicts with existing code:

  1. Allow names with hyphens like background-color in object literals.
  2. Allow values with units like 45deg, 10px and the like. That will require new data types in JS but they are handy anyway
  3. Add so called tagged tuples to the language. In terms of CSS this rotate(45deg) is not a function call but rather tuple (data structure with the name). In terms of TIScript this can be written as [rotate:45deg] – one element tuple with the tag ‘rotate’.
  4. Add whitespace as a valid list separator, at least in object literals, so this
       { transform: rotate(45deg) translate(10px,10px) }
    

    will be an equivalent of

       { transform:[rotate(45deg), translate(10px,10px)] }
    

    And that would be pretty much it.

In fact CSS syntax (that may look like a mess sometimes) uses in reality two types of lists and one tuple<2> (in order of precedence):

  1. comma separated lists: background: url(1.png),url(2.png);
  2. white-space separated lists: background: no-repeat url(1.png);
  3. pair-tuples: font: 12pt 10pt/14pt "arial";

But that would be next step. At the moment I am trying to add values with units and whitespace lists…

Next Page »