Jump to content


Photo

shoestring framework


  • Please log in to reply
10 replies to this topic

#1 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 06 September 2017 - 12:39 AM

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.co.../HtmlElem/test/)
and project-code here (http://www.lynkfs.co...est/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.
  • Igor Savkic likes this
Nico Wouterse

#2 Laksekjønn

Laksekjønn
  • Members
  • 440 posts

Posted 07 September 2017 - 01:13 AM

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.
  • Nico Wouterse likes this

#3 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 07 September 2017 - 03:03 AM

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
Nico Wouterse

#4 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 07 September 2017 - 01:01 PM

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)
Nico Wouterse

#5 Laksekjønn

Laksekjønn
  • Members
  • 440 posts

Posted 07 September 2017 - 05:59 PM

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

a. Make Project External issue
http://forums.smartm...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. ---&amp;gt; the forms .sfm are not created!

b. Property 'Angle' 'Opacity' 'Zoom' 'BorderRadius' not found!
Details see at: http://forums.smartm...movablecontrol/
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.smartm...g-transparency/
  • Nico Wouterse likes this

#6 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 09 September 2017 - 05:05 PM

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.co.../shoestring/www (just click the listbox items)
This demo project (http://www.lynkfs.co...ing/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.
Nico Wouterse

#7 Laksekjønn

Laksekjønn
  • Members
  • 440 posts

Posted 09 September 2017 - 06:18 PM

Another way to create fast Visual JForms based project

a. at "SMS_INSTALL_FOLDER/Repository" directory, just create a file named "Visual JForms.spg" with the following content: https://pastebin.com/raw/d6ruEJ5A
b. restart SmartMS
c. choose "New..." (Create a new project) --> "Visual JForms Project"
  • Nico Wouterse likes this

#8 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 17 September 2017 - 10:02 AM

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.co...shoestring/www/
Alpha project http://www.lynkfs.co...ing/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.
Nico Wouterse

#9 ielite

ielite
  • Members
  • 704 posts

Posted 17 September 2017 - 07:59 PM

neither link works for me


&nbsp;

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.

&nbsp;

#10 Nico Wouterse

Nico Wouterse
  • Moderators
  • 250 posts
  • LocationAustralia

Posted 18 September 2017 - 01:11 AM

corrected
Nico Wouterse

#11 Igor Savkic

Igor Savkic
  • Members
  • 185 posts

Posted 18 September 2017 - 01:17 AM

> neither link works for me

...open up OK for me.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users