Quantcast
Channel: TMS Software
Viewing all 1008 articles
Browse latest View live

TMS RADical WEB, using HTML & CSS for design & layout of your application pages

$
0
0

By default, the Delphi form designer serves as a WYSIWYG design surface for your web application forms. This means that the UI controls on the Delphi form will appear absolute positioned on the web page. For page layout & organization, there are the typical Delphi container controls like a panel, groupbox, scrollbox, gridpanel.



The parent/child relationship of the Delphi controls is also reflected on the produced web pages. Additional facilities like control alignment, anchoring and a splitter control are available to let you and the end user control the layout of the pages. In this default mode, everything is as such very familiar to Delphi developers and users of Delphi VCL Windows applications and sometimes this similarity is desirable. However, the TMS WEB Core framework is also completely open to have the page layout designed directly from HTML & CSS. The architecture of the framework provides for separating design & code and even have the design done by people with a role, i.e. graphical designers.
So, how is this separation handled? Fortunately, in a very easy and straightforward way. The link between HTML and the UI controls and code used in the Delphi IDE is based on the unique HTML element ID. Every TMS WEB Core control has a property ElementID. When the ElementID is not used, i.e. left empty, the HTML elements the control consists of is generated by the TMS WEB Core framework. When the ElementID is specified, the HTML element found is hooked up to the Pascal class for the control. This means that property accessors directly get and set values from the HTML element and the various HTML element Javascript events are hooked up the class and exposed as Pascal event handlers.
Here the TWebMemo is hooked up via the ElementID property to a TEXTAREA HTML element with ID set to “mem” and already in the HTML file.



The software developer and the graphical designer can collaborate by simply ensuring that the designer provides the HTML element IDs to the software developer or the software developer can provide a list of IDs of controls needed to the graphical designer. It speaks for itself that using this technique empowers us to take advantage of responsive design for TMS WEB Core web applications. When the HTML template for the page is applying responsive design techniques, i.e. different layouts for different device screen sizes, the UI controls will appear where the designer defined these should appear depending on the screen size. That is not all though. It is also possible to let the Delphi designed UI be generated in the body part of a HTML page or in any specified HTML container element in a HTML page. As such, a graphical designer could create a page layout with a header, footer and other elements in the HTML page and add a specific area via a HTML DIV or SPAN element where the Delphi designed UI will be generated in. To do so, all that is needed is set to the ID for the HTML element where the form should be generated via the Form.AppContent property. Finally, each UI control also exposes an ElementClass property. Via this ElementClass property a CSS style can be specified for an UI control. Via this way for example, it is very easy to use a popular framework like bootstrap. It is sufficient to set the bootstrap CSS class names to the UI controls on the Delphi form designer by their ElementClass properties.


Here the ElementClass property of the edit control on the form is set to the bootstrap ‘form-control’ style:

One of the demos included in the TMS WEB Core framework shows this. By simply changing the bootstrap theme via changing the reference in the HTML page template, the appearance of the web application will adapt automatically.

Demo without styling:
http://www.tmssoftware.biz/tmsweb/demos/tmsweb_simple/

Demo with bootstrap styling applied:
http://www.tmssoftware.biz/tmsweb/demos/tmsweb_bootstrap/

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.


TMS RADical WEB, using common web functionality & consuming cloud services

$
0
0

In web applications, we have come to expect that we can easily integrate audio, video or services like Youtube or Google Maps to embed video or geographical functionality. TMS WEB Core provides a multimedia component with which audio & video can be played. It provides a control that makes it dead-easy to add a Youtube video in a web application. All that is needed is setting the Youtube video ID and that's it. Also adding a map with Google Maps is easy. Drop the Google Maps component on the form and you see the map in the web application. The component offers right now already access to markers, zooming and panning and we plan to extend it over time with many more capabilities all easily accessible in Pascal code in a RAD way.

procedure TForm4.WebButton2Click(Sender: TObject);
var
  lat,lon: double;
begin
  lat := 48.8566;
  lon := 2.3522;
  WebGoogleMaps1.SetCenter(lat,lon);
  WebGoogleMaps1.AddMarker(lat,lon,'Paris');
end;

procedure TForm4.WebButton3Click(Sender: TObject);
var
  lat,lon: double;
begin
  lat := 51.5074;
  lon := 0.1278;
  WebGoogleMaps1.SetCenter(lat,lon);
  WebGoogleMaps1.AddMarker(lat,lon,'London');
end;



And of course, you can also experience this demo live.

Also, in a non-visual way, access to cloud services is possible. For consuming OAuth 2.0 based cloud services, there is a OAuth web client. Alternatively, for more strict & secure purposes, a server side accessor helper will be needed. At this time, there is a sample component demonstrating access to Google calendar as well as access to our myCloudData.net service. It is clear that over time, we will add more out of the box ready web clients for other cloud services as well as helpers to facilitate server-side cloud service access.





Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, debugging your code

$
0
0

Given TMS WEB Core is based on a Pascal to Javascript compiler with the Javascript code running in the browser, there is not a direct way to debug the code from the Delphi IDE. From the IDE, the Javascript code is generated and the browser is launched with the HTML page URL. After launching the browser, there is no further interaction between the IDE and the browser. Of course, since modern browsers come with a Javascript debugger integrated, you can debug the web applications this way directly from the browser. Of course, debugging this way means you need to need to be familiar with Javascript and figure out how the Javascript you step through corresponds to the Pascal code in your web application. Although this is still a possible way to debug, the Pascal to Javascript compiler provides for a way easier method to debug your code as original Pascal code when using the Google Chrome or the Mozilla Firefox browser debugger.



So, when you launch your web application in debug mode, with the help of an automatic generated map file, the Google browser debugger allows you to step through your original Pascal source code, inspect values, use watches, set breakpoints etc.. pretty much the same way as you would do from the Delphi IDE. So, all in all, this offers excellent debugging facilities for your web applications when using the Google Chrome browser or Mozilla Firefox browser.



So, with TMS WEB Core, if you compile in debug mode, this extra map file is generated that allows you to debug from the browser in Pascal code and when you compile in release mode, this map file is not generated and your Pascal code is not visible to users.

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, history, the team and future

$
0
0



There is the famous quote: "Everything starts with a dream" and many years ago, Michael Van Canneyt, one of the main contributors to the Lazarus and Free Pascal compiler project had the dream of having the Pascal language as a first-class language for creating web applications in pretty much the same way as Delphi developers can since 1995 create first-class Windows applications with the Pascal language and VCL.
Michael Van Canneyt did years of research on ways to achieve this goal, including what the best approaches are to create a high-performance Pascal to Javascript compiler and how to best map the Delphi RTL on Javascript. When Michael Van Canneyt shared his dreams with Detlef Overbeek, editor of the Blaise Pascal magazine, Detlef was so enthusiast that he initially funded the further development of this idea and this enabled to involve Mattias Gaertner to help the development of the compiler. Realizing much more would be needed than just a compiler, Detlef Overbeek got in touch with Bruno Fierens, founder & director of TMS software. Given the expertise of TMS software in UI control frameworks, bundling the forces would finally enable the dream to come true. Bruno Fierens was so thrilled by the idea of having the ability to create modern web applications in a component-based RAD way with the strictly typed and object oriented Pascal language from the Delphi IDE that he put a big part of the TMS team behind the project and even attracted some more brilliant minds to realize this goal. Over one year now, this team closely worked together to bring a first version of the product under the TMS RADical WEB umbrella: TMS WEB Core. The power team that brought this first part of the dream to reality is at this moment:

Bart Holvoet: Expert at TMS software in web development + cloud services and responsible for standard TMS WEB Core UI controls and jQuery control wrappers

Bruno Fierens: Embarcadero MVP, TMS software founder, director and responsible for the TMS RADical WEB strategy & overall product architecture

Detlef Overbeek: Editor of the Blaise Pascal magazine and never-ending source of inspiration, motivation & ideas

Holger Flick: Embarcadero MVP and TMS WEB Core evangelist, QA, training and UX expert and advisor

Masiha Zemarai: Marketing manager at TMS software responsible for TMS WEB Core sales & marketing

Mattias Gaertner: Compiler engineer responsible for the Pascal to Javascript compiler

Michael Van Canneyt: Architect of compiler and RTL and overall technical advisor

Pieter Scheldeman: Architect at TMS software responsible for the FNC framework and web-enabling the FNC framework for TMS WEB Core

Roman Kassebaum: Embarcadero MVP and responsible for the TMS WEB Core IDE integration

