Jump to content
Sign in to follow this  
lynkfs@gmail.com

shoestring framework

Recommended Posts

I'm sharing a lightweight framework I'm using for a variety of projects.

It sort of sits between the RTL (looking forward to the coming update by the way), where all visual components can be placed pixel perfect, and SMS-created websites where the final layout is determined by the browser.

 

The master object here is based on the JHTMLElement element (see previous posts by me, Laksekjønn and others).

Everything else is derived from this.

 

A couple of the W3C.* and System.* units are used in this framework but none of the SmartCL.* units.

No external or internal CSS file either.

 

The basic TElement constructor in this framework creates the (visual or non-visual) element, sets some basic properties, inserts it on its parent, adds a couple of eventlisteners and makes sure there is at least an empty stylesheet available.

 

constructor TElement.Create(element: String; parent: TElement);
begin

  FElement := JHTMLElement(Document.createElement(element));
  FElement.className := element;
  FElement.id := w3_getUniqueObjId;

  var FElementStyle := JElementCSSInlineStyle(FElement).style;
  FElementStyle.setProperty('visibility','visible');
  FElementStyle.setProperty('display','inline-block');
  FElementStyle.setProperty('position','absolute');
  FElementStyle.setProperty('overflow','auto');

  If parent = nil
    then document.body.appendChild(self.AsNode)
    else parent.AsNode.appendchild(self.AsNode);

  SetBounds(0,0,0,0);

  (self.AsNode).addEventListener("click", @CBClick, false);
  window.addEventListener("resize", @CBResize, false);
//others...

  var s1 = document.styleSheets;
  if s1.length = 0 then begin
    var style := document.createElement("STYLE");
    document.head.appendChild(style);
  end;

end;
Visual components are derived directly from this.

A very lightweight component is f.i. this listbox :

 

unit JListBox;

interface

uses JElement, JPanel;

type
  JW3ListBox = class(TElement)
  private
    ItemCount : integer;
  public
    constructor Create(parent: TElement); virtual;
    Procedure Add(item: TElement);
  end;

implementation

{ JW3ListBox }

constructor JW3ListBox.Create(parent: TElement);
begin
  inherited Create('div', parent);
  ItemCount := 0;
end;

procedure JW3ListBox.Add(item: TElement);
begin
  item.setProperty('width','calc(100% - 4px)');
  item.SetBounds(2, 2 + (ItemCount * item.height) + (ItemCount * 2), item.width, item.height);

  Inc(ItemCount);
end;

end.

usage

 

  var ListBox1 := JW3ListBox.Create(self);
  ListBox1.SetBounds(10, 10, 400, 200);
  ListBox1.setProperty('background-color', 'gold');

  For var i := 1 to 50 do begin
    var Panel0 := JW3Panel.Create(ListBox1);
    Panel0.setProperty('background-color', 'silver');
    Panel0.height := 30;
    Panel0.tag := inttostr(i);
    Panel0.OnClick := procedure(Sender:TObject)
      begin console.log('clicked silver item #' + (Sender as JW3Panel).tag); end;

    var Panel1 := JW3Panel.Create(Panel0);
    Panel1.setProperty('background-color', 'lightgreen');
    Panel1.SetBounds(2,2,26,26);
    Panel1.SetinnerHTML(IntToStr(i));
    Panel1.tag := inttostr(i);
    Panel1.OnClick := procedure(Sender:TObject)
      begin console.log('clicked green item #' + (Sender as JW3Panel).tag); end;

    ListBox1.Add(Panel0);
  end;
These type of components are very lightweight, and easy to construct.

Panels, Buttons, ToolBars, Images, ProgressBars etc don't take long.

 

 

The scaffolding components are the Form and the Application object, both also derived from TElement.

 

unit JForm;

interface

uses JElement;

type
  JW3Form = class(TElement)
    private
    procedure FormInit;
  public
    constructor Create(parent: TElement); virtual;
    procedure ShowForm; virtual;
    procedure ReSize; virtual;
  end;

  TFormClass = class of JW3Form;

implementation

uses Globals;

{ JW3Form }

