JavaScript. Private members (instance variables).

March 13, 2008

Filed under: Sciter,Script,Source code,Web Application Techologies — Andrew @ 1:28 pm

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)

March 2, 2008

Filed under: Sciter,Script,Source code,Web Application Techologies — Andrew @ 9:08 pm

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.

XML/HTML tokenizer (or pull parser?)

October 7, 2007

Filed under: Source code — Andrew @ 11:19 pm

Here is source code of my XML/HTML tokenizer: xh_scanner_demo.zip

See my article on CodeProject: HTML/XML scanner/tokenizer

Does not allocate any memory while parsing, extremely fast and compact.

« Previous Page