Jump to content


website building - 2

web site page flexbox

  • Please log in to reply
9 replies to this topic

#1 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 15 February 2017 - 05:51 AM

This is an addendum to my previous post


The Smart visual components system is based on absolute positioning.

Which is great in many cases for pixel perfect rendering under program control.


This post is about relying on browser capabilities, which means the positioning default is not 'absolute' but 'static' (or 'absolute', or 'fixed') and the browser determines element positioning depending on context.


So to have a certain degree of control, something else is needed.


There are some great css frameworks available based on the flex-box element

and I particularly like 'Frow', hosted on github and available for free


just substitute the frow css file for the app.css file


Frow is a css framework and features basic element positioning on pages.

Works great and contains among other components a grid system as well


Below program (that's all there is to it !) positions a grid and a button

The grid is populated from a database and the button is custom styled

uses W3C.HTML5, W3C.DOM, W3C.CSS, W3C.Console, JElement, W3C.XMLHttpRequest, ECMA.JSON;
//Frow 3 column grid
var h0   := TElement.Create('div', nil, 'frow-container');        //grid container
  var h01  := TElement.Create('div', h0,  'frow centered');       //rows
// columns h011 - h013 created from database                      //column elements
var sql_statement : String;
var encodedstr : String;
var FHttp := JXMLHttpRequest.Create;
  asm @encodedstr = encodeURIComponent('SELECT * FROM testtable limit 5'); end;
  sql_statement := "sql_statement="+encodedstr;
var smscursor : Variant;
var DBRows : Integer;
JGlobalEventHandlers(FHttp).onLoad := lambda(e:JEvent)
  Console.Log('SQL statement executed and cursor ' + e.type + 'ed !');
  smscursor := JSON.parse(FHttp.ResponseText);
  DBRows := smscursor.smsrows.length;
//create 100*5=500 rows
  For var j := 0 to 100 do begin
   For var i := 0 to DBRows - 1 do begin
    var r01 := TElement.Create('div', h01, 'col-md-2-12', smscursor.smsrows[i].user);
               TElement.Create('div', h01, 'col-md-1-12', '<br><br>');
    var r02 := TElement.Create('div', h01, 'col-md-2-12', smscursor.smsrows[i].password);
               TElement.Create('div', h01, 'col-md-1-12');
    var r03 := TElement.Create('div', h01, 'col-md-2-4', smscursor.smsrows[i].pwhint);
    r01.SetProperty('background', 'lightblue');
    r02.SetProperty('background', 'lightgrey');
    r03.SetProperty('background', 'lightgreen');
    r03.SetProperty('border','1px solid lightseagreen');
//add a blank line and a nicely styled button
var p01 := TElement.Create('p', nil, 'p', '&nbsp;');
var d01 := TElement.Create('div', nil, 'div');
  var d011 := TElement.Create('div', d01, 'frow');
    var d0111 := TElement.Create('button', d011, 'button', 'Submit');
    d0111.SetProperty('border','2px solid lightseagreen');
    d0111.SetProperty('color', 'lightseagreen');

it comes out of the box with responsive styling, so this demo changes layout depending on screen size.

Scrolls nicely on mobile too


In some cases may be a good alternative for the standard grid component

  • Igor Savkic likes this

Nico Wouterse

#2 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 15 February 2017 - 02:29 PM

Also check out the ux kitchen sink

uses W3C.HTML5, W3C.DOM, W3C.CSS, W3C.Console, JElement;
//Frow kitchensink
var p0   := TElement.Create('p', nil, 'p');
var ks := TElement.Create('div', nil, 'form-example-contain bottom-margin');
    var ks1 := Telement.Create('div', ks, 'frow centered');
        var ks2 := TElement.Create('div', ks1, 'form-example card-shadow');
            var ks3a := TElement.Create('label', ks2, 'blue', 'Name');
            var ks3b := TElement.Create('input', ks2, 'input');
                ks3b.SetAttribute('type', 'text');
                ks3b.SetAttribute('placeholder', 'Placeholder Text');
            var ks3c := TElement.Create('label', ks2, 'label', 'Disabled Field');
            var ks3d := TElement.Create('input', ks2, 'blue');
                ks3d.SetAttribute('type', 'text');
                ks3d.SetAttribute('placeholder', 'Placeholder Text');
                ks3d.SetAttribute('disabled', 'disabled');
            var ks3e := TElement.Create('div', ks2, 'frow gutters');
                var ks4a := TElement.Create('div', ks3e, 'col-md-1-2');
                    var ks5a := TElement.Create('label', ks4a, 'blue', 'Zipcode');
                    var ks5b := TElement.Create('input', ks4a, 'input');
                        ks5b.SetAttribute('type', 'text');
                        ks5b.SetAttribute('pattern', '\d*');
                        ks5b.SetAttribute('maxlength', '5');
                var ks4b := TElement.Create('div', ks3e, 'col-md-1-2');
                    var ks5c := TElement.Create('label', ks4b, 'inline', 'Color');
                    var ks5d := TElement.Create('select', ks4b, 'my-custom-select inline');
                        var ks6a := TElement.Create('option', ks5d, 'option', 'Red');
                        var ks6b := TElement.Create('option', ks5d, 'option', 'Green');
                        var ks6c := TElement.Create('option', ks5d, 'option', 'Blue');
            var ks3f := TElement.Create('label', ks2, 'blue', 'File Upload');
            var ks3g := TElement.Create('input', ks2, 'input');
                ks3g.SetAttribute('type', 'file');
            var ks3h := TElement.Create('label', ks2, 'blue', 'Text Area');
            var ks3i := TElement.Create('textarea', ks2, 'my-custom-textarea card-shadow', '');
            var ks3j := TElement.Create('div', ks2, 'frow justify-around');
                var ks4c := TElement.Create('button', ks3j, 'blue card-shadow hidden-xs', 'Submit');
                var ks4d := TElement.Create('button', ks3j, 'rounded', 'Submit');
                var ks4e := TElement.Create('button', ks3j, 'my-custom-button', 'Submit');
JGlobalEventHandlers(ks4c.AsNode).onClick := lambda(e:JEvent)
  asm alert('First button'); end;
JGlobalEventHandlers(ks4d.AsNode).onClick := lambda(e:JEvent)
  asm alert('Second button'); end;
JGlobalEventHandlers(ks4e.AsNode).onClick := lambda(e:JEvent)
  asm alert('Third button'); end;

with eventhandlers included



  • Igor Savkic likes this

Nico Wouterse

#3 Igor Savkic

Igor Savkic
  • Members
  • 130 posts

Posted 15 February 2017 - 06:33 PM

Thanks for sharing, this frow system is really impressive, I'll have to try it and apply when possible.                             

It would be great if next SMS update would be fully compatible with it.

#4 warleyalex

  • Members
  • 388 posts

Posted 15 February 2017 - 09:01 PM

Yeap, the visual designer expects the controls to be derived from TW3CustomControl (which brings in a more heavy infrastructure).
It has been said, the upcoming new RTL, jonlennartaasenden has made some changes architectually in the RTL. 
The TW3Component is now the basis for non-visual components, which opens up for a whole new set of lightweight controls 
that can be dragged onto a form. Here is the new inheritance chain:

Personally, I think this approach is a great idea, you could even use a SmartMS Lite IDE alternative, maybe open source.


Unfortunately, they didn't really like of this idea (all bets are on the RAD approach) - the visual designer and "live" rendering of controls. The SmartCL* framework has its strenghts.


BTW, I have already used your approach, that I'd call the "hard core metal smart programming", in several projects, for instance:











Hey, I will wait the next RTL release, and modify the the  SMS Component Generator tool to generate a component template based on the TW3Component class, I hope it will generate plain smart JHTMLElements on the fly in a second :)


  • Nico Wouterse likes this

