Memory leak alike condition in script

Consider the following simple markup:

<div.collapsible>
  ...
  <widget.myAspect>...</widget>
</div>

and let’s assume that a) content of this div changes dynamically and widget.myAspect uses the following aspect:

function MyAspect() {
   var container = this.$p(div.collapsible);
   var me = this;
   container.on("collapse", function Foo() { 
      me.doSomething();
   });
}

Note that each time you create <widget.myAspect> the aspect function gets called and  brand new “collapse” event subscription (new instance of function Foo above) gets added to div.collapsible.  Therefore list of subscriptions will grow consuming more and more memory on each DOM change inside the div. Even worse – inner function is a closure that holds me – variable that contains instance of DOM element. So after some time the memory will hold a number of disconnected DOM elements as a pure garbage.

Yes, when the div.collapsible will be removed from the DOM or the window will be destroyed or document reloaded all these dead objects will be freed, but until then your application will demonstrate memory leak alike dynamic.

Thus pay attention on components that subscribe itself to parent’s events. If you do have such situations then consider use of behavior classes instead of aspects and unsubscribe event handlers in detached method. Yet there are other options for that.

Google Maps in Sciter

Demo of using Google Maps in Sciter.

Demo of using Google Maps in Sciter.

Google provides two sets of map APIs:

  • Interactive, browser only widget that provides map navigation with incremental and contiguous update of map regions.
  • Another API is so called static maps. That service provides static map images that can be used in src attributes of <img> or <picture> elements. Despite static nature of such maps they can be used interactively.

Below is an example of using Static Google Maps in Sciter:

Read more…

Using native child windows in Sciter.

Sometimes there is a need of using child windows in Sciter.
For example you would like to use Scintilla editor that is implemented on Windows as a child window component.

You can do that but with the following limitations:

  1. Elements with child window attached cannot appear inside scrollable containers as windows are drawn on top of everything. Only popup element can appear on top of child windows.
  2. Such elements cannot be under CSS transformations. Windows does not support affine transformations on child windows.

For such components to be useful in Sciter we will need to solve three tasks:

  1. Let Sciter know that we want custom functionality on that particular DOM element.
  2. Create such a window and attach it to the DOM element.
  3. Provide some component specific methods for the script to manipulate the component by script code.

To accomplish all three tasks we will need to define our own native behavior.

class editor: public sciter::event_handler 
{
   // ...
public:
   virtual void attached  (HELEMENT he ) //...
   virtual void detached  (HELEMENT he ) //...
}

struct editor_factory: public behavior_factory {

  editor_factory(): behavior_factory("editor") {}

  // the only behavior_factory method:
  virtual event_handler* create(HELEMENT he) { return new editor(); }

};

// instantiating and attaching it to the global list of supported behaviors
editor_factory editor_factory_instance;

We also need to instruct Sciter on which element it shall create an instance of our class editor.

Usually that is done by declaring special element type in CSS:

editor  /* element with tag 'editor' */
{ 
   behavior: editor;  /* will have that behavior */
   display: block;    /* displayed as rectangular block */
   width: *;          /* its width and height will take */
   height: *;         /* all available space inside the container */   
}

Having the above declaration we can define the editor in our markup as:

<body>
  <editor/>
</body>

Creating window and attaching it to the DOM element

When the engine will parse <editor/> element in markup it will find style for it. That style has behavior property defined for the element
so the engine will send SC_ATTACH_BEHAVIOR notification and default SC_ATTACH_BEHAVIOR handler ( see: sciter-x-host-callback.h ) will
request chain of registered behavior factories to create instance of the event_handler for the element. As a result our editor_factory::create() method will be invoked
At the very end the engine will call our editor::attached() method to indicate that the element has the editor attached to it.

Therefore the best place to call ::CreateWindow() Windows function is the attached() method of our behavior.

class editor : 
  public sciter::event_handler
{
public:

  HWND     hwnd;
  HELEMENT self; // note: weak ref (not addrefed)

  editor(): event_handler()
            , hwnd(0)
            , self(0) 
  {}

  virtual void attached  (HELEMENT he ) 
  {
    self = he;
    dom::element el = he;
    hwnd = ::CreateWindow(
                  TEXT("Scintilla"),
                  TEXT(""),
                  WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN | WS_VISIBLE,
                  0, 0,
                  0, 0,
                  el.get_element_hwnd(true), // get element's host window
                  0,
                  ghInstance,
                  0);
    el.attach_hwnd(hwnd); // attach the window handler to the DOM element.
                          // after that the engine will manage window position and dimension
                          // by CSS rules 
  } 

  virtual void detached  (HELEMENT he ) 
  { 
    if(hwnd && ::IsWindow(hwnd))
      ::DestroyWindow(hwnd);
    hwnd = 0;
    self = 0;
    dom::element el = he;
    el.attach_hwnd(0);
    delete this;   // we delete the handler here as no one is using it anymore.  
  }
  ...
} 

The behavior will manage life cycle of our window: it will create the window when DOM will be created and destroy it when the element will be removed from the DOM.

Defining scripting methods

The last task left is to define methods so our script can do something meaningful with the window.

In order to do that we need to define handle_scripting_call() in our behavior but instead of doing it that literally we will use BEGIN_FUNCTION_MAP/END_FUNCTION_MAP that provide
handle_scripting_call implementation for us:

class editor : 
  public sciter::event_handler
{
public:

  HWND     hwnd;
  HELEMENT self; // note: weak ref (not addrefed)

  editor(): event_handler()
            , hwnd(0)
            , self(0) 
  {}

  virtual void attached  (HELEMENT he ) { ... } 
  virtual void detached  (HELEMENT he ) { ... }

// scripting methods bindings
  BEGIN_FUNCTION_MAP
    FUNCTION_0("getText",get_text) // getText()
    FUNCTION_1("setText",set_text) // setText(text:string) 
  END_FUNCTION_MAP

  sciter::value get_text() {
    std::wstring text;
    // GetWindowText(hwnd) & friends here
    return sciter::value(text);
  }  

  sciter::value set_text(const sciter::value& text_val) {
    std::wstring text = text_val.get(L"");
    // SetWindowText(hwnd) & friends here
    return sciter::value(); // returns undefined value, a.k.a. void
  }  
}

This way we have defined our behavior that exposes two methods that we can use in script:

<script type="text/tiscript">
function self.ready() {
  var elEditor = $(editor);
  elEditor.setText("Hello world!"); // calling our native method
}
</script>
<body>
  <editor/>
</body>

In reality you probably will have more native methods defined. Just don’t forget to add their bindings to the FUNCTION_MAP.

And see this discussion about wrapping Scintilla editor.

Tokenizer + ::mark() = syntax colorizer

Here is selfie of syntax (tiscript) colorizer – the text below is a full source code of syntax highlighting routine.
The code has colorized itself:

syntax colorizer

syntax colorizer

Can your browser do that in 40 lines of code?

And here are styles that define style of tokens:

plaintext > text::mark(number) { color: brown; }
plaintext > text::mark(number-unit) { color: brown; }
plaintext > text::mark(string) { color: teal; }
plaintext > text::mark(keyword) { color: blue; }
plaintext > text::mark(symbol) { color: brown; }
plaintext > text::mark(literal) { color: brown; }
plaintext > text::mark(comment) { color: green; }

Easy, no?

And even shorter selfie, colorizer wrapped as an aspect component (referenced from colorizer.css):
colorizer

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

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.