Blog

All Blog Posts  |  Next Post  |  Previous Post

Importing web components into TMS WEB Core

Bookmarks: 

Thursday, April 23, 2020


Home office does not stop us from researching and experimenting with new technologies. While in the past weeks we shared news about our TMS FNC Maps, we were also busy with doing research for future versions of TMS WEB Core. We would like to give you a sneak peek of one of our ongoing projects: web components.

What are web components?

Web components allow you to create custom and reusable HTML tags via a set of JavaSript APIs, they can be scripted and styled without colliding with other parts of the document. They are based on existing web standards and support is continuously added. They were first introduced in 2011 but no proper support followed until recently. You can read more about how to create web components in the MDN web docs. This naturally raises the question: Can we use them in TMS WEB Core?

The short answer is yes because WEB Core already provides ways to interact with native JavaScript calls. You can call document.createElement('your-custom-tag') and set the properties of the TJSElement. But we are Delphi developers after all, and most of us prefer to use Pascal over JavaScript. So wouldn't it be nice to import them into TMS WEB Core?

Our importing tool

Imagine the following scenario: You found a nice web component pack that you'd like to use in TMS WEB Core. You can create wrapper classes yourself, but it might take a lot of time depending on the complexity of the components. We also don't like doing a lot of manual work like that, so we had the idea to create an importing tool instead. Unfortunately there are many ways to create web components but not enough or reliable ways to extract information regarding to properties, events and methods. It was clear that some sort of helper file will be needed and we set up a goal: Create wrapper classes automatically based on JSON descriptions. We also take every opportunity we can to challenge our own framework - we created this tool using TMS WEB Core!

As a first set of components to cover, we wanted to import Smart UI from the creators of jQuery jQWidgets controls that we already support in TMS WEB Core. It has both simple and complex elements, so it already gave us a huge set of functionality to cover.



The TMS WEB Core web components import tool was written with TMS WEB Core itself, so in a way, TMS WEB Core can magically create its components 😉

How does it work?

First we convert the JSON description to a TJSONObject then we loop through the properties and store them accordingly. In case of methods and events we need to store the parameters list too. Once that's done, we have everything we need to create the Pascal wrapper classes. This means 2-3 files for each component:
  • A core file to contain the source that's responsible for setting the correct properties, calling the correct methods, binding the correct events...
  • A stub file for designtime purposes
  • And sometimes it's unavoidable to introduce a file where we map onto the functions provided by the given component's JavaScript object
In each of these cases we start from a template string and extend/modify that based on the type of the file. These modifications include adding the properties, property setters, binding/mapping the methods and events, adding collections and extra classes where needed. We also need to take into account which types of properties can be published and which properties remain public. The result is a Pascal wrapper class where minimal manual work might still be needed, but it's a huge step compared to manually writing everything!

Let’s see an example!

For this demonstration we picked two smaller components: SmartButton and SmartToast. Both components were automatically generated; we are just going to use them! After conversion the class definition looks pretty similar in the stub and core file. The only differences are the property getters/setters and protected methods:
TWebSmartButton = class(TWebCustomControl)
private
  FAnimation: string;
  FClickMode: string;
  FContent: JSValue;
  FDisabled: Boolean;
  FInnerHTML: string;
  FLocale: string;
  FMessages: TJSObject;
  FReadonly: Boolean;
  FRightToLeft: Boolean;
  FTheme: string;
  FType: string;
  FValue: string;
  FUnfocusable: Boolean;
  FOnClick: TNotifyEvent;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
  property Content: JSValue read FContent write FContent;
  property Messages: TJSObject read FMessages write FMessages;
published
  property Animation: string read FAnimation write FAnimation;
  property ClickMode: string read FClickMode write FClickMode;
  property Disabled: Boolean read FDisabled write FDisabled default false;
  property InnerHTML: string read FInnerHTML write FInnerHTML;
  property Locale: string read FLocale write FLocale;
  property Readonly: Boolean read FReadonly write FReadonly default false;
  property RightToLeft: Boolean read FRightToLeft write FRightToLeft default false;
  property Theme: string read FTheme write FTheme;
  property &Type: string read FType write FType;
  property Value: string read FValue write FValue;
  property Unfocusable: Boolean read FUnfocusable write FUnfocusable default false;
  property OnClick: TNotifyEvent read FOnClick write FOnClick;
end; 
You can compare these properties and events to the component documentation.

We are going to show a notification when the button is clicked. The properties can be set from the form designer but except for the SmartButton.InnerHTML property we are doing it programmatically now. So far our form looks like this:



The white rectangle above is the TWebSmartButton and the one below is the TWebSmartToast. The TWebSmartToast is not visible at runtime but the width and the height of the control are used if the Modal property is enabled.
Let’s implement the OnClick event, set the properties of the TWebSmartToast and show the notification:
procedure TForm1.WebSmartButton1Click(Sender: TObject);
begin
  WebSmartToast1.Position := 'top-left';
  WebSmartToast1.&Type := 'success';
  WebSmartToast1.ShowCloseButton := True;
  WebSmartToast1.Value := 'This is a success! :-)';
  WebSmartToast1.Open;
end;
With such small effort we get the following, visually appealing result:



We hope that this got your interest already, because here you can find an online demo of some of the Smart UI components. The wrappers for the components you find in the demo were 100% automatically generated! This again shows the power of what TMS WEB Core can do!

Tunde Keller


Bookmarks: 

This blog post has received 5 comments.


1. Thursday, April 23, 2020 at 4:13:40 PM

Very cool!

Price Rhett


2. Thursday, April 23, 2020 at 7:06:27 PM

That''s amazing!

Farias Anderson


3. Friday, April 24, 2020 at 2:59:55 AM

Very Very Cool

Motion Byte In


4. Saturday, April 25, 2020 at 9:35:18 AM

What you guys are doing here is amazing! Two things I''m curious about: One is "importing" functional (non-visual) javascript APIs into the WebCore ecosystem; I''m particularly interested in the Web Audio API (a JS library; see more here: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API), but there are dozens if not hundreds of them around.

The other came up while reading this article. By analyzing JSON specs, does this mechanism lend itself to creating components libs from Swagger specs? Or what about things like functional (non-JS) APIs like from Amazon, Google, and eBay? Most such APIs offer JS interfaces, so maybe they''d be helpful for this. (?)

Schwartz David


5. Sunday, April 26, 2020 at 10:43:30 AM

This article focuses solely on the ''web components'' standard, not on jQuery controls or JavaScript APIs, objects. For the web components standard, see: https://www.webcomponents.org/specs

The pas2js compiler team already has import tools for JavaScript APIs (such as web audio). Fwiw, the next TMS WEB Core version will have such imported Pascal API wrappers for webaudio, webrtc, webassembly, webbluetooth.

REST APIs, such as from Amazon, eBay, Google are yet another technology for which we do not have automatic import at this moment.

So, this article focus is on web components only and it is what we are working on at this moment.

Bruno Fierens




Add a new comment:
Author:
Email:
  You will receive a confirmation mail with a link to validate your comment, so please use a valid email address.
 
Comment:
 
 

All fields are required.
 



All Blog Posts  |  Next Post  |  Previous Post