Sanjay Kanade: Software developer at TMS software developing web-enabled FNC UI controls

Wagner R. Landgraf: Architect of TMS Business Subscription line of tools and responsible for the XData client for TMS WEB Core



We have many plans for extending the capabilities of this technology and reach into new territories with new products under the TMS RADical WEB umbrella. Our roadmap for the next years is filled with ideas and we especially look forward to all your ideas & wishes to further extend and steer the plans for innovative new developments.

You feel as excited & thrilled as we are and want to become part of this brilliant top team? We've got much more plans and work to roll-out the full TMS RADical WEB. If you are the bright, motivated talent wanting to help make dreams come true, contact us today!



Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, Easy REST Server integration with TMS XData Client

$
0
0

One very cool feature of TMS RADical WEB (if not the main one) is that it allows Delphi developers to build Web applications that do not need a server connection. It's just HTML and JS files that run in the browser.

But we all know that there are some applications that need to retrieve data from somewhere, and also eventually persist data. We do not need a server to "run" the application, but we eventually might need communicate to a server to ask for data, perform centralized operations, authentication, etc.

While you can use any API server you want from the Web application, when using TMS XData to build the server your life will be way easier:


  • First, because with TMS XData you can write your backend server using Delphi and Pascal.
  • Also, because TMS XData is simply way too productive - it's very easy and fast to publish entities directly from database and to create service operations in a snap.
  • And, finally, because TMS XData provides first class support to TMS WEB Core, providing components that make it very easy and straightforward to connect to a XData server

The following screenshot shows the TMS XData Web Client demo in action. It's a sample that connects to a public XData REST server that holds information about music artists, albums, genres and tracks. With this demo you can retrieve and modify data from this server.



Note that this demo is dynamic. It means you can simply change the URL of server and it will work with any TMS XData Server you might have, regardless of the entities it publishes. The server provides the metadata for the whole API, and the client loads it at runtime allowing you to access the API in a very high level.

Also design-time components are available for you to simply assign properties and set handlers for the events that will fire when the server request is finished.



In case you're curious about how it's accomplished, here is the full source code for the implementation section of the single unit of the demo. The interface part was removed just because it's a bunch of declarations of the visual control fields.
procedure TForm1.btDeleteClick(Sender: TObject);
begin
  XDataWebClient1.Delete(SelectedEntitySet, TJSObject(TJSJSON.parse(DeleteMemo.Lines.Text)));
end;

procedure TForm1.btGetClick(Sender: TObject);
begin
  XDataWebClient1.Get(SelectedEntitySet, SelectedId);
end;

procedure TForm1.btListClick(Sender: TObject);
begin
  XDataWebClient1.List(SelectedEntitySet, edQuery.Text);
end;

function TForm1.SelectedEntitySet: string;
begin
  Result := cbEntitySets.Items[cbEntitySets.ItemIndex];
end;

function TForm1.SelectedId: Integer;
begin
  Result := StrToInt(edId.Text);
end;

procedure TForm1.ShowInfo(const Msg: string; Error: Boolean);
begin
  InfoLabel.Caption := Msg;
  if Error then
    InfoLabel.Font.Color := clRed
  else
    InfoLabel.Font.Color := clWindowText;
  InfoLabel.Visible := True;
end;

procedure TForm1.btPostClick(Sender: TObject);
begin
  XDataWebClient1.Post(SelectedEntitySet, TJSObject(TJSJSON.parse(PostMemo.Lines.Text)));
end;

procedure TForm1.btPutClick(Sender: TObject);
begin
  XDataWebClient1.Put(SelectedEntitySet, TJSObject(TJSJSON.parse(PutMemo.Lines.Text)));
end;

procedure TForm1.WebFormCreate(Sender: TObject);
begin
  ServerLabel.Caption := Format('XData Server URL: %s', [XDataConnection1.URL]);
  XDataConnection1.LoadModel;
end;

procedure TForm1.XDataConnection1ModelLoad(Sender: TObject);
var
  Container: TXDataEntityContainer;
  I: Integer;
begin
  Container  := XDataConnection1.Model.DefaultEntityContainer;

  cbEntitySets.Items.Clear;
  for I := 0 to Container.EntitySets.Count - 1 do
    cbEntitySets.Items.Add(Container.EntitySets[I].Name);
  if cbEntitySets.Items.Count > 0 then
    cbEntitySets.ItemIndex := 0;
end;

procedure TForm1.XDataWebClient1Error(Error: TXDataClientError);
begin
  ShowInfo(
    Format('%s. RequestId: %s. Code: %s. Request Url: %s',
      [Error.ErrorMessage, Error.RequestId, Error.ErrorCode, Error.RequestUrl]),
    True
  );
end;

procedure TForm1.XDataWebClient1Load(Response: TXDataClientResponse);
begin
  InfoLabel.Visible := False;
  if Response.RequestId = 'get' then
    GetMemo.Lines.Text := TJSJson.stringify(Response.Result)
  else
  if Response.RequestId = 'list' then
    ListMemo.Lines.Text := TJSJson.stringify(Response.Result)
  else
  if Response.RequestId = 'post' then
    ShowInfo(Format('New entity created in %s collection.', [SelectedEntitySet]))
  else
  if Response.RequestId = 'put' then
    ShowInfo(Format('Entity updated in %s collection.', [SelectedEntitySet]))
  else
  if Response.RequestId = 'delete' then
    ShowInfo(Format('Entity removed from %s collection.', [SelectedEntitySet]));
end;

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, developing custom controls

$
0
0

In November 2016, I created a presentation for Embarcadero CodeRage about creating FNC custom controls. You can find this presentation including its source code here: https://community.embarcadero.com/blogs/entry/developing-user-interface-controls-for-both-vcl-and-fmx-with-bruno-fierens Unless you have been living under a rock the past 2 weeks, you have most certainly seen we have recently introduced the technology preview of TMS WEB Core and with that also the news that the TMS FNC framework is now also web-enabled. So, I thought it was a good moment to revisit this November 2016 CodeRage presentation and see how applicable it still is for creating custom TMS FNC UI controls, but this time for using this in the web!
The good news is that this took me less than 10 minutes to get the original custom TMS FNC UI control I created for VCL, FMX and LCL now also working for the web.

So, what did I have to do?

I started from the unit VCL.TMSFNCFancyTrackbar that contained the source code for the VCL variant of the FNC Fancy trackbar control. I renamed this file VCL.TMSFNCFancyTrackbar to WEBLib.TMSFNCFancyTrackBar.pas as WEBLIB is the prefix for the namespace for the web variant of the FNC controls. Further, for this small test, I manually renamed the unit references in the uses list in WEBLib.TMSFNCFancyTrackBar.pas.

  VCL.Controls,
  VCL.TMSFNCCustomControl,
  VCL.TMSFNCGraphics,
  VCL.TMSFNCTypes,
  VCL.TMSFNCGraphicsTypes;
to
  WEBLib.Controls,
  WEBLib.TMSFNCCustomControl,
  WEBLib.TMSFNCGraphics,
  WEBLib.TMSFNCTypes,
  WEBLib.TMSFNCGraphicsTypes;

I did not touch any other part of the code. Next, I copied the code to instantiate this custom control TTMSFNCFancyTrackBar from the test project to the TMS WEB Core test project:

begin
  tb := TTMSFNCFancyTrackBar.Create(Self);
  tb.Parent := Self;
  tb.Width := 600;
  tb.Height := 200;
  tb.Slider.LoadFromFile('slider.png');
  tb.Thumb.LoadFromFile('thumb.png');
end;

As I knew my app was going to need a PNG file for the trackbar background and the trackbar thumb, I copied the PNG files to the folder where the web application is deployed and from where its files are being served to the browser. 5 minutes later, the web application was running and resulted in:


So, a kind of half working trackbar. The tickmarks are displayed and the position value as well but my trackbar background and trackbar thumb were missing.
Then it dawned on me that the most likely reason of the issue was that my custom control didn’t have OnChange handlers for the TTMSFNCBitmap classes that were used as class properties to hold the trackbar background and thumb. When using the code in a native client application, the loading of the images from file is instant and thus, when the native app starts, the images are loaded and being used immediately to paint the control. So, I had never noticed this before.
In the web this is different. Under the hood, we have implemented TMSFNCBitmap.LoadFromFile() via asynchronous loading of the image file via an XMLHttpRequest() object. This means there is no instant synchronous loading and therefore it means that I need to signal the custom control to refresh itself when the images are loaded. This is achieved by assigning an event handler to the TTMSFNCBitmap.OnChange event and from there, Invalidate the control.