constructor JW3Form.Create(parent: TElement);
begin
  inherited Create('div', parent);

  SetProperty('border','1px double grey');
  Left := 5; Top := 5;
  setProperty('width','calc(100% - 10px)');
  setProperty('height','calc(100% - 10px)');
  setProperty('background-color','white');

  OnResize := procedure(sender:TObject)
  begin
    screenwidth := window.innerWidth;
    ReSize;
  end;
end;

Procedure JW3Form.ShowForm;
begin
//
end;

Procedure JW3Form.ReSize;
begin
//
end;

end.

usage

 

unit Form1;

interface

uses JElement, JForm, JImage, JButton;

type
  TForm1 = class(JW3Form)
  public
    procedure ShowForm; override;
    procedure ReSize; override;
    Image1 : JW3Image;
  end;

implementation

uses Globals;

Procedure TForm1.ShowForm;
begin
  inherited;

  Image1 := JW3Image.Create(self);
  Image1.setAttribute('src','images/Slide1.png');

  Button1 := JW3Button.Create(self);
  Button1.SetinnerHTML('My Button');
  Button1.OnClick := procedure(Sender:TObject) begin Application.Show('Form2'); end;

end;

end.

and finally Application :

 

unit JApplication;

interface

uses
  JElement, JForm;

type
  JW3Application = class(TElement)
  public
    FormNames: Array of String;
    FormsClasses: Array of TFormClass;       //see JForm: TFormClass = class of JW3Form;
    FormsInstances: Array of JW3Form;
    constructor Create(parent: TElement); virtual;
    procedure AddForm(FormName: String; aClassType: TFormClass);
    procedure Show(FormName: String);
  end;

implementation

uses Globals;

{ JW3Application }

constructor JW3Application.Create(parent: TElement);
begin
  inherited Create('div', parent);

  setProperty('width','100%');
  setProperty('height','100%');
  setProperty('background-color','white');
end;

procedure JW3Application.AddForm(FormName: String; aClassType: TFormClass);
begin
//
  FormNames.Add(FormName);
  FormsClasses.Add(aClassType);
  FormsInstances.Add(nil);
end;

procedure JW3Application.Show(FormName: String);
begin
//
  For var i := 0 to FormNames.Count -1 do begin
    If FormsInstances[i] <> nil then
      FormsInstances[i].SetProperty('display','none');
    If FormNames[i] = FormName then begin
      If FormsInstances[i] = nil then        //form has never been displayed yet
        begin
          FormsInstances[i] := FormsClasses[i].Create(self);
          (FormsInstances[i] as FormsClasses[i]).ShowForm;
        end else begin
          (FormsInstances[i] as FormsClasses[i]).ShowForm;
          FormsInstances[i].SetProperty('display','inline-block');
        end;
    end;
  end;
end;

end.

and usage

 

uses Globals, Form1, Form2, Form3;

//create forms
Application.AddForm('Form1',TForm1);
Application.AddForm('Form2',TForm2);
Application.AddForm('Form3',TForm3);

//show initial form
Application.Show('Form1');