#5 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 16 February 2017 - 03:12 AM

I've been thinking too of asking to change the IDE so that it caters for other component structures (like the bare-metal JHTMLElements of this post).

Or to be made open source, or having some sort of api to make it more accessible for alternative components


That might drain the scarce resources too much though,

or it might be on the drawing board already

We'll see what happens in the (near) future.


The generator tool would certainly be an asset !

I was looking for your previous version, but it has been removed from the link


By the way (and somewhat unrelated) I also compiled the project for the ux kitchen sink with the command line compiler, and that works just great too.

Nico Wouterse

#6 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 16 February 2017 - 11:57 AM

hmmmmmm (thinking)


These classes form part of SmartCL.Components :


  //Baseclass for custom application target containers
  TCustomAppContainer = class(TW3Component)
  //DIV based application target
  TDIVAppContainer = class(TCustomAppContainer)
  //Document Body container
  TDocumentBody = class(TCustomAppContainer)

Nico Wouterse

#7 warleyalex

  • Members
  • 388 posts

Posted 17 February 2017 - 05:03 AM

Just curious, It look me less than 1 second to clone your kitchen demo http://www.lynkfs.co.../www/main0.html using the generator.

var docFragment := JDocumentFragment( document.createDocumentFragment() ); // contains all gathered nodes

var div_ := JHTMLDivElement( document.createElement('DIV') );
div_.setAttribute("class", "form-example-contain bottom-margin");

var div_0 := JHTMLDivElement( document.createElement('DIV') );
div_0.setAttribute("class", "frow centered");

var div_1 := JHTMLDivElement( document.createElement('DIV') );
div_1.setAttribute("class", "form-example card-shadow");

var label_ := JHTMLLabelElement( document.createElement('LABEL') );
label_.setAttribute("class", "blue");
var text_ := JText( document.createTextNode("Name") );

var input_ := JHTMLInputElement( document.createElement('INPUT') );
input_.setAttribute("class", "input");
input_.setAttribute("type", "text");
input_.setAttribute("placeholder", "Placeholder Text");

var label_0 := JHTMLLabelElement( document.createElement('LABEL') );
label_0.setAttribute("class", "label");
var text_0 := JText( document.createTextNode("Disabled Field") );

var input_0 := JHTMLInputElement( document.createElement('INPUT') );
input_0.setAttribute("class", "blue");
input_0.setAttribute("type", "text");
input_0.setAttribute("placeholder", "Placeholder Text");
input_0.setAttribute("disabled", "disabled");