TTMSFNCFancyTrackBar = class(TTMSFNCCustomControl)
…
protected
    procedure ImageChanged(Sender: TObject);
…
end;

procedure TTMSFNCFancyTrackBar.ImageChanged(Sender: TObject);
begin
  Invalidate;
end;

constructor TTMSFNCFancyTrackBar.Create(AOwner: TComponent);
begin
  inherited;
  FThumb := TTMSFNCBitmap.Create;
  FSlider := TTMSFNCBitmap.Create;
  FThumb.OnChange := ImageChanged;
  FSlider.OnChange := ImageChanged;
  …
end;
With this inplace, the TTMSFNCFancyTrackbar custom control looks 100% identical to the native versions created earlier for VCL, FMX and LCL applications:


and yes, also the interaction with keyboard and mouse work fine.

If you already embarked on creating custom FNC controls, this means there is excellent news. With little or no effort, you will be able to use these custom FNC UI controls also in your web applications created with TMS WEB Core!
The full source code of the web version of the TTMSFNCFancyTrackbar can be downloaded here but you can as well easily play with it directly from your browser in this demo app: http://www.tmssoftware.biz/tmsweb/demos/tmsweb_customcontrol/


Well, this is just one approach for creating custom UI controls for TMS WEB Core. This approach offers you to create controls pretty much with the same UI control model as you could from Delphi 1. In another upcoming blog article, we'll present an entirely different way for creating custom UI controls where the control will be fully built-up from HTML elements!

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, technology preview update

$
0
0

We’ve been overwhelmed by the enthusiasm of many users about the news of TMS WEB Core and also the many reactions, feedback, comments of users who immediately got their hands wet with the technology preview.

From all feedback received combined with our internal planning, we’re pleased to inform that there is now a technology preview update available that brings not only many small improvements but also some exciting new features!

The highlight of the technology preview update is the introduction of the jQWidgets jQxGrid UI control. This control can now be easily used from your Pascal code from a TMS WEB Core application. jQxGrid is a high performance jQuery grid with paging, sorting, grouping, editing & filtering capabilities. It also features different column types.



If you get TMS WEB Core 0.9.2 you can start playing with the new grid right-away or you can explore the grid via the online demo.

Second new big feature is that now data-modules, i.e. the TWebDataModule, are also available. The same easy-to-use centralized place for databinding & business logic that we are used to in Delphi VCL or FMX applications is now also available in TMS WEB Core applications.



Also new is a Twitter feed display component. Showing your personal or company Twitter feed integrated in your web application is now as easy as dropping a component and setting your feed name.



We’ve also made it easier to use cookies and query parameters directly from your Pascal code. Getting or settings cookie values is now very easy. You can use code like:

Cookies.Add(‘CompanyNameCookie’,’tmssoftware’, Now + 5000);
Cookies.Add(‘UserNameCookie’,’Bruno Fierens’, Now + 5000);
Cookies.SetCookies;
And there is more!
The IDE integration was also improved with built-in automatic listing of CSS style classnames or HTML element IDs, so you can pick directly from the Object Inspector what CSS style from your HTML template you want to assign to a control or to what HTML element you want to link a control.



Other than this there are numerous smaller improvements in aligning, splitter, Google Maps geolocation, Google maps route display, …

We’ll keep you posted with more updates as we continue to execute the planning and we look forward to hear all your feedback!

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

TMS RADical WEB, time for some fun

$
0
0

Last week, our team was brainstorming and as usual, lots of interesting and cool ideas come up. Based on these ideas, we have some more exciting technology being worked on now and coming up soon and you’ll learn about it here shortly. But, from time to time, there are also fun ideas that come up during our brainstorm sessions. One such idea was to check if it wouldn’t be possible to port an existing Pascal game to TMS WEB Core and this way, make the game available via our website for playing it directly online. We thought this was not only a good idea but also a perfect validation to see how well our TMS WEB Core performed in enabling Delphi developers to move existing code over to the web. So, our software architect Pieter Scheldeman, also the architect of the cross-framework, cross-platform FNC framework, searched for some open-source Pascal games. One of the games Pieter found was the Tetris game in the Bianco Games collection from Marco Bianchini: https://torry.net/authorsmore.php?id=800

After checking out the source code of the Tetris game a bit, we were amazed that after less than 30 minutes of work by Pieter, the game was already running in the browser!


You can play with the game for yourself here:

http://www.tmssoftware.biz/tmsweb/demos/tmsweb_tetris

The game does all its painting via the Delphi TCanvas in a custom control. As TMS WEB Core introduces a TCustomControl class with access to a TCanvas object with the same interface as the Delphi TCanvas, the control in which the Tetris blocks fall was working quickly with almost no code changes in the web. It shows the strength of the Pascal to Javascript compiler combined with the component framework we have designed for it.

Have fun playing the Tetris game without needing to install it on your machine. We’re curious and eager to learn if you have more cool challenges to validate our TMS WEB Core technology against.

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.


TMS RADical WEB, custom controls using HTML elements

$
0
0

In a previous blog, it was demonstrated how custom controls for TMS WEB Core could be created using the FNC framework and how easy it was to use FNC code that was written for VCL, FMX or LCL applications also for web applications.
In this article, we want to cover custom controls from an entirely different angle. That means custom controls that are built from a hierarchy of HTML elements. The example via which we want to explain building such custom controls is about a commonly used UI concept in web development, i.e. a login panel. This is where the user enters his username & password to authenticate. So, in this article, we’ll show the details how to make a TMS WEB Core custom UI control that represents such reusable login panel.


In terms of HTML, the login panel consists of an outer DIV element. In this DIV, we put different DIV elements to hold label text to indicate where the username HTML INPUT element is and where the password HTML input element is. Finally, there is a HTML BUTTON used to confirm the actual entry and do a login.

From a TMS WEB Core custom control perspective, this means we will create a Pascal class descending from TCustomControl and we’ll override the CreateElement virtual method. This CreateElement virtual method is what is responsible for returning the hierarchy of HTML elements representing the UI control. In this case, the code for CreateElement is:

function TLoginPanel.CreateElement: TJSElement;
var
  br: TJSElement;
begin
  Result := document.createElement('SPAN');
  FCaption := TJSHTMLElement(document.createElement('DIV'));
  FUserInput := TJSHTMLElement(document.createElement('INPUT'));
  FPasswordInput := TJSHTMLElement(document.createElement('INPUT'));
  FPasswordInput.setAttribute('type','password');
  FUserLabelSpan := TJSHTMLElement(document.createElement('DIV'));
  FPasswordLabelSpan := TJSHTMLElement(document.createElement('DIV'));
  Result.appendChild(FCaption);
  Result.appendChild(FUserLabelSpan);
  Result.appendChild(FUserInput);
  Result.appendChild(FPasswordLabelSpan);
  Result.appendChild(FPasswordInput);
  br := document.createElement('BR');
  Result.appendChild(br);
  FButton := TJSHTMLElement(document.createElement('BUTTON'));
  Result.appendChild(FButton);
  FButton.addEventListener('click', @HandleLoginClick);
end;

Here FCaption, FUserLabelSpan, FUserInput, FPasswordLabelSpan, FPasswordInput and FButton are Pascal references to the HTML elements SPAN, INPUT and BUTTON used in the control. You can see that the HTML elements are created with document.createElement(). This is almost as if one would do this in Javascript, but via the Pascal to Javascript compiler, you can see the DOM object document can be used as Pascal object.

One more note about the CreateElement method, you can see that the purpose of the last line in the method: FButton.addEventListener('click', @HandleLoginClick);
is to attach a TLoginPanel method HandleLoginClick to the HTML element ‘onclick’ event handler. The HandleLoginClick method is declared as

function HandleLoginClick(Event: TJSMouseEvent): Boolean; virtual;

To see how this HTML element event handler is eventually hooked up to trigger the TLoginPanel.OnLogin event, see this code snippet from the TLoginPanel class:

TLoginPanel = class(TCustomControl)
private
    FOnLogin: TNotifyEvent;
    function HandleLoginClick(Event: TJSMouseEvent): Boolean; virtual;
protected
   procedure DoLogin; virtual;
published
    property OnLogin: TNotifyEvent read FOnLogin write FOnLogin;
end;