Demo here (http://www.lynkfs.com/Experiments/HtmlElem/test/)

and project-code here (http://www.lynkfs.com/Experiments/HtmlElem/test/index.sproj)

 

 

So why going to the trouble of creating a separate framework ?

The advantages for me is that it is very close to the browser, almost a wrapper around the inbuilt browser functionality, while still maintaining the object pascal syntax.

 

It is also pretty lightweight.

I'm rebuilding a 1500KB web-app using this framework.

Halfway there I can see that the js filesize will be (much) less than half.

 

The other advantage is that the Globals unit defines links to the window and document object.

unit Globals;

interface

uses JApplication;

//framework globals
var Application : JW3Application;
var ScreenWidth : Integer := 0;
var document external 'document': variant;
var window   external 'window':   variant;

implementation

initialization
//
  Application := JW3Application.Create(nil);
end.
This means that asm sections are largely not necessary.

I can just easily write window.alert('alert') instead of asm alert('alert'); end;

 

To be very clear :

This framework covers just a small portion of what SMS natively covers.

However for simple projects it works well enough.

Share this post


Link to post
Share on other sites

Since TW3Form inherits from the TW3CustomControl base class. The smart visual designer expects TW3CustomControl as base class to forms and visual controls. If you rename TElement as base class to TW3CustomControl, and with some extra refactoring then you can use "visual forms" with thin visual controls. Im my experiments, trying to reproduce your example, I've got 18.5K with 4 visual forms.

Share this post


Link to post
Share on other sites

That is a beautiful idea, that makes it possible to use the visual designer as well.

 

I've set up this framework in such a way that it can be used in (almost) the same way as using the normal RTL, although the codebase is complete different.

 

Being able to use the visual designer makes it even more similar, I like that a lot.

 

The footprint as in the size of the resulting js file is indeed quite impressive.

I've rewritten 4 forms of a 10-form web-app of 1350KB and haven't exceeded 50KB yet

That is before minifying it or pushing it through the closure compiler

 

I've made up some more components, it's so easy to do and I'll share them sometime later

If you feel like it, feel free too

 

Cheers

Nico

Share this post


Link to post
Share on other sites

Got it.

It takes a couple of changes to the framework, but nothing major

 

The process to use this framework with the visual designer is as per normal :

- Build one or more packages, say a JPanel

- Add a Form to a project and in the visual designer add a JPanel

- Optionally add an eventhandler in the visual designer (like OnClick)

 

Then code the form as per usual.

 

For anyone interested, these changes and how to apply them can be found here (www.lynkfs.com/Experiments/HtmlElem/visualdesigner/index.sproj)

Share this post


Link to post
Share on other sites

There are two boring minor bugs in Smart IDE, I hope they will fix in some day.

 

a. Make Project External issue

http://forums.smartmobilestudio.com/index.php?/topic/3757-make-project-external-issue/

Steps to reproduce:

open the project "www.lynkfs.com/Experiments/HtmlElem/visualdesigner/index.sproj"

Make Item as External also does not working as expected. ---&gt; the forms .sfm are not created!

 

b. Property 'Angle' 'Opacity' 'Zoom' 'BorderRadius' not found!

Details see at: http://forums.smartmobilestudio.com/index.php?/topic/4068-visual-component-from-tw3movablecontrol/

Since we are using custom ligthweight visual controls, the Smart IDE insist in using these properties;

an workaround would be declaring such as:

published

(* dummy properties :: SmartIDE expects these properties, this is minor bug *)

property Opacity: Integer;

property Angle: Float;

property Zoom: Float;

property BorderRadius: Integer;

 

 

c. Custom components name displayed in the component bar

So, we can not use custom names in the SMS_INSTALL_DIR/packages/Container.spk

The Component name is displayed on the component bar. I would like to use custom name.

 

e.g. Try to replace JW3Panel component name to "Panel"

SmartIDE it will raise a exception "Component Panel does no appear to be available"

 

<SMART>
  <Package version="2" subversion="2">
    <Name>Container</Name>
    <Vendor></Vendor>
    <Created>2015-05-16T22:47:07.275</Created>
    <Modified>2015-05-16T22:47:31.564</Modified>
    <Version>
      <Major>0</Major>
      <Minor>0</Minor>
      <Revision>1</Revision>
    </Version>
    <SmartVersion />
    <Code>
      <Encryption>None</Encryption>
      <Password></Password>
      <Files>
	  
        <File>
          <Name>JElement</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JElement.pas</External>
        </File>	  
	  
        <File>
          <Name>JApplication</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JApplication.pas</External>
        </File>
		
        <File>
          <Name>Globals</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\Globals.pas</External>
        </File>			  	  
	  
        <File>
          <Name>JForm</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JForm.pas</External>
        </File>			  	  
		
        <File>
          <Name>JPanel</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JPanel.pas</External>
        </File>			  
	  
        <File>
          <Name>JListBox</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JListBox.pas</External>
        </File>		

        <File>
          <Name>JImage</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JImage.pas</External>
        </File>		
		

        <File>
          <Name>JToolBar</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JToolBar.pas</External>
        </File>		


        <File>
          <Name>JButton</Name>
          <MediaType>text/pascal</MediaType>
          <External>C:\PROJECTS\HtmlElem2\JButton.pas</External>
        </File>		
		
		
        <File>
          <Name>SmartCL.Forms</Name>
          <MediaType>text/pascal</MediaType>
          <External>SmartCL.Forms.pas</External>
        </File>		
		</Files>
    </Code>
    <Components>
	  <Component>
        <Name>JW3Panel</Name>
        <Category>3rdParty</Category>
        <Glyph>
          <Name>JW3Panel</Name>
		  <MediaType>image/png</MediaType>
          <External>Glyphs\JW3Panel.png</External>
        </Glyph>
      </Component>		
	
	  <Component>
        <Name>JW3ListBox</Name>
        <Category>3rdParty</Category>
        <Glyph>
          <Name>JW3ListBox</Name>
		  <MediaType>image/png</MediaType>
          <External>Glyphs\JW3ListBox.png</External>
        </Glyph>
      </Component>	

	   <Component>
        <Name>JW3Image</Name>
        <Category>3rdParty</Category>
        <Glyph>
          <Name>JW3Image</Name>
		  <MediaType>image/png</MediaType>
          <External>Glyphs\JW3Image.png</External>
        </Glyph>
      </Component>	
	  

	   <Component>
        <Name>JW3ToolBar</Name>
        <Category>3rdParty</Category>
        <Glyph>
          <Name>JW3ToolBar</Name>
		  <MediaType>image/png</MediaType>
          <External>Glyphs\JW3ToolBar.png</External>
        </Glyph>
      </Component>	 
	  
	   <Component>
        <Name>JW3Button</Name>
        <Category>3rdParty</Category>
        <Glyph>
          <Name>JW3Button</Name>
		  <MediaType>image/png</MediaType>
          <External>Glyphs\JW3Button.png</External>
        </Glyph>
      </Component>	
	  
      <Component>
        <Name>TW3Form</Name>
      </Component>	  
	  </Components>
  </Package>
</SMART>
d. Icons in IDE missing transparency, please take a look on this one:

http://forums.smartmobilestudio.com/index.php?/topic/4034-icons-in-ide-missing-transparency/

Share this post


Link to post
Share on other sites

To recap the main elements of this framework :

 

If implements the usual structure of applications having multiple forms and forms having multiple visual components.

 

It can be used in the smart-ide as per usual.

Compiling, executing and development is not different from using the standard RTL.

It accepts the generated default code for new Forms (except for the uses clause)

It can be used with the visual designer :)

It follows the conventions of the current version of sms closely.

 

The differences are that the code base is completely new, and is generally somewhat closer to the html/css/js metal.

This makes for pretty small compiled scripts with fast loading and execution.

 

The latest kitchen sink includes some components plus the databased version of Laksekjonn's FishFacts

and can be found here http://www.lynkfs.com/Experiments/shoestring/www (just click the listbox items)

This demo project (http://www.lynkfs.com/Experiments/shoestring/index.sproj) has a mere 32KB footprint (recompiled in the new alpha)

 

It is of course not a replacement for the current or upcoming RTL upgrade.

But is usable for a range of relatively simple project types.

Share this post


Link to post
Share on other sites

Just in case someone is interested, the shoestring framework compiles ok in alpha

 

The latest kitchen sink includes some more components and demo's

and can be found here http://www.lynkfs.com/Experiments/shoestring/www/

Alpha project http://www.lynkfs.com/Experiments/shoestring/index.sprojhere

 

On another topic, I've had a look at the new alpha components especially the grid

I must congratulate the creator(s), it's awesome.

Share this post


Link to post
Share on other sites

neither link works for me

 

 

 

Just in case someone is interested, the shoestring framework compiles ok in alphaThe latest kitchen sink includes some more components and demo'sand can be found here http://www.lynkfs.co.../shoestring/www Alpha project (http://www.lynkfs.co...ing/index.sproj) hereOn another topic, I've had a look at the new alpha components especially the gridI must congratulate the creator(s), it's awesome.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×