var div_2 := JHTMLDivElement( document.createElement('DIV') );
div_2.setAttribute("class", "frow gutters");

var div_3 := JHTMLDivElement( document.createElement('DIV') );
div_3.setAttribute("class", "col-md-1-2");

var label_1 := JHTMLLabelElement( document.createElement('LABEL') );
label_1.setAttribute("class", "blue");
var text_1 := JText( document.createTextNode("Zipcode") );

var input_1 := JHTMLInputElement( document.createElement('INPUT') );
input_1.setAttribute("class", "input");
input_1.setAttribute("type", "text");
input_1.setAttribute("pattern", "\\d*");
input_1.setAttribute("maxlength", "5");

var div_4 := JHTMLDivElement( document.createElement('DIV') );
div_4.setAttribute("class", "col-md-1-2");

var label_2 := JHTMLLabelElement( document.createElement('LABEL') );
label_2.setAttribute("class", "inline");
var text_2 := JText( document.createTextNode("Color") );

var select_ := JHTMLSelectElement( document.createElement('SELECT') );
select_.setAttribute("class", "my-custom-select inline");

var option_ := JHTMLOptionElement( document.createElement('OPTION') );
option_.setAttribute("class", "option");
var text_3 := JText( document.createTextNode("Red") );

var option_0 := JHTMLOptionElement( document.createElement('OPTION') );
option_0.setAttribute("class", "option");
var text_4 := JText( document.createTextNode("Green") );

var option_1 := JHTMLOptionElement( document.createElement('OPTION') );
option_1.setAttribute("class", "option");
var text_5 := JText( document.createTextNode("Blue") );

var label_3 := JHTMLLabelElement( document.createElement('LABEL') );
label_3.setAttribute("class", "blue");
var text_6 := JText( document.createTextNode("File Upload") );

var input_2 := JHTMLInputElement( document.createElement('INPUT') );
input_2.setAttribute("class", "input");
input_2.setAttribute("type", "file");

var label_4 := JHTMLLabelElement( document.createElement('LABEL') );
label_4.setAttribute("class", "blue");
var text_7 := JText( document.createTextNode("Text Area") );

var textarea_ := JHTMLTextareaElement( document.createElement('TEXTAREA') );
textarea_.setAttribute("class", "my-custom-textarea card-shadow");

var div_5 := JHTMLDivElement( document.createElement('DIV') );
div_5.setAttribute("class", "frow justify-around");

var button_ := JHTMLButtonElement( document.createElement('BUTTON') );
button_.setAttribute("class", "blue card-shadow hidden-xs");
var text_8 := JText( document.createTextNode("Submit") );

var button_0 := JHTMLButtonElement( document.createElement('BUTTON') );
button_0.setAttribute("class", "rounded");
var text_9 := JText( document.createTextNode("Submit") );

var button_1 := JHTMLButtonElement( document.createElement('BUTTON') );
button_1.setAttribute("class", "my-custom-button");
var text_10 := JText( document.createTextNode("Submit") );

document.body.appendChild( docFragment );

The main advantage to use the DocumentFragments allow to place child elements onto an arbitrary node-like parent (the parent can be a visual smart component or inject directly on the body), allowing for node-like interactions without a true root node.  


Doing so allows developers to produce structure without doing so within the visible DOM.


The main advantage, using the JHTMLElement interfaces - to create node element - is the code insight/completion available in the smart IDE, such parameter/methods hits is available everywhere. We can easily assign event handlers directly on the corresponding JElement node or indirectly via a custom published property.


e.g. Assign event handle on the specific node:

  TProcedure = procedure;

procedure bindEvent(element: Variant; EventType: variant; handler: TProcedure);
  if (element.addEventListener) then
    element.addEventListener(EventType, @handler, false)
    element.attachEvent('on'+EventType, @handler);

procedure teste;

bindEvent(button_1, "click", teste); // button_1 is JElement node 

Unfortunately, the smart generator is not complete, some tags doesn't have the corresponding JElement interface in the w3C.HTML5 unit. 

  • ielite, Nico Wouterse and Igor Savkic like this

#8 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 19 February 2017 - 04:43 AM

Hi Warleyalex


Thanks for your views and sharing


Looks like we've been working along similar lines, 

and obviously you got there sooner 


I particularly like your documentFragment approach, it saves a lot of browser reflows when inserting multiple elements


Your diversification of the different JElement types is more specific and makes for better reading too, although sometimes the generic JElement approach may make life easier.


I started this post as I needed to find out how to produce lightweight web pages, so I'll just add the remainder that I wanted to share in the next day or so

Maybe at some point we can merge some code if that's of general interest

Nico Wouterse

#9 warleyalex

  • Members
  • 388 posts

Posted 20 February 2017 - 02:25 AM

Take a look at this

#10 Nico Wouterse

Nico Wouterse
  • Members
  • 175 posts
  • LocationAustralia

Posted 20 February 2017 - 04:55 AM



I hadn't seen your generator before and couldn't find it when I looked for it


This is great



Nico Wouterse

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

IPB Skin By Virteq