function TLoginPanel.HandleLoginClick(Event: TJSMouseEvent): Boolean;
begin
  DoLogin;
end;
procedure TLoginPanel.DoLogin;
begin
  if Assigned(OnLogin) then
    OnLogin(Self);
end;

To interface our Pascal class with the HTML elements two more virtual method overrides are important. There is the UpdateElementVisual method and the UpdateElementData method. The purpose of the UpdateElementVisual method is to do changes to HTML element properties that affect the UI control visually. The UpdateElementData method is to do changes with respect to data contained in the HTML elements.
For this TLoginPanel control, we expose a few properties to set captions for labels in the UI control as well as the values of the HTML INPUT elements for username and password.

The properties of the TLoginPanel used for the login panel data are:

TLoginPanel = class(TCustomControl)
published
    property CaptionLabel: string read FCaptionLabel write SetCaptionLabel;
    property LoginLabel: string read FLoginLabel write FLoginLabel;
    property Password: string read GetPassword write SetPassword;
    property PasswordLabel: string read FPasswordLabel write SetPasswordLabel;
    property User: string read GetUser write SetUser;
    property UserLabel: string read FUserLabel write SetUserLabel;
end;
The UpdateElementData method is:

procedure TLoginPanel.UpdateElementData;
begin
  inherited;
  FUserLabelSpan.innerHTML := FUserLabel;
  FPasswordLabelSpan.innerHTML := FPasswordLabel;
  FButton.innerHTML := FLoginLabel;
  FCaption.innerHTML := FCaptionLabel;
  (FUserInput as TJSHTMLInputElement).value := FUser;
  (FPasswordInput as TJSHTMLInputElement).value := FPassword;
end;

To customize the look and feel of the login panel, there is a dual approach. The first and classic Pascal like approach is the basic properties are defined to set the background & border color of the panel and the padding and margin of the controls within the panel. The second approach is that the CSS class can be set for the HTML elements used and that also via CSS full customization of look and feel is possible. This leaves the choice to either stick to classical Delphi style RAD development and do all from the form designer or work with separate CSS and perhaps leave the styling to a graphic designer instead of letting the developer do everything.

The visual properties exposed for the TLoginPanel class are:

TLoginPanel = class(TCustomControl)
published
    property BorderColor: TColor read FBorderColor write SetBorderColor;
    property Color: TColor read FColor write SetColor;
    property ElementClassName: string read FElementClassName write SetElementClassName;
    property ElementCaptionClassName: string read FElementCaptionClassName write SetElementCaptionClassName;
    property ElementInputClassName: string read FElementInputClassName write SetElementInputClassName;
    property ElementButtonClassName: string read FElementButtonClassName write SetElementButtonClassName;
    property ElementLabelClassName: string read FElementLabelClassName write SetElementLabelClassName;
    property Margin: integer read FMargin write SetMargin;
    property Padding: integer read FPadding write SetPadding;
end;

The Element*ClassName properties allow to set CSS class names for the control itself (outer DIV), the SPAN elements for the labels associated with the INPUT elements and of course of also for the HTML INPUT and BUTTON elements.

The UpdateElementVisual override becomes:
procedure TLoginPanel.UpdateElementVisual;
var
  strpadding,strmargin: string;
begin
  inherited;
  if Assigned(ElementHandle) then
  begin
    strpadding := IntToStr(Padding)+'px';
    strmargin := IntToStr(Margin)+'px';
    ElementHandle.setAttribute('class',ElementClassName);
    if (ElementClassName = '') then
    begin
      ElementHandle.style.setProperty('background-Color',ColorToHTML(Color));
      ElementHandle.style.setProperty('border', 'solid 1px '+ColorToHTML(BorderColor));
      ElementHandle.style.setProperty('padding',strPadding);
    end;
    ElementHandle.style.setProperty('display','table');
    FCaption.setAttribute('class',ElementCaptionClassName);
    if (ElementCaptionClassName = '') then
    begin
      FCaption.style.setProperty('margin-top',strMargin);
      FCaption.style.setProperty('margin-bottom',strMargin);
      FCaption.style.setProperty('font-weight','bold');
    end;
    FUserInput.setAttribute('class',ElementInputClassName);
    FPasswordInput.setAttribute('class',ElementInputClassName);
    if (ElementInputClassName = '') then
    begin
      FUserInput.style.setProperty('margin-top',strMargin);
      FUserInput.style.setProperty('margin-bottom',strMargin);
      FPasswordInput.style.setProperty('margin-top',strMargin);
      FPasswordInput.style.setProperty('margin-bottom',strMargin);
    end;
    FUserInput.style.setProperty('width','100%');
    FUserInput.style.setProperty('display','table-cell');
    FPasswordInput.style.setProperty('width','100%');
    FPasswordInput.style.setProperty('display','table-cell');
    FUserLabelSpan.setAttribute('class',ElementLabelClassName);
    FPasswordLabelSpan.setAttribute('class',ElementLabelClassName);
    if (ElementLabelClassName = '') then
    begin
      FUserLabelSpan.style.setProperty('margin-top',strMargin);
      FUserLabelSpan.style.setProperty('margin-bottom',strMargin);
      FPasswordLabelSpan.style.setProperty('margin-top',strMargin);
      FPasswordLabelSpan.style.setProperty('margin-bottom',strMargin);
    end;
    FButton.setAttribute('class',ElementButtonClassName);
    if (ElementButtonClassname = '') then
    begin
      FButton.style.setProperty('margin-top',strMargin);
      FButton.style.setProperty('margin-bottom',strMargin);
    end;
    FButton.style.setProperty('float','right');
  end;
end;

Notice how the properties are set when no CSS class is specified for HTML elements or otherwise the look and feel will be determined by the CSS.

The result becomes:

This is the basic look and feel without CSS.

Now, let’s bring bootstrap CSS and some custom CSS in the game and see the new look and feel.

Bootstrap is introduced with adding

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

to the project HTML file and in addition we add CSS in the project HTML file <STYLE> section to control the LoginPanel look & feel:
<style>
    .labelcenter {
      text-align: center;
    }
    .loginpanel {
      padding: 15px;
    }
    .loginpanelelement {
      margin-top: 2px;
      margin-bottom: 2px;
    }
</style>
Now the appearance of the panel becomes:



We have only scratched the surface here of the many possibilities to enrich the TMS WEB Core framework with custom UI controls but we hope we have generated interest and enthusiasm.

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

Object Pascal: Declaring Units

$
0
0

Unsplash image

Declaring units in a specific order in code would facilitate the code maintenance in the future.

Introduction

When we're organizing our things, we tend to keep closer to us all objects that we use daily, right?

So it should be with the units of a project.

The order that units appear in the code could facilitate or not the maintenance.

In that article, I will show you what order I use to declare units in my own projects.

Compiler

The units, also known as modules, compose the projects.

Every project must be divided into logical units and make that division it's not always easy, because it involves an abstract and logical level of thinking.

After dividing the project units, we also need to concern with third-party units.

Nowadays it's almost mandatory that we use lib's and frameworks. Mostly, they are Open Source projects.

Such third-party units make our work easier, as they already have ready-made artifacts that speed up the development of projects.

In addition to these third-party units, we also have the default units located in Run-time Library (RTL) or VCL/LCL, which have many interfaces, classes, functions, and artifacts, ready-to-use.

So, what order we should declare such units in our code?

Here is the order that I propose:

    unit MyUnit;
    uses
      // 1. fpc/lazarus/delphi units,
      // 2. 3rd units,
      // 3. my open source units,
      // 4. project units

When the compiler starts parsing your code and it arrives at MyUnit, it will read the units in the sequence in which they were declared — there may be some optimization, but the important thing is the final result, which depends on the order above — and the identifiers (classes, interfaces, functions/procedures, variables and constants) will be "stored in order" in which they were declared.

So, I propose to declare, initially, all units that are standard to the compiler and IDE. Then, all third-party units such as libs and frameworks. After, all units referring to your public projects, be them OpenSource or shared within sectors of your company. Finally, we declare all units of the project itself, that is, the project we are currently working on.

And why is this important?

The reason is because the compiler needs to know in which unit a particular artefact (class, function, etc) is located.

The rule is that:

If you have 3 units (Unit1, Unit2 and Unit3 ) and each has a class named TFoo, the compiler will "inform" your code that TFoo is located in the last declared unit.

For example:

    uses
      Unit1, Unit3, Unit2;

Notice that I reversed the numerical order. First is 1, then 3, and finally 2.

