INPUT, WIDGET and custom elements in h-smile core

What is a difference between <input> and <widget> elements [in h-smile core]?

<input> is intrinsically display:inline-block element and <widget> is intrinsically display:block element.

So <input> can live only in some element that has display-model:inline-inside model, in other words in some text container like <p> (paragraph). So if you have markup as:

<div>
  Text: <input type=... />
</div>

engine is forced to wrap content of the div into anonymous text container block.(See: anonymous-block-level ).

In h-smile core that anonymous text container is not so anonymous – it is an element of type <text> (see menu: browse.exe -> Debug -> Element probe on). That <text> is just a <p> but without margins applied by default. You can style that <text> as any other element.

Concept of the Layout Parent Box

For inline-block elements Layout Parent Box is its line box (see: inline-formatting) so when you say height:100%% for inline-blocks their height will be set to the full height of line box.

For block elements Layout Parent Box is a content box of block’s parent (in normal flow). So in this markup:

<div style="height:200px; flow:vertical">
  <widget #first style=height:50%% />
  <widget #second style=height:50%% />
</div>

both widgets will each get 100px height (if no margins, paddings or borders were defined for the widgets).

Can markup parser be extended to support non-standard html elements?

Answer is “yes”.

Let’s say we want htmlayout to support element <checkbox>. We want such element 1) to contain only text (or other inline element) inside and 2) to behave exactly as <input type="checkbox">. To do so we need to define its model for the markup parser. The best place for this information is to put in the Master Style Sheet by using function HTMLayoutAppendMasterCSS().

Here is how such definition may look like:

checkbox {
  display: inline-block;        /* inline with outer text */
  display-model: inline-inside; /* contains only inlines */
  style-set: "std-checkbox";    /* all other visual and behavioral styles are
                                   derived from standard checkbox */
}

After such declaration parser will know how to parse such an element and how it shall be placed into the DOM.

Note: all custom elements shall be XML compatible in other words properly closed. So for this case our checkbox can appear only as <checkbox /> or <checkbox>some text</checkbox> in markup.

For an example of HTMLayoutAppendMasterCSS function use see htmlayoutsdk/wtl/browse/browse.cpp, function _tWinMain().


This article was prepared in Sciter/<richtext> editor.

JavaScript. Private members (instance variables).

As you know JavaScript has no concept of private members in objects. Objects there are “racks of properties” that anyone can change.

Here is a simple way of making “objects” in JS that have private instance variables. Such variables can be changed only by [public] methods you provide.

Consider following code:

  function CreateMyObject()
  {
    var m_first = 0;
    var m_second = 0;

    var envelope = // our public interface
    {
        getFirst: function() { return m_first; },
        setFirst: function(v) { m_first = v; },
        getSecond: function() { return m_second; },
        setSecond: function(v) { m_second = v; }
    };    
    return envelope;
  }  
  
  var f = CreateMyObject();
  
  var n = f.getFirst(); // calling our methods 

Here we have CreateMyObject() that behaves as a constructor of our object. It returns envelope object that has four methods. Only these methods can update or retrieve state of m_first and m_second variables. There are literally no other ways to access them from anywhere else other than set of methods provided.

Under the hood: In this example each interface method that we’ve created is a closure in fact: such methods have access to environment of outer function (CreateMyObject in this case) so they can access variables in this environment. Making a closure can be a memory expensive operation so avoid their use when you expect many instances of such objects.

Sciter. Working with persistent data (database)

Here is an example of minimalistic application working with DB (persistent data) in Sciter.

Screenshot of DB form.

This sample is using three files:

  1. simple-db-form.htm – main file of our application;
  2. db.tis – open or create database;
  3. form.tis – behavior that handles showing/saving data from list of input elements on the form.

db.tis – open or create database

This file contains single procedure that will open or create new storage if does not exist:

function openDatabase(pathname = "records.db")
{
  var ndb = Storage.open(pathname);
  if(!ndb.root)
  { 
    // new db, initialize structure
    ndb.root = 
      { // root of our db is an object having single field 'records'
        records: ndb.createIndex(#integer) // main index, int -> item
      };
  }
  return ndb;
}

Structure of our storage is simple – its root node contains single field records of type Index. In our example this index maps integer – number of the record to the record itself – object that may have arbitrary structure.

form.tis – showing/saving data from input elements on a form

// Form handler class
type Form: Behavior
{
  function show(rec)
  {
    if(this.shown) this.save(); // save previously shown record.
    this.shown = rec;
    function load_value(el)
    {
      var name = el.attributes#name;
      el.value = rec[symbol(name)];
    }
    this.select(load_value, "[name]"); 
    // call load_value for each element having "name" defined.
    // De facto this means that form content defines structure of the record.
  }
  function save()
  {
    var shown = this.shown;
    function store_value(el)
    {
      var name = el.attributes#name;
      shown[symbol(name)] = el.value;
    }
    this.select(store_value, "[name]"); 
    // call store_value for each element having "name" defined.
  }
}

This behavior class has two methods:

  • show(rec) – show fields of object rec in fields of the form and
  • save() – stores content of input elements of the form in fields of last shown rec object

simple-db-form.htm – main file of our application

And last part is our main file that defines UI layout and assembles all parts together:

<html>
<head>
  <style>
    form#record 
    { 
      prototype:Form; 
    }
    ...
  </style>  
  <script type="text/tiscript">
    include "form.tis";
    include "db.tis";
    
    var form = self.select("form#record");
    var rec_no = self.select("#rec-no");
    
    var db = openDatabase();
    var no = 0;
    
    function gotoRecNo( n )
    {
      no = n;
      if( no < 0 ) no = 0;
      else if( no >= db.root.records.length ) no = db.root.records.length - 1;
      form.show( db.root.records[no] );
      rec_no.text = String.printf("%d of %d", no, db.root.records.length); rec_no.update();
    }

    function gotoNewRecord() 
    { 
      // create new record 
      var newidx = db.root.records.length;
      db.root.records[ newidx ] = { first:0, second:"", third:"<html><\/html>" };
      gotoRecNo(newidx); 
    }

    // handlers of navigatonal buttons
    function self #first .onClick() { gotoRecNo(0); }
    function self #prev  .onClick() { gotoRecNo(no - 1); }
    function self #next  .onClick() { gotoRecNo(no + 1); }
    function self #last  .onClick() { gotoRecNo(db.root.records.length - 1); }
    function self #new   .onClick() { gotoNewRecord(); }
    
    function view.onLoad()   { if(db.root.records.length) gotoRecNo(0); 
                                        else gotoNewRecord(); }
    function view.onUnload() { form.save(); db.close(); }
    
  </script>  
<head>
<body>
  <h1>Simple DB form</h1>
  <form #record>
    <table>  
      <tr><td>First (number)</td><td><input name="first" type="number"/></td></tr>
      <tr><td>Second (text)</td><td><input name="second" type="text"/></td></tr>
      <tr><td>Third (richtext(html))</td><td><richtext name="third" /></td></tr>
    </table>
  </form>
  <div #nav>
    <button #first title="to first record">|<</button>
    <button #prev title="to prev record"><</button>
    <button #next title="to next record">></button>
    <button #last title="to last record">>|</button>
    <button #new title="create new record">new</button>
    record: <span #rec-no>?</span>
  </div>
</body>
</html>

Done. We have simple form that allows us to create records with text, numeric and richtext (html) fields.


Code above is not the best one from architectural point of view – its goal is to show basic principles, not more.
You can find this sample in [Sciter SDK]/samples/ideas/db/ folder.