Where is located TFoo class when you'll use it in yourMyUnit?

The answer is: In Unit2.

Because it was declared by last.

Imagine that the compiler is putting a reference table into memory for all the identifiers it finds. First, it finds TFoo when it reads Unit1. Then, it finds it again when it reads Unit3. At this point it overrides the reference that says that TFoo is in Unit1, because it is now in Unit3. Finally, when it reads Unit2 the identifier is repositioned again.

If in that same MyUnit I need to use TFoo from Unit1, I am required to qualify the class with the unit name instead of just using identifier:

    Foo := Unit1.TFoo.Create...

You can see another example here

Sections

In the Object Pascal language we have two places (sections) where we can declare the units that will be used.

We can declare in the interface section or in the implementation section.

Is it worth declaring Units in the implementation section?

In my opinion, no.

In doing so, you will have 2 places to organize the precedence of the Units, meaning you will have more work.

Because the Object Pascal language does not support Circular Reference between Units, one of the reasons for having the option to declare Units in the implementation section is to allow this bi-directional reference between them. However, this also indicates a bad design in the division of the project units.

Conclusion

Defining the order of declaration of the units in each unit of your project can be extremely important to facilitate maintenance and organization.

As you add new identifiers, you will be sure that the compiler will give you "priority" to use the identifiers for your project, without having to prefix it with the unit name.

If you add some identifier and it conflicts with another unit that has the same name, simply prefix that identifier with the name of the unit, either from third parties or from the environment itself. However, this conflict will not exist in the identifiers of the units of your project.

Therefore, in your code, you should better "get closer" units that belong to the project, because they are more used, than from other auxiliary units.

See you.



Object Pascal: Redefining Classes

$
0
0

Photo by Mpumelelo Macu on Unsplash

The redefinition of classes is a practical method to minimize the collision of names between classes, even using short identifiers.

Introduction

The Object Pascal language has a very useful feature which, I believe, is not widely used by developers.

I do not know if there is a specific name for it, but I named it "redefining classes".

In fact this feature can be used to redeclarate classes, constants, and even functions.

However, in object-orientation, we basically only use classes. So, forget the rest and let's focus on them.

Let's take a look at some techniques that can be applied using such a concept.

Renaming

Imagine that you want to use a class of some Lib but, this class has the same name — example TSmartMemory — of one of your classes, which you already use throughout your code. What to do?

The first option is to never use both classes on the same unit. But maybe you're not that lucky.

The second option is to prefix one of the Classes with the unit name — very common to see this in Java projects — for example:

    uses
      LibMemory,
      MyMemory;

    begin
      M := TSmartMemory.New;  // your class
      L := LibMemory.TSmartMemory.Create;
    end

The third option, which I use most of the time, is "rename" the class of Lib to a nomenclature that does not collide with the nomenclature already used in my project. Let's take a look at an example:

    unit MyMemory;

    uses
      LibMemory;

    type
      // TSmartMemory from LibMemory
      TLibStartMemory = TSmartMemory;

      // my new class
      TSmartMemory = class
        // ...
      end;

In the example above, both classes are declared in the same unit in the project — the MyMemory — and the project can use both classes without nomenclature collision.

    begin
      M := TSmartMemory.New;
      L := TLibSmartMemory.Create;
    end;

Using this technique we avoid name conflict, which is very useful.

Instead of using the real class name, we can give it an alias. The code stay cleaner, simple and using short identifiers, because we don't need to use the unit name as a prefix.

The C# language has something very similar which makes me wonder where the main architect of the C# language took out this idea.

Visibility

Many times we need to use a composition of different classes to solve a problem.

But, if each one of these classes has been declared into a different unit, we will need to declare all those units to get access for each one of those classes.

For example. We need of TClass1, TClass2, and TClass3. Each one of them into different units, Unit1 , Unit2 e Unit3, respectively.

    unit MyUnit;

    uses
      Unit1, Unit2, Unit3;  
      
    begin
      TClass3.New(
        TClass2.New(
          TClass1.New
        )
      )
    end;

If we need to use that composition in many places of the code, we will always have to remember which units these classes are in.

Another option is to make classes visible, redeclaring all of them in a single unit, for example Unit123, so that we can use them in a simpler way but still maintaining each implementation in different units.

    unit Unit123;

    uses
      Unit1, Unit2, Unit3;

    type
      TClass1 = Unit1.TClass1;
      TClass2 = Unit2.TClass2;
      TClass3 = Unit3.TClass3;

Now, just use Unit123 in the code to have access to all 3 classes that previously could only be accessed in different units.

    unit UnitTest;

    uses
      Unit123;  
      
    begin
      TClass3.New(
        TClass2.New(
          TClass1.New
        )
      )
    end;

This technique is very useful for simplifying an API, giving developers only a few classes for use in very specific contexts.

Inheritance

There are times when we want to use class inheritance — even though Object Composition is the best choice — however, we would like to use the same name of the ancestral class.

Let's imagine that we are developing a software and, into one of its units, has a class that represents a PDF file. We name this class as TPDFFile.

However, we know there may be tens or hundreds of Libs already working with PDF. So, let's named one of them of PDFLib, for example.

In PDFLib we have a class called TPDFFile which is exactly the same name that we have already decided that will be used in our software, but the project architect says that our class should inherit from PDFLib.TPDFFile.

I guess you already know the answer:

    unit MyPDFUnit;

    uses
      PDFLib;

    type
      TPDFFile = class(PDFLib.TPDFFile)
        // more methods
      end;

By prefixing the class of Lib, we can identify it differently from our own class declared in the same unit.

The TPDFFile class is now an extension of PDFLib.TPDFFile which belongs to an external Lib. But, for all the rest of the code in the project, there will be only the MyPDFUnit.TPDFFile class to represent a PDF.

Extending

The technique that I will show you now was already used even before to have a syntax for class helpers.

For example, imagine that you want to include new properties or methods in TEdit class. The first thought is to use inheritance to create a new component. However, you do not want to replace each TEdit in all TForm that already exist in the project. So, what to do?

The answer is still to use inheritance. But there is a trick or hack that I will show in the technique below. But I would like to remind you that this should be used very sparingly. I only used this technique very seldom and only for classes that represent widgets, that is, classes of components that are used in Forms.

To extend a TEdit without creating a new class and without having to change the Forms, just use the same technique above:

    unit MyStdCtrls;

    type
      TEdit = class(StdCtrls.TEdit) // or Vcl.StdCtrls.TEdit
        // more methods and properties
      end;

You do not need to change widgets in Forms. The design rendering of the Form will work using the resources (* .lfm * .dfm) correctly.

There is one trick you can not forget: In each of these Forms you will need to declare your unit after of the actual StdCtrls unit.

    unit MyForm1;

    uses
      StdCtrls, MyStdCtrls;

This hack is required for the compiler to find the declaration of your unit before it is found in the default StdCtrls.

That is why it is so important to have an order in the declaration of the units.

Optional Nomenclature

This technique can be considered the opposite of the first one shown in this article, ie., instead of you "renaming" a class belonging to another Lib, you will give to the developer some naming options for the use of their classes.

Imagine that you've coded a package with some classes. In this package you like to use simple names such as TStream, TMemoryStream, TString, TInteger, etc.

See that we already have some possible "problems" here. Let's see:

1. The TStream and TMemoryStream classes already exist in FPC or Delphi and, because that, there may be a collision of names if developers use your package, as it is very likely that they are already using such default classes names in their projects;

2. The TString and TInteger classes are classes with very simple or generic names and, again, it is likely either some other Lib or even the projects of these developers already use such names.

The problem here is the name clean and short. While these names are perfect, they have the great potential of generating some name collision problems.

But when you are creating your package, you have to abstract the external world. The context of the package that should influence the nomenclature of classes and not the external world that might use it!

I "fought" against this problem for many years. Before I "discovered" this technique, I prefixed my Classes with 1, 2 or 3 letters — this seems to be the standard used by all component developers in the market — however, you can find out over time that your "prefix" chosen for your classes have already been used in another Lib from third parties.

Imagine you have to use verbose names like TXyzMemoryStream throughout your code to then find out that Xyz is already a prefix used by a large "component maker" on the market.

Then, I discovered that the Object Pascal language already had an answer and I could have the best of both worlds. I could use simple, compact and clean names inside my context (package, project, lib) but giving to potential developers a more verbose, but with less possibility of collision of names, if so desired.

Let's look at an example: Imagine that you have a package with a class named TDataStream. This name already avoids the collision with TStream which is basically what this class represents, but the Data prefix was not used to minimize the nomenclature collision, but rather because of its semantics.

But, let's say either Lazarus or Delphi have now implemented a general purpose class called... TDataStream.

Should I change the name of this class in all my projects that already use this nomenclature? Of course not!

I would only give the option for (new) developers to use another nomenclature for the same class, like this:

    type
      TDataStream = class sealed(TInterfacedObject, IDataStream)
      // some methods
      end;
      
      TSuperDataStream = TDataStream;

The code now has 2 naming possibilities for the same class!

You can either continue to use TDataStream throughout your code, as long as you hold the declaration order of the units, or you can use the new TSuperDataStream option.

And, even if there is still a collision of nomenclature, it will be up to the developer to use the first technique of this article to solve it.

This way, both sides (package developers and package users) are free to use whatever names they want in their classes.

The only exception, as far as I know, are the components that are installed in the IDE. Both IDEs (Lazarus and Delphi) do not allow install components with the same name, even if they are in different packages.

Conclusion

The redeclaration or renaming of classes (and constants, functions, etc) is a technique that exists almost from the beginning of the language, but which the vast majority of developers do not use, either due to lack of knowledge, inability or lack of interest.

It is an old concept but it provides some techniques and possibilities for better encoding today, as demonstrated in this article.

See you.



Object Pascal: Immutable State

$
0
0

Photo by Morgan Harper Nichols on Unsplash

In object-orientation, an object can be considerable immutable even if it... changes.

Introduction

Learning a complex concept tends to be better absorbed if we divide the concept into small parts.

For example, when we begin to learn English, we are taught that to refer to something that happened in the past, we must use past verbs to make affirmations or use the modal verb did or did not to ask questions or denials. This is the verbal tense Past Simple.

Example: "I saw this movie".

Then, as you begin to study the language more, you discover that there are many other ways of expressing something that has occurred in the past. For example, the use of verb tense Present Perfect.

Example: "I have seen this movie".

Here we see the use of the modal verb to have and the use of Past Participle of the verb to see.

Both sentences say the same when we translate to Portuguese, for example, but the second sentence can be considered more correct than the first one — you only discover this after you learn the Present Perfect. But this is not an English article, so let's go back to object-orientation.

This introduction is to show you that we must first learn a concept in its simplest form; then we improved.

Concepts of Immutability

When you've learned about immutability you may have thought that an object is immutable if, after it is created, nothing is changed inside it or that the object always returns the same information when a method is called.

Well, that is not so simple.

Unlike functional languages, where everything is immutable by default, in object-orientation this concept may be broader.

Let's take a look in some concepts.

External content

A class that represents a file could be immutable in two ways:

type
  TFile = class
  private
    FFilePath: string;
    FStream: IDataStream;
  public
    constructor Create(const FilePath: string);
    function Stream: IDataStream;
  end;
  
  implementation
  
  constructor TFile.Create(const FilePath: string);
  begin
    FFilePath := FilePath;
  end;
  
  function TFile.Stream: IDataStream;
  begin
    if not Assigned(FStream) then
      FStream := TDataStream.New(FFileName);
    Result := FStream;
  end;

In the code above, the TFile.Stream: IDataStream method will always return the same value read on the first run.

The object is immutable and constant.

But, what if we change the method like below, the class will continue been immutable?

function TFile.Stream: IDataStream;
begin
  Result := TDataStream.New(FFileName);
end;

Yes, for sure.

Although the result of the method may be different for each call — the contents of the file can be changed by another process — the object would remain unchanged because its state (FFilePath attribute) has not been changed.

It is immutable, but not constant.

The same concept applies to content coming from a Database, Website, etc.

Content in Memory

Can a list of objects be considered mutable if we add items after it is created?

Let's take a look in this code:

type
TDataParams = class(TInterfacedObject, IDataParams)
  private
    FList: TInterfaceList;
  public
    constructor Create;
    class function New: IDataParams; overload;
    destructor Destroy; override;
    function Add(Param: IDataParam): IDataParams; overload;
    // ...
  end;
  
implementation

{ TDataParams }

constructor TDataParams.Create;
begin
  inherited Create;
  FList := TInterfaceList.Create;
end;

class function TDataParams.New: IDataParams;
begin
  Result := Create;
end;

destructor TDataParams.Destroy;
begin
  FList.Free;
  inherited;
end;

function TDataParams.Add(Param: IDataParam): IDataParams;
begin
  Result := Self;
  FList.Add(Param);
end;

The TDataParams class encapsulates a list of TInterfaceList.

At each inclusion of a new item, the in-memory persistence of the objects is delegated to this internal list.

Do you think we're changing the object state (FList)?

We are not.

The reason is that we are not redefining FList. We are not creating a new list.

A list of items is being created in memory — memory blocks — but the initial address of FList remains intact.

Also, FList is a secondary attribute, so we could even redefine this attribute without being in disagreement with the principle. But, if the list instance were passed in the constructor, then we could not redefine the object because it would be considered as a primary attribute.

Immutability of the State

If even after some internal or external changes to the object, it is still considered immutable, how do we know if we are not violating the principle of immutability?

Simple: If the state of the object, ie., its primary attributes, is not changed/redefined, then it is immutable.

Once an attribute is instantiated, it can not have its memory address changed. These attributes will be initialized in the constructor of the class and can never be reinitialized.

Your object must be faithful to arguments passed in the class constructor, however it is free to work and respond to whatever you want in your methods.

Conclusion

Immutability, in object-orientation, is not about internal or external changes to the object, but about not changing the primary state of it.

Do not confuse data with object state.

So, we need to work with these concepts in mind.

See you.



TMS announces a new training day: TMS RADical Web Day in Germany

$
0
0



We're excited to inform we are organizing a new training day: TMS RADical Web Day in Germany.

Learn everything about fascinating new ways to create modern new web development with Delphi!

When you're a passionate Delphi developer and interested in applying your skills for creating web applications, you cannot miss the TMS RADical Web Day.

On the TMS RADical Web day, you can:

  • Discover how to apply your Delphi knowledge to create high performance web applications.
  • Learn how RAD techniques can be applied to go web with components.
  • Learn how you can integrate existing web frameworks like jQuery.
  • Experience how to use REST services from your web applications.
  • Learn how TMS XData or Embarcadero RAD server data can be used from web apps.
  • Learn how you can now use FNC UI controls not only for VCL, FMX, LCL apps but also for the web.
  • Mingle with fellow Delphi developers.
  • Get a glimpse of the roadmap of future developments under the TMS RADical Web umbrella.
  • Talk in person to the experts from TMS software.
  • Receive a gift with the fully functional trial version of TMS WEB Core, samples and documentation.
  • Get 20% discount for one product of your choice, for your new licenses!

Organization

Sessions are presented by:

  • Bruno Fierens, CTO of tmssoftware.com + Embarcadero MVP
  • Roman Kassebaum, architect tmssoftware.com + Embarcadero MVP
  • Wagner Landgraf, architect tmssoftware.com + product manager TMS Business Subscription
  • Adrian Gallero, architect tmssoftware.com + product manager TMS Flexcel product line
  • Leon Kassebaum, Delphi & TMS WEB Core enthusiast

Location

This extraordinary event will take place at Hotel-Residence Klosterpforte, Klosterhof 2-3, 33428 Harsewinkel-Marienfeld, GERMANY. The location is easily accessible via the A2 motorway.


TMS software has chosen for Hotel-Residence Klosterpforte as it offers an inspiring and peaceful place in the midst of the nature and green to maximize your concentration & creativity. Facilities for hotel rooms at the event are optionally available for attendees.

Registrations

Early bird: 195 EUR (before May 1, 2018)
Regular price: 245 EUR

The registration fee includes a full day access to the sessions and coffee/drinks during this day. A 3 course hot meal is served for lunch.

Seats are limited. Don't delay your registration and reserve your seat!

Get more information or make your reservation here!

We look forward to see you!

Enable HTTPS in your REST server with Free SSL/TLS Certificate from Let’s Encrypt

$
0
0

One of the most important aspects of a REST API server is security. It should be mandatory that your data is encrypted while being transferred between client and server. And the “standard” way to do such encryption is using HTTP Secure (HTTPS).



To support HTTPS in your server, you need an SSL/TLS certificate. Not so long ago, this was a task that was relatively annoying/hard to do, and it would also require you to pay yearly fees for that. That’s not true anymore, since the release of Let’s Encrypt. From their website: “Let’s Encrypt is a free, automated and open Certificate Authority”. What does that means, basically? You can now have SSL/TLS certificates for free. And automatically!

The purpose of this article is to give you direct step-by-step instructions for you to install your SSL/TLS certificate for any TMS Sparkle-based server (like TMS XData, for example). Thus, if you want more info about Let’s Encrypt and how its system works, please visit their web site to learn more about how it works.

To install a Let’s Encrypt certificate in your TMS Sparkle server, we are going to use a tool named win-acme (Simple ACME Client for Windows, WACS - Windos ACME Simple). It was formerly called letsencrypt-win-simple (LEWS). The video presented at the end of this article was made when the tool still had its old name, so also some screenshots of this article will reflect that as well. But the process remains mostly the same with very small differences mentioned in this article.

In this example we are going to secure a server that responds to address http://app.devgems.com. To start with, you must have a domain name and your server must be working and responding HTTP requests to that domain name. Here is for example a screenshot of a browser request to that server. Note that it’s not secure yet



To download win-acme, go to the Releases link of its GitHub page https://github.com/PKISharp/win-acme/releases and download the latest version available. By the time this blog post was written the file name should be win-acme.v1.9.10.1.zip, but you might find a similar name with a most recent version. In case you want to use the exact version used for this server (to folllow exactly what is being done in the video and in the screenshots) you can download it from this link: https://github.com/PKISharp/win-acme/releases/download/v1.9.7.0-beta10/letsencrypt-win-simple.v1.9.7.0-beta2.zip.

Upload the downloaded file to the Windows server running your TMS Sparkle server, and extract it to any directory, for example C:\letsencrypt. You should have a folder with the files like the following:



Notice the selected file above, named letsencrypt.exe.config. It’s the config file for the tool. In most recent versions, that file would be named settings_default.config. Whatever is the name you have there depending on your version, open that file in a text editor (Notepad, for example) and search for a setting named CertificateStore. Change the value of that setting to “My”. The section of the file should look like this:

<setting name=“CertificateStore” serializeAs=“String”>
  <value>My</value>

In the same folder, create a file named bindcertificate.bat with the following content:

netsh http delete sslcert ipport=0.0.0.0:443
netsh http add sslcert ipport=0.0.0.0:443 certhash=%1 certstorename=%2 appid={00112233-4455-6677-8899-AABBCCDDEEFF}

The GUID in appid above could be anything. You can change to a GUID value you want, or just use what's there. You should then have your new file in the folder:



Now open command-line with administrator rights, go to C:\letsencrypt folder if you are not already there, and run the following command. Please don't forget to replace <yourdomain> by your real domain. In the case of our example here, it would be app.devgems.com

letsencrypt --plugin manual --manualhost <yourdomain> --validation selfhosting --script "c:\letsencrypt\bindcertificate.bat" --scriptparameters "{5} {3}" --usedefaulttaskuser

Depending on the version of the tool you are using, you might be asked to enter your e-mail address and agree to the terms of condition. The e-mail address will only be used by Let's Encrypt to notify you about certificate expirations. You will only have to do that for the first time.

If everything went ok, you should have an output like this indicating the certificate was generated and installed in your computer:



You can open the MMC Snap-in to check that your certificate is installed properly:



And that's it! Not only the certificate is now installed in your server computer, but it is also configured to your TMS Sparkle server and will be renewed automatically. Your server now supports HTTPS forever! If we browse to our server address now using HTTPS, we can confirm it's using the new certificate:



The following video shows in much more details the operation described above, including using the "test" flag to test the whole process in a test environment before using the production one.



Overview of what's coming on the TMS RADical Web Day, May 24th in Germany

$
0
0

Here is an overview of what is waiting for you on the first TMS RADical Web Day on May 24th in Germany! You will experience first-hand from the experts of TMS software all details, inner-workings, examples, architecture, roadmap, binding to server, etc... for exciting new ways to create modern web applications for Delphi developers.


Check the full details and registration form link here: https://www.tmssoftware.com/site/tms-training-day-20180524.asp?ln=EN
The TMS software team looks forward to see you. Don't hesitate and sign-up for this exceptional training day!


May 25 is TMS XData training day, the day after TMS RADical Web Day

$
0
0

Our TMS XData expert Wagner R. Landgraf travels from Brasil to Germany especially for the TMS RADical Web training day on May 24th at Marienfeld, Germany. TMS XData is the tool for Delphi developers to enable creating fast, easy and secure REST APIs to access cloud databases from desktop, mobile and web client applications. As there is a demand for in-depth training on this powerful TMS XData product, we decided to also offer a possibility for training on TMS XData on May 25th, the day after the TMS RADical Web training day and available for an ultra limited number of developers to ensure a personal, hands-on and very interactive training.

TMS XData Training Day (all sessions in English)

09h00 - 09h30
Welcome, coffee, meeting

09h30 - 10h30
1. Introduction to TMS Sparkle and TMS XData
a) Presenting TMS Sparkle concepts: http.sys, modules, example server
b) Creating a XData module with a “hello world” operation
c) XData overal concepts: service operations and entities

10h30 - 11h00
Coffee break / Instructor available for questions and discussion

11h00 - 12h00
2. Service Operations
a) Creating service operations - interface and implementation
b) Parameter passing: in body, in url
c) Supported parameter types: scalar, structured and PODO
d) Parameter by reference
e) Memory Management
f) Using/receiving TStream

12h00 - 13h30
3-course warm lunch / instructor available for questions and discussion
13h30 - 15h00
3. Database access
a) “Traditional” approach
b) Connection Pool
c) Aurelius integration in service operations
d) Entity publishing: CRUD operations
e) Querying, paging and counting entities
f) Entity set permissions

15h00 - 15h30
Coffee break / Instructor available for questions and discussion

15h30 - 16h15
4. Desktop client-side development
a) TXDataClient overview
b) Invoking service operations
c) CRUD operations from client
d) Memory management

16h15 - 17h00
5. Web client-side development
a) TXDataWebClient overview
b) TXDataWebDataset usage
c) Asynchronous paradigm

17h00 - 17h30
Closing, questions and answers.

Alternative advanced topics that can be handled on-demand:
a) JWT and authentication
b) Server-side events
c) Custom error-handling in server
d) Swagger/OpenAPI


The TMS XData training day price is 295EUR. For Delphi developers attending both the TMS RADical WEB training day and TMS XData training day, price is 395EUR. Contact us directly by email sales@tmssoftware.com for registrations. Contact us as quickly as possible as registration is on a first-come, first-serve basis.

Statistics extension for TMS Analytics & Physics developing library

$
0
0

TMS Analytics & Physics developing library includes many extensions for various mathematical applications: complex numbers, linear algebra, special functions, common fractions, numerical methods. New version 2.4 introduces package for statistical analysis. The extension allows evaluating base statistical properties of real data samples (mean value, median and others), generating sequences of special numbers (Fibonacci, prime numbers and many others), creating arithmetic, geometric and harmonic progressions, working with probability distributions.

It should be noted here, that as the Analytics library allows symbolic evaluations of very complicated formulae, some statistical problems can be solved without using the special package. For an example, the Linear Algebra package includes functionality for processing array and matrix data. So, we can solve, for an example, the following problem: find the sum of ‘A’ array elements those are greater than ‘x’. The result can be calculated with the following code:



The output for the code is the following:



The problem is solved with the ‘if’ function that compares all items of the ‘A’ array with ‘x’ value and generates new array which contains elements of ‘A’ if the condition satisfied and 0 value if not. When the sum of the result array calculated we get the solution of stated problem. The goals of new Statistics package is providing the simplest formula for evaluating base statistical characteristics and solving statistical problems that cannot be solved without specialized library. First, let us consider evaluation of base statistical characteristics of some discrete sample values, stored in ‘A’ array. This can be done with the following code:



For this data, we get the following statistical values:

Mean of A = 0.155625
Median of A = 0.135
Mode of A = 0.1
Variance of A = 0.012124609375
Deviation of A = 0.440447215906742

As can be seen from the code above, every value calculated with one function call. The function ‘Mean{P}(A)’ here evaluates the mean value of the data. This function is parametric and the ‘P’ parameter specifies the ‘power’ of the mean (https://en.wikipedia.org/wiki/Mean#Power_mean). The parameter value can be one of the four: ‘-1’ – harmonic mean, ‘0’ – geometric mean, ‘1’ – arithmetic mean, ‘2’ – quadratic mean. In our case P=1 and we calculated the arithmetic mean of ‘A’. One of the advantages of using the symbolic capabilities of the Analytics library is that, even if some feature is not realized in the package directly, one can use the formula for this feature. Let us consider how to do this for other types of ‘mean’ values. There is so called generalized mean (https://en.wikipedia.org/wiki/Mean#Generalized_means) that is defined by the formula:



where f is a function and f-1 is its inverse. For an example, if f is exponent, then f-1 is natural logarithm. The ‘exponential’ mean function is not provided with the statistical package, but it can be easily evaluated with the following simple formula:



which produces the output:

Exponent Mean of A = 0.161840327746035

The value of ‘exponent’ mean is slightly differs from common arithmetic mean that follows from the different meaning of the characteristics.

One of main features of Statistics package is that it allows working with probability distributions and solve real statistical problems (https://en.wikipedia.org/wiki/Probability_density_function). The version supports 6 distributions: Gauss (normal), Laplace, Cauchy, Gumbel, logistic and exponential. Let us consider the following statistical problem: there is a known probability distribution for lifetime of a bacteria species. Let us suppose the distribution is Gaussian function with parameters µ and s (https://en.wikipedia.org/wiki/Normal_distribution). We need to calculate the probability that the bacteria dies on the time interval [t1..t2].
This probability defined by the formula:



where f(x) is the probability density function (PDF) of the distribution. The value of the probability can be evaluated with the following code:



First, we added the variables for the distribution’s parameters to the translator and variables for the time interval. The function 'GaussPDF{µ s}(t1 t2 100)' produced the array of 100 values for the Gaussian PDF with specified parameters (µ=5 hours, s=0.5 hours) on the specified interval of [5.5..6.0] hours. Then we used numerical integration of the values, replacing the integral with the appropriate summation. The answer for our question is - the probability that the bacteria dies on the interval 5.5-6 hours is about 13.6%. The version 2.4 is already available. Source code of the example application for statistics analysis can be downloaded from here.

Real-time communications with WebSockets in TMS WEB Core applications

$
0
0

TMS WEB Core promises easy, fast and RAD component based web application development. For fast, real-time updates on a web page with light-weight server-communications, WebSockets are an ideal mechanism.
That is why TMS WEB Core also comes with a WebSocket client:

This is a non-visual component that makes it very easy to start using WebSocket based communication. Drop this component on the form, configure the WebSocket hostname & port and call WebSocketClient.Connect. When a connection is established, the OnConnect event is triggered. From the moment of connection, data sent by the WebSocket server is received via the event OnDataReceived. The signature of this event is:

procedure OnDataReceived(Sender: TObject; Origin: string;  Data: TJSObject);

Origin is the WebSocket server sending the data and the data itself is sent as a JavaScript Object. This means it can be different types. Sending data is equally easy. Simply call
WebSocketClient1.Send(AMessage: String);

To create an online chat application using this WebSocket technology takes only a few configurations in the component to configure the WebSocket server and a couple of lines of code. There is the logic that performs the Connect & Disconnect:
procedure TWebForm1.Connect;
begin
  if FConnected then
  begin
    WebSocketClient1.Disconnect;
  end
  else
  begin
    if WebEdit1.Text = '' then
      ShowMessage('Please enter a name first')
    else
      WebSocketClient1.Connect;
  end;
end;

To send a message when connected, we simply send the message as color/sender/message pair via the WebSocketClient.Send() function. Each chat user can choose a color and messages from the user are displayed in his selected color:

procedure TWebForm1.SendMessage;
var
  s: string;
begin
  if FConnected and (WebEdit2.Text <> '') then
  begin
    s := TMSFNCColorPicker1.SelectedColor) + '~' + WebEdit1.Text + '~' + WebEdit2.Text;
    // limit message length
    s := Copy(s,1,256);
    WebSocketClient1.Send(TTMSFNCGraphics.ColorToHTML(s);
    WebEdit2.Text := '';
  end;
end;

To display the message, we use the web-enabled TTMSFNCListBox component from the TMS FNC UI Pack. With this control we can show the received messages in listbox items with banding and some HTML formatting per item to indicate the sender and the message. The message is received via WebSocketClient.OnDataReceived as text and therefore we can use Data.toString to get the JavaScript object as text:
procedure TWebForm1.WebSocketClient1DataReceived(Sender: TObject; Origin: string;
  Data: TJSObject);
var
  it: TTMSFNCListBoxItem;
  sl: TStringList;
  s: String;
  n: string;
  c: TTMSFNCGraphicsColor;
  v: string;
begin
  it := lst.Items.Add;
  s := Data.toString;
  sl := TStringList.Create;
  try
    TTMSFNCUtils.Split('~', s, sl);
    if sl.Count > 2 then
    begin
      c := TTMSFNCGraphics.HTMLToColor(sl[0]);
      n := ''+sl[1]+'';
      v := sl[2];
      it.Text := n + ' says:
' + v; it.TextColor := c; end; finally sl.Free; end; end;

There isn't much more to creating a chat application for your TMS WEB Core applications except of course to put a WebSocket server application on your server that can equally be written with Delphi. With TMS WEB Core we include a sample WebSocket server service application.
Thanks to TMS WEB Core, you can directly see the result of our demo in your favorite web browser, no need to install anything to explore! Head over to http://www.tmssoftware.biz/tmsweb/demos/tmsweb_chatclient/ to start chatting.

TMS WEB Core chat client application running in the Chrome browser

TMS WEB Core chat client application running in the Safari browser on iPhone


Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

This was TMS RADical Web Day, May 24 at Klosterpforte, Germany

$
0
0



Without a doubt, this was THE day our team looked forward to as well as many Delphi developers. The TMS RADical Web day was all about devoting a full day to the new web development tools being worked on by the tmssoftware team. We had chosen a place for this event in a peaceful green area of Germany, Klosterpforte, Germany. It would allow us to exchange the latest informations without any distractions from hectic & stressfull city life, away from busy & stressfull days company life typically brings.

With a group of about 40 persons, we not only presented the latest status of the developments of the TMS WEB Core framework, the web-enabled TMS FNC framework, TMS XData REST server technology, Flexcel reporting technology, Embarcadero RAD server technology, but we also listened closely to your needs, suggestions, concerns and questions. In short, we hope not only the attendees learned a lot, our team also learned a lot. In short, it was a very fruitful day. After the TMS RADical Web day, there was an even more in-depth day focused on TMS XData REST server technology. A group of about 10 Delphi developers intensively learned & discussed the many possibilities TMS XData REST server offers.

I especially want to thank for all the hard work delivered from the team present: Wagner Landgraf, Adrian Gallero, Pieter Scheldeman, Roman Kassebaum, Leon Kassebaum, Detlef Overbeek, Mattias Gärtner, Matthias Eissing.

If you missed this event, don't worry. Next, there will be a presentation about TMS Web Core at the Italian Delphi Day on June 7 in Piacenza and there is a meetup planned on June 12 in the offices of TMS software.

If you are hosting other events where you'd wish to see TMS WEB Core in action, please contact us and when feasible we'll consider coming to a place near you!

Meanwhile, the team is hammering out as much as possible the last niggles & issues and working feverishly to bring the first release as soon as possible.

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

Article & sample for how to use Embarcadero RAD server as server backend for TMS WEB Core applications

$
0
0

TMS WEB Core is a framework for creating web client applications from the Delphi IDE in the Delphi language and using RAD component based development. TMS WEB Core is designed to be totally open in many ways, also with respect to binding to a server back-end. This binding to the server back-end is typically done using REST APIs. TMS software has its own high-performance, flexible and low-cost REST API framework TMS XData for accessing databases on a server but it is equally possible to use node.js, ASP.NET Core microservices, other technologies or also the Embarcadero RAD Server that comes with Delphi (there is now one free license included in the Delphi Enterprise or Architect editions) and that offers a powerful, fast & flexible creation of REST API endpoint servers.

  

Embarcadero MVP, famous speaker and writer of several Delphi books Bob Swart, was excited when he learned about TMS WEB Core and wanted to explore the capabilities of using Embarcadero RAD server as a backend for a TMS WEB Core web client application. Based on the results of his research and work, Bob Swart did the effort to create an article that explains and demonstrates how one can use Embarcadero RAD server with TMS WEB Core from start to finish. There is not only the article that Bob Swart makes available but also the sample source code.

Downloads

Article:

Source code:



Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

Viewing all 1008 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>