text: 2nd Edition
  By Erick Engelke
  erickengelke@gmail.com
  Kitchener, Canada
  All rights reserved. No parts of this book may be reproduced, stored in a retrieval system
  or transmitted in any form or by any means without prior written permission from the
  author, except in brief quotations embedded in critical articles or reviews.
  Every effort has been made in the preparation of this book to ensure the accuracy of the
  information presented. However, the information in this book is sold without warranty,
  either express or implied. Neither the author, the publisher or its affiliates, dealers and
  distributors will be held liable for any damages caused or alleged to be caused directly or
  indirectly by this book.
  The author has endeavored to provide trademark information about all the companies and
  products mentioned in this book by the use of capitals. However, the author and publisher
  cannot guaranty the accuracy of this information.
  I am very grateful for the keen proofreading and eternal patience of Tim Young of Elevate.
  In 1995 there was a new product called Delphi which revolutionized Windows
  development for many programmers. It introduced the Object Pascal language and the
  Visual Component Library (VCL) which greatly simplified writing Windows applications,
  and database applications in particular.
  The idea was called RAD for Rapid Application Development and it benefitted small
  shops and individual programmers because they could quickly produce applications which
  competed with big firms, and it helped big firms because they could do more… faster.
  In the years since, Delphi has been reworked to support native Linux, Android, IOS and
  Macintosh applications. Its open source cousin: Free Pascal with Lazarus have supported
  these and other platforms too. Their motto is ‘write once, compile anywhere’.
  Several groups have translated Delphi’s basic architecture to Web applications which
  generate JavaScript as the run time language. The two I have used are Smart Mobile Studio
  SMS and Elevate Web Builder or EWB. They are not identical to Delphi, but still so
  similar one feels eerily at home..
  This book focuses on EWB. I think it marks an epoch in Web development that ushers in an
  age of reasonable tools for fast and reliable production of Web pages.
  If you have a Delphi background, you will be instantly familiar with much of EWB. But
  even newcomers will find it inviting. By basing the product on the ideas of Delphi, the
  Elevate developers have inherited a lot of well-tuned principles.
  Pascal is a wonderful language. It has the power of C and thus has been used to write
  whole operating systems, but unlike C and its derivatives (C++, JavaScript, PHP), it has
  very strong type checking. I believe the loose typechecking of these other languages leads
  to many bugs and run-time errors because the execution does not match the programmer’s
  intent.
  With Pascal, the compiler knows exactly how you have defined a variable or constant or
  object, and it uses it only in that manner. This not only makes your execution more
  predictable, it means most programming errors are found at compile time and not when
  your users go to execute the code. It also means the compiler can use efficient strategies,
  and that leads to fast execution.
  There is an excellent reference to the general Object Pascal language written by Marco
  Cantu. It makes a great read and a reference text, and it is applicable to EWB, Free Pascal,
  Delphi and others.
  EWB is a product of Elevate Software in the state of New York, USA. They started out in
  1998 with database technologies which they sell world-wide. In 2011 recently they
  branched into web development with EWB.
  I found they have excellent customer service with product support being provided by the
  actual developers as well as many satisfied customers.
  They test their products rigorously using automated tests, so you are not likely to discover a
  bug.
  EWB is written in Delphi and bears a strong resemblance to the Delphi Integrated
  Development Environment.
  There is also a command line version of the compiler for those who chose not to use the
  IDE.
  When you are ready to ship your completed application, you can chose to compress the
  source code. This converts it to minimalist JavaScript functions, variable names and
  spacing to compress the size of the output files, and effectively obfuscates it from easy
  reading or modification.
  For a typical project, compressed and obfuscated HTML and JS files typically hover
  around 1 MB total, which is the size of a typical Jpeg file and can easily be loaded by
  phones and other network devices on cellular, Wifi and other Internet options.
  I will focus on the most popular applications, which are Form based applications. You can
  create other pages without using the libraries, but I feel that is best done as an advanced
  project, if at all. The libraries benefit you with the wisdom and experience of several years
  of development and refinement. And the cost (in size and performance) is low.
  The reader is assumed to know some programming language like Pascal, C, PHP, C++,
  JavaScript or similar.
  This is not a definitive introduction. There are many texts which spend hundreds or
  thousands of pages doing justice to that topic. Instead, this is intended to get a typical
  programmer up-to-speed in EWB’s implementation of Object Pascal.
  Pascal is a case-insensitive language. You can use any combination of capitalization at any
  time, so: myObject is the same as MyObject. Just try to follow some convention or your
  code will look ugly.
  EWB uses Unicode for all elements. It is capable of creating applications for any Unicode
  language. However, EWB cannot support some Eastern languages in the Code Editor.
  For comments, EWB supports C++like // single line comments and { } for multiline
  Delphi allows dynamic and static range arrays. EWB only supports dynamic arrays. They
  are always zero based, and the size (length) of the array must be set in code, just like
  dynamic arrays in Delphi.
  If you do not come from an OOP backgroup, objects are like C structures but on steroids.
  Not only do they contain data, they do so much more. They contain methods, which are
  functions and procedures that implement functionality for the object.
  Objects offer:
  Encapsulation: The object is self-aware. It can contain data that only the objects methods
  can access, and it can present that data in special ways. For example, it can act like an
  array, but when you access an element, one of the methods is called to perform an action
  such as update a cell in an on-screen table. So the upstream program is simplified because
  it just appears to access a read-only, read/write or write-only attribute, but in reality it is
  calling code.
  Inheritance
  Classes descend from other classes and inherit their strengths, while adding or replacing
  functionality. This creates a class hierarchy with no limit on its depth.
  EWB only supports single inheritance, meaning classes have a single parent, which can
  also be a descendants of still other classes. This differs from some languages which permit
  classes to inherit from one or more direct classes.
  Much has been written about the argument of whether single inheritance is better or worse.
  I’ll simple leave it as a fact that many great programs have been written with single-
  inheritance languages and that it is simpler to understand and implement.
  If no inheritance is specified, the class will inherit from TObject. Classes can have four
  types of members:
  The protected section of a form is not used for anything in the IDE - the IDE manipulates a
  special section that is internally called the designer public section. You'll notice that the
  IDE puts things in the section at the top with no label - that's the designer public section. It
  has the same scope behavior as public.
  Private will be for variables and methods you create which only your class can use. By
  default, put all variables and methods into private.
  Public is the designation for all variables and methods you wish to expose to other classes
  and procedures. Move variables and methods to Public when you realize they need to be
  accessed externally.
  Object methods can be simple functions and procedures, they can also be declared as
  virtual, abstract and override.
  Virtual methods can be overridden in descendant classes.
  Abstract methods indicate the virtual method is NOT implemented in the base class, but
  must be implemented by descendant classes. Your application will not compile until you
  implement the functionality – which in turn reduces the problem of not implementing all the
  requirements.
  Inherited methods can augment the functionality in a base class, and can even call the base
  class function.
  Overloaded methods have multiple declarations. Such as add( x, y : integer) :
  integer;
  add( x, y : double ):double; overload; Note that EWB, unlike several
  other Object Pascal variants, does not require you to use the overload keyword.
  Constructors and Destructors are special methods that handle the process of creating and
  destroying instances. In Delphi the constructors and destructors allocate and free memory –
  which is not necessary in our JavaScript environment. However, they are also useful for
  initializing variables and cleaning up afterwards.
  Typically, you will not create files like C’s Header files which are separate from the
  source code (.H files in the C example). Instead, a declaration section at the top of the
  Pascal file does a similar thing.
  unit Main;
  interface
  // types, variables, objects and methods used
  // and implemented in this file
  implementation
  // the rest of the file is private to this file
  end.
  Pascal is a single-pass language meaning the compiler only reads through the source once,
  whereas C is typically a two to four pass language. As a result, Pascal compiles much
  faster, but it must be organized more carefully.
  If you define, say, TClassDog, and it descends from TClassMammal, then you must define
  TClassMammal before you define TClassDOG.
  Functions and procedures may be passed variables, but these variables only have scope
  inside the method called.
  These methods can also reference variables and methods specified in the current class.
  Pascal has the love-it-or-hate-it WITH keyword, where you can specify: WITH
  InstanceDog do
  ….
  so you do not have to specify the variable name on each line. There are many arguments for
  and against this keyword. I’ll leave it to you, but remind you that WITH overrides the
  normal scope of any local or class
  variables/properties/methods.
  Most modern programming languages let you cast from one variable type to another.
  We will use an example later where we iterate through visual components on the screen
  and only react to TButtons by using is to query the class type. is does not simply look at the
  current class type, it works for all inherited types too.
  var
  i : integer;
  c : TComponent;
  but : TBbutton;
  begin
  for i := 0 to Component.Count -1 do begin c = Components[i];
  if ( c is TButton ) then begin
  but := TButton( c );
  but.Caption := ‘a button’; end;
  end;
  Good programming deals with exceptions you never expected, and those that you did
  anticipate too.
  In Object Pascal, the keywords are try, except, on exception, and raise.
  For example, if the user tries to enter negative money, you should raise an exception.
  If ( a < 0 ) then
  Raise Exception.Create(‘do not use negative money’);
  The component library and the run-time raise exceptions whenever necessary. Use
  try..except to handle exceptions.
  try a := StrToInt( edit1.Text );
  except
  ShowMessage(‘Could not convert ‘+edit1.Text+‘ to a number’);
  end;
  Or you can access the exception class variable to print out the general exception
  information.
  try
  a := StrToInt( edit1.Text );
  except
  on E: Exception do
  ShowMessage(‘Error:’+E.message); end;
  In the exception handler you can re raise the exception for the next stacked exception
  handler.
  Object Pascal also implements a finalize section to implement code that always executes
  whether an exception is raised or not.
  try
  …
  finally
  .// this code is always called
  end;
  Visual applications have a default handler if you do not handle the exception. It normally
  prints a generic message with the exception text. You can define a TApplication.OnError
  event handler which can do other things, such as give your phone support number.
  EWB is not an island to itself. You may also wish to call external JavaScript libraries or
  access variables in the Document Object Model (DOM), etc. Remember that JavaScript is
  case sensitive, so you must be careful with casing of references. However, only the
  developer of external interfaces must be concerned with case sensitivity of JavaScript, so
  application code which references it from EWB Pascal is free to use any capitalization you
  choose. EWB will emit the JavaScript using the case of the external interface definition
  and not the case of the references to it.
  The most common example of external interfaces is to access the Window’s URL. Here we
  see how to switch to Google’s home page.
  uses webdom;
  s := ‘’; window.location.replace( s );
  Like Delphi, EWB uses a message queue to sequence operations. Async is used to schedule
  future code execution. We have a whole chapter on this later.
  One of the most used object classes is TStrings and its relative TStringList which both
  encapsulate lists of strings.
  After you create() a TStringList, you can add strings with member functions add(), delete().
  You can access individual lines as though it were an array of strings. And you can deal
  with the entire list as though it were a single string using the .Text attribute; You can sort()
  and find() strings.
  If you assign strings with a NameValueSeparator (defaults to =), you can use it as though it
  were an associative array.
  Eg.
  var
  sl : tstringlist;
  name : string;
  age : integer;
  begin
  sl := tstringlist.Create;
  sl.add(‘Name=Erick’);
  sl.add(‘Password=Friday’); sl.Values[ ‘Age’] := ‘49’;
  name := sl.Values[‘Name’]
  age := IntToStr( sl.Values[‘Age’]);
  end;
  The visual form designer is comprised of the form, the tabbed units editor, and the
  components one can select.
  The object inspector show properties and events related to a selected component. You can
  select something visual, like a button, something nonvisual, or even the form itself to adjust
  its properties and events.
  A messages window at the bottom shows messages such as the compiled size, or errors if a
  compiler error is being reported to you.
  If you select Project | Options | Application, you can set the title where appears on the
  browser’s header. This step is necessary to have a professional looking page.
  So we have a blank form. As a matter of practice, save the files right away and run the
  form by pressing F9 or Run | Run. It will wish to save the form and the project, put them in
  a new subdirectory to keep things organized.
  EWB will then show the empty form. Not very interesting yet, just a blank form. Press the
  close X button above the blank page, this will return to edit mode.
  From the Visual Objects collection on the upper right hand of the screen, pick the T icon
  and then tap on the empty form to place it anywhere on the form. This is a text label, it
  displays text. Being the first TLabel on your form, it will be called Label1. TEdit is the
  class name, Label1 is the instance name.
  Then move your mouse over the other icons until you find TButton, which is a button Place
  it on the form too: Button1.
  Double click on the button you just placed. This will open the code editor on the button’s
  OnClick event handler, the method called when one clicks on a button.
  This is a program. Press F9 to Run it. Both the label and button are visible, but they say:
  Caption, which is the default text for the Caption property. But when you press the button, it
  changes the Label1’s Caption property to ‘hello’, and through encapsulation, that updates
  the screen automatically.
  begin
  i := Edit1.Text;
  Label1.Caption := i + 1;
  end;
  This will not compile when you press F9, because i is an Integer type and Edit1.Text
  (which is the user input) is a string and not all strings can be turned into numbers. And it
  would also complain because integers cannot be converted to strings in the next line
  begin
  i := StrToInt(Edit1.Text);
  Label1.Caption := IntToStr(i+1);
  Now it compiles and runs. Enter a number and we will show the following integer.
  But you could still enter a text string like George instead of a number, and you will get an
  error message: Invalid Integer Value and a line number like 619.
  Let’s see the actual code. Open the output subdirectory from your source subdirectory and
  you will find both an HTML and a JS (JavaScript) file. The error refers to the StrToInt()
  function which is implemented not in Pascal but in JavaScript.
  function strtoint($0)
  {
  if ($0 != "" && $0[0] == "0" && ($0[1] == "x" || $0[1] ==
  "X"))
  var $1 = parseInt($0,16); else
  var $1 = parseInt($0,10); if (!isNaN($1))
  return $1;
  else
  throw "Invalid integer value";
  };
  Yes, your code is converted to JavaScript and executed by the JavaScript engine in your
  web browser.
  A nice way to deal with this is using Try/Except exception blocks.
  procedure TForm1.Button1Click(Sender: TObject); var
  i : integer;
  begin
  try
  i := StrToInt(Edit1.Text);
  Label1.Caption := IntToStr(i+1);
  except
  Label1.Caption := 'That was not a number';
  When an error arises, the Try/Exception block jumps to the Exception code and executes it.
  If there are no exceptions, the Exception block never executes.
  The complete source code to our form is:
  unit Unit1;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebLabels, WebBtns,
  WebEdits;
  type
  TForm1 = class(TForm)
  Label1: TLabel;
  Button1: TButton;
  Edit1: TEdit;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  implementation
  procedure TForm1.Button1Click(Sender: TObject); var
  i : integer;
  begin
  try
  i := StrToInt(Edit1.Text);
  Label1.Caption := IntToStr(i+1);
  except
  Label1.Caption := 'That was not a number'; end.
  Let’s clean it up a bit. Going back to the Visual Form Designer, look to the left of the screen
  and you will find the Object Inspector. Click once on the Label1 and the Object Inspector
  will show its default values. Caption is set to Caption, change this to enter a number. This
  changes the startup value of the Caption.
  Click once on the button1 and it its Caption to Go. Now your application looks better. You
  can drag the visual controls around the screen to make the position nicely.
  There is only one other piece of code to write, and it is mostly hidden and usually
  automatically written, it’s the project Application source.
  Go to Project | View Source and you will find something like:
  project Project1;
  contains Unit1;
  uses WebForms, WebCtrls;
  begin
  Application.Title := '';
  Application.LoadProgress := False;
  Application.CreateForm(TForm1); Application.Run;
  End
  We will explore this code later, but for now the important thing is that it creates
  TForm1/Form1 (our form had a name), and then it runs the application, which is all the
  open forms, of which there was simply Form1.
  We will change the application again to show how live it is. Go to the System tab on the
  Visual Form Designer and place a TTimer on the form. The TTimer is a non-visual
  component meaning it doesn’t display anything. Double click on it and enter the following
  code it its Timer1Timer event handler.
  Using the Object Inspector you can change the Interval parameter from 1000 ms to 10000
  for every 10 seconds. The beauty of EWB is that you write clean simple functions instead
  of messy JavaScript which is error prone.
  Our last change shows a useful tool for displaying answers and can help tremendously in
  debugging: using ShowMessage() which pops up a message on the users screen
  In our previous example, the time would overwrite the user’s results, and this is not ideal.
  So change the code for the Button1 to:
  procedure TForm1.Button1Click(Sender: TObject); var
  i : integer;
  begin
  try
  i := StrToInt(Edit1.Text);
  ShowMessage( IntToStr(i+1 ), ‘debug’);
  except
  ShowMessage( 'That was not a number',’debug’); end;
  end;
  Run your app again. Now input generates a Modal message box that blocks all input until
  the user presses Ok. Unlike in Windows or even alert() in JavaScript, this box does not halt
  program flow, the program keeps executing but input is blocked. This behavior is due to the
  Message Queue which we will examine later.
  There are some things to note. EWB applications are SPA or Single Page Applications,
  like Gmail, Facebook, etc. This means you load a page once and do everything without
  experience fast and responsive to users. It feels like a Windows program. And now web
  apps are as easy to write as Delphi Windows programs.
  Your application can access the network, and we will do plenty of that in time, but
  typically it will do AJAX (Asynchronous JavaScript And XML) calls to a server and
  update itself as needed in the background.
  Only the simplest apps have a single form, real apps usually have multiple forms that either
  appear simultaneously or in some sequence.
  With EWB you can have as many open forms as you please (and your JavaScript run-times
  allow), easily in the hundreds if not more.
  Each form type is written in a separate source file, however, you may create several
  instances of the same form type, in which case all instances would be based on the same
  file.
  Simply take your single-form app as we had in the previous chapter and add more forms by
  pressing File | New | Form and then selecting the base class for your Form. Make this one
  of type TDialog..
  Press F9 to run, and you will see there are two forms created, one will be over the top of
  the other. You can grab the dialog box by its top and drag it off of your old Form1.
  Our problem is that Form2 is being create and displayed along with Form1 by the
  Application’s source. So fix it by editing Project | View Source
  project Project1;
  contains Unit1, Unit2; uses WebForms, WebCtrls;
  begin
  Application.Title := '';
  Application.LoadProgress := False;
  Application.CreateForm(TForm1);
  Run the program and we only see the one form. Place a TLabel on Form2. It’s time to get
  into the good habit of always changing your components to useful names, so go to the object
  inspector and change its name property to: lbUserAnswer which stands for Label User
  Answer.
  i : integer;
  begin
  if not Assigned( Form2 ) then
  Form2 := TForm2.Create( Application );
  try
  i := StrToInt(Edit1.Text);
  Form2.lbUserAnser.Caption := IntToStr( i + 1 ); Form2.Show;
  except
  ShowMessage( 'That was not a number'); end;
  end;
  which indicates the module references things in the Interface section of the Unit2 file which
  has our second form. Press F9 and your program will display its output in the new output
  window.
  The Form2 variable is defined as type TForm2 in Unit2, which we included in the uses
  statement.
  We use if not Assigned( Form2) because by default the object/TForm1 is not assigned any
  memory – well, it was assigned, but we commented that out in the Project Source, so it
  must be created manually.
  Form2 := TForm2.Create(Application) creates the object and sets all the parameters to
  their defaults, including all the parameters of all visual and nonvisual components of the
  form.
  Form2.Show shows the form, because merely creating and modifying a form isn’t enough,
  you have to show it too.
  - EWB generates a single web page (SWP) no matter how many forms are visible and how
  many buttons one presses
  - Forms are each designed in a separate unit
  - Forms are auto-created in the Application source, you must comment them out if you do
  not want them created and displayed at start time.
  - You must instantiate each form variable with
  TFormN.Create(Application).
  - The only global variables we know about (so far) are Application, Form1 and Form2.
  The rest are objects within these object classes. The next few chapters introduce you to
  classes available in the Visual Form Designer. The online help is a complete and updated
  reference; my goal here is to describe the controls and list their most noteworthy
  parameters.
  Among the classes you can drop in a form, the most common are from the Standard group.
  They are almost all text-based, though some have optional icons.
  The label is usually text, numbers, and other things which are being presented. These are
  cornerstones of your visual form. You can update the Caption at any time to update the
  display.
  Like most controls, it is possible to edit the many object attributes. Some commonly
  changed ones are:
  • AutoSize – typically leave as true, otherwise you must adjust the size if you reassign the
  Caption
  • Caption – the text to display
  • Font parameters, which include Color, GenericFamily and Size
  • Background, which includes Fill… Color to highlight a text field
  • Format … Wrap to turn on line wrapping
  • Tag – which can hold an arbitrary number, useful for holding any data number you want
  • OnClick() event handler.. yes labels can receive events, and OnDblClick() double click
  handler.
  • OnSize() is called when the size changes for any reason. This is a special label which has
  a balloon holding the text and an optional icon property which specify one of a few
  standard icons. You may choose to make it invisible by set Visible property to False at
  design time, then set Visible := True to make it appear. Setting the Animations property you
  can make it pop up nicely.
  Yet another label extension. This one displays an alert at the top of the window.
  AllowClose determines whether an X close button appears to close the error message or
  not. Orientation determines whether a left sided or right sided X is used to close the error
  message. It is common to create the TAlertLabel at design time but only make its Visible
  property true when necessary, such as when the network request fails or a password is
  incorrect.
  mouse for helping the user with a balloon text or some other notice.
  • Icon can specify an icon
  The TIconButton specifies a button with an icon (glyph) and no text or border.
  • Like most controls, you can specify a different cursor for when the mouse pointer is over
  the control
  • Sometimes you may want to fire events as long as a button is pressed, like in a video
  game. Set the RepeatClick to True and
  • If you set ModalCancel to True, this button will be called when the user presses Esc.
  • If you set ModalEnter to True, this button will be called when the user pressed
  Enter/Return.
  • You must set ModalResult to the value which will be returned from the modal dialog box.
  Use this!
  • InputType can be set to various values. It does not restrict the input but
  on many devices it determines what type of virtual keyboard is
  displayed.
  o tiNumber
  o tiEmail
  o tiNone
  o tiURL
  • It is possible to modify keystrokes entered by intercepting the
  OnKeyPress or OnKeyDown. For example, you could make a sound if a
  user entered a letter in a number field.
  • It is common to hook the OnKeyUp() event handler to process
  keystrokes after the Edit has placed them into the Value buffer.
  This control is used just like TEdit, but it displays dots instead of characters.
  MultiLineEdit is a self-explanatory name.
  • The text entry is stored as a TStrings property called Lines. You can specify Lines[0],
  Lines[1], etc. up to Lines.Count -1
  • You can also read or set the whole string with Lines.Text
  • MaxLength is the number of characters allowed
  • ReadOnly is useful for transforming this to a text output box
  • ScrollBars can be defined as sbHorizontal, sbVertical, sbNone or sbBoth. Scroll bars are
  only displayed if necessary.
  • The default View is cvMonth, you can also set it to cvCentury, cvDecade, and cvYear
  • Read or write the date by editing the Text field
  • Dates are stored in US American format: month/day/year, you may have to convert to your
  locality’s format
  • See also:TDateEditComboBox
  • Text contains the current value, which is either empty string or one of Items
  • Often handle OnCLick() or OnChange() events
  TListBox is a box containing a list of strings.
  The TDateEditComboBox is an Edit box which features a drop down calendar if the user
  clicks on it.
  • The date is stored in American format month/date/year
  • Read or write the Text property
  • Your program or the user can specify a time following the date and it will be viewable in
  the Text property, but the built-in calendar only specifies a new date
  • The application can read or write SelectedDate which is the DateTime selected by the
  user but returns DateTime(0) if the date is invalid OR the user specified a time on that date.
  SelectedDate is in the local time zone
  This is an Edit/ComboBox which is useful for situations where a user needs to be able to
  enter in a value or select it from a separate dialog, such as a lookup dialog that has a data-
  bound grid in it.
  RowSelect := True)
  • Selected items are in a Selected array
  • TGridCells are arranged in TGridColumns and TGridRows
  • We will show several examples later
  The graphics controls are… well... graphical.
  Containers hold other visual controls. Sometimes they have visual boarders, but not
  always.
  A THeaderPanel is the header that goes at the top of a form or a panel. Typically you
  would place a TLabel into the THeader which would say the name of the virtual window.
  It is automatically included in a TPanel.
  TSizer is used to allow the user to adjust the size of controls. See the chapter on layouts.
  A TSizeGrip modifies controls so a user can resize them, simply drop the TSizeGrip onto a
  control and you can drag the lower right hand corner larger or smaller, up to constraints in
  the control’s constraints, or the size of the bounding control.
  There is only one menu class, TMenu.
  • Use OnClick event which is fired when someone presses a menu option
  • Index is the currently selected item.
  • Use the + symbol to add menu options.
  • Set Visible to show or hide the menu
  The TDataSetToolBar shows a perfect example of a TToolBar in use, it has buttons for
  common actions like adding, deleting, modifying records and more. The TLink control has
  a clickable caption which leads a browser to a different page.
  The TScript component allows you to include a JavaScript file in your application
  dynamically. You must still specify an external interface from the EWB compiler. We use
  this extensively in our JavaScript chapter.
  Implement a Google map into your application. Specify Locations on the map. Set Options
  such as MapType for roads or other options. In our Cordova/PhoneGap example we
  desmonstrate how to use the TMap.
  You can design your web form using the WYSIWYG (what you see is what you get) visual
  form designer.
  EWB supports dynamic layout and sizing of controls known in the industry as Responsive
  Web Design. It seems a little bit intimidating at first, but it is powerful and relatively
  simple once you get started. After only a few projects, you will get the hang of the layouts
  and many of us use it in every new project.
  • LayoutOrder – the order in which objects are added among layout groups.
  • Layout parameters:
  o Consumption
  o Overflow
  o Position
  o Reset (Boolean)
  o Stretch
  • Margins (left, right, top, bottom)
  • Padding (left, right, top, bottom)
  Objects are laid out in order specified by LayoutOrder. First 0, then 1, etc. and they are
  placed into the remaining rectangle of space in the Form or container.
  Position tells from where to start drawing the object. Often you will start at the TopLeft and
  proceed either to the right or down. Sometimes buttons start at the bottom right and grow
  leftward or up.
  Consumption specifies if the direction the object grows (left, right, etc.) and eats into the
  remaining rectangle.
  Overflow says what to do when you run out of space in the current direction, like go Right,
  go Down, etc.
  Reset says to reset to the beginning since the last Reset (or the start).
  Stretch tells whether to optionally grow in a direction, or not at all. If an object stretches,
  its minimum and maximum constraints are observed. If it doesn’t stretch, they are ignored
  because it stays the designed size.
  Margin says how close an object should be to other objects, and padding is the space
  inside the object reserved for spacing.
  An example is needed to see how these factors all play together. This example is found on
  the EWB web site under Responsive Design.
  Thus LayoutOrder 1 is below it. And it grows to the right, but has a RESET=True, so the
  rectangle goes to the last reset position which is at the top of the remaining rectangle.
  LayoutOrder 2 is a tricky one: it stretches to the right (consumption), but grows toward the
  bottom, so the remaining rectangle is below it.
  LayoutOrder 3 naturally falls below LayoutOrder 3 because we grew to the bottom. Now
  we grow to the right.
  Where LayoutOrder 4 is placed depends on the remaining space. If there is room, we
  continue growing to the right. But if you resize the rectangle smaller, #4 has to go below
  #3, because #3 specified overflow would go below.
  It is useful to stretch and squeeze the browser window. Also, many browsers support a
  responsive design mode which simulates the size of common devices like cell phones,
  tablets, etc.
  Using responsive design, your pages can be attractive and functional on all devices. But
  you will have to test and apply the rules as we have done here to make sure it grows and
  shrinks the way you want.
  When doing responsive design, you often want to have the MultiLineEdit box grow as
  needed. This can easily be accomplished in code by setting the OnKeyUp handler as
  follows;
  c : integer;
  begin
  c := MultiLineEdit1.Lines.Count;
  MultiLineEdit1.Height :=
  (c+1) * (3*MultiLineEdit1.Font.Size) div 2; end;
  Don’t let the math scare you, it’s just c (the number of lines of text) incremented by one so
  there is always a bit of extra room, multiplied by a bit more than the font height.
  Sometimes you want the form or panel to be resizable on the desktop.
  Start by setting your form’s layout to TopLeft placement and stretch BottomRight. Then
  place a TScrollPanel on your form , set its layout to TopLeft placement with strech
  BottomRight, and finally set the Scroll property to ssBoth.
  If you only want part of the form to scroll, use a TBasicPanel to delimit the area that will
  not scroll, using Layout parameters to occupy that space. Then use the above steps with
  TScrollPanel on the remaining space to create a scrollable area.
  You can impose Contstraints that limit the minimum and maximum size of your scollable
  area.
  EWB supports {$DEFINE xxx} and {$IFDEF xxx}/{$ENDIF} much like Delphi.
  You can use this to mark of a section of code that you want to temporarily disable. Often
  you will have a problem with a function, so {$ifdef DEBUG} it out, and {$ifdef DEBUG}
  out the definition in the TYPE section too.
  Another great use is to comment out commens with embedded { and } characters, like
  JSON or sample C/PHP/JavaScript code. You cannot normally comment out these things
  because every end brace } frustratingly turns off comments.
  I use {$ifdef xxx} between different versions of my code. Modern browsers allow you to
  store some data locally in the local and session storage. The space is not enormous, but it
  is big enough to store useful strings.
  Local storage is conveniently accessed through the LocalStorage TPersistent class with
  functions like Set, Items (which gets data), and Clear which all operate on Key names.
  Local storage persists for a long time, possibly years.
  Session storage is access through the SessionStorageƒ TPersistent class with the same
  functions as LocalStorage. Session storage generally is deleted when you exit or restart
  your browser (not just closing the window or tab).
  Be aware that these data, although not visible to other Web applications, are not considered
  secure. The user or local applications can read the data, so do not store anything sensitive
  like Social Security Numbers, passwords, etc.
  Session storage is particularly useful for Web site that have pages which load and change
  frequently but EWB usually does not usually involve a lot of different web pages.
  However, you may wish to store which windows are open, so if the user hits reload then
  you can do something intelligent to recover.
  Here is the source code:
  unit storage1;
  interface
  uses WebCore, WebComps, WebUI, WebForms, WebCtrls, WebEdits,
  WebLabels, WebBtns;
  type
  TForm1 = class(TForm)
  edSession: TEdit;
  edLocal: TEdit;
  Label1: TLabel;
  Label2: TLabel;
  btSave: TButton;
  btRetrieve: TButton;
  Label3: TLabel;
  Label4: TLabel;
  btClear: TButton;
  procedure btSaveClick(Sender: TObject);
  procedure btRetrieveClick(Sender: TObject);
  procedure btClearClick(Sender: TObject);
  private
  { Private declarations } public
  { Public declarations } end;
  var
  Form1: TForm1;
  implementation
  end.
  As we alluded to earlier, you can compile to JavaScript and debug that. And we will
  discuss techniques built into EWB and also some not yet included in EWB, such as adding
  breakpoints, using JavaScript variable watches, and more advanced DEWBUnit Unit
  Testing is introduced.
  The first step is to ensure you have not enabled compression/encryption on your project.
  This way the generated HTML/JavaScript is human readable.
  When trying to figure out raised exceptions, a method I found helpful for debugging
  exceptions is to place a try / except block around code that has problems. Then declare a
  local variable var ProgressNum : integer. In various places around your function, assign
  ProgressNum to various different values (0,1,2,3…). And in your exception handler have
  Except on Exception: E do
  ShowMessage(‘ERROR: ‘+E.message +
  IntToStr( ProgressNum ));
  End;
  This code fragment will pinpoint the last good spot in your program before the exception.
  Note that EWB exceptions are based on JavaScript exceptions, which differ from Delphi
  Pascal exceptions. For example any number div 0 in JavaScript does not generate a divide
  by zero error, instead the returned result is infinity. If you depend on a divide by zero
  exception, you will have to detect a zero and raise the exception yourself.
  Another trick is to use ShowMessage() to show variable contents and how far you have
  progressed. This has a problem under EWB in that the message boxes are all displayed
  concurrently, so you will have a bunch of message boxes present.
  Native JavaScript is typically riddled with bugs due to the fact the language is interpreted
  rather than compiled and not strongly typed. For these reasons, almost every web browser
  supports debugging features for JavaScript programmers. We’ll learn how to use them.
  First, you must download my debugcode.js JavaScript file and add it to your project
  (Project | Options | External Files | … ) Then add the following few lines to your interface
  section.
  Start by adding a breakpoint to any function where you are having problems. Just add the
  line:
  eval(‘debugger;’);
  On most browsers, F12 enables the debug screen. If it doesn’t on yours, either find it on the
  menu or switch to an easier-to-use debugger like Chrome or Firefox. F12 and debug
  output/breakpoints do not work on the built-in browser of the EWB IDE.
  Click on the “console” button on your browser’s developer pane, it should show no error
  messages except the messages you outputted with debugoutput(). If you see errors here
  there is something that should be fixed. You can output text to the console window with
  console.log(‘stuf’), and this is a handy way to debug – output everything that happens until
  something stops.
  Step over the debugger statement and return to the calling function, which is typically
  what you will want to debug. You can usually see the contents of any variables and classes
  by clicking on their names inside the source code, and many browsers let you set a Watch
  variable, just like Delphi’s debugger.
  Many EWB programs have been written without the use of JavaScript debugging, but once
  you see these tricks, you can speed up development by improving your efficiency
  debugging your code.
  Another way to set breakpoints is to edit the JavaScript output, search for some word in
  your source code (constants, variable and class names are good candidates), and insert the
  command debugger; where the trouble is, then run the application.
  Unit Testing is the systematic creation of tests to validate software, it’s an important step in
  making professional quality software.
  The idea is simple, put your logic into subroutines or non-GUI class methods, then create a
  sequence of tests and run them against your code and test the actual outputs against
  expected outputs.
  For example, look at the following two subroutines using DEWBUnit,
  QEWBUnit’s assert.equal() method checks that the first two parameters are equal. If they
  are, all is well, otherwise it logs the error that one has some other value.
  Button1.Caption := 'ha';
  assert.equal( one, 1 , 'one = 1');
  assert.equal( animal,'dog', 'animal = dog');
  assert.okay('happiness found');
  assert.fail('homework');
  raise exception.Create('divide by zero');
  end;
  QEWBUnit is told the time limit for this routine and all its results is 4ms (assert.timelimit)
  and that the expected number of assertions is 3 (assert.expect).
  Assert.equal passes for one = 1, but fails for animal = dog. Assert.ok logs ‘happiness
  found’, and also logs the failure ‘homework’.
  Finally, QEWBUnit logs the exception created and not handled by your code. All you need
  to add this is copy QEWBUnit.* to your project and add the few lines:
  end;
  The code creates an instance of the Tester, then queues tests on a procedure, then on the
  TestMethod method, and again on the initial procedure.
  The Start function runs the tests in the queue. In the results below, I have checked the
  “Show only failures” checkbox, and the results show only test2 failed, and which failures it
  had.
  Among the results are the number of milliseconds of each stage. This value is not
  absolutely correct as the QEWBUnit code does consume some time doing its chores. In
  general, you will find pure JavaScript typically take 50ms or less, whereas GUI operations
  are often over 100ms to complete. Network operations can take 10ms to seconds or even
  minutes.
  Note the Assert parameter is different for each function called. And your function may
  return before the whole operation is completed due to the asynchronous model – such as if
  you have networking or GUI calls which happen asynchronously.
  The results are green for success, red for failure, and orange for an incorrect number of
  results when you set a count with Assert.expect().
  In a production application you would define important functions and typical results, then
  write the function to implement the results.
  Eg.
  procedure TForm1.TestMethod( assert : TEWBU_test); var
  t : DateTime;
  yesterday : DateTime;
  lastweek : DateTime;
  lastyear : DateTime;
  begin assert.timelimit(100); // no way should it take 100 ms
  t := now;
  assert.equal( fn(t), ‘right now’ , 'test for right now');
  yesterday := DateTime( Integer( t ) – 1000*24*60*60 );
  assert.equal( fn(yesterday),’yesterday’, 'test yesterday');
  lastweek := DateTime( Integer(t ) – 1000*8*24*60*60 ));
  assert.equal( fn(lastweek),’last week’, ‘test last week’);
  lastyear := DateTime( Integer(t ) – 1000*370*24*60*60 ));
  assert.equal( fn(lastyear),’last year’, ‘test last year’);
  end;
  Now that you have write the function fn(x:DateTime). Typically you would leave the tests
  available to test every component before every new product release; this will ensure small
  changes do not break working code.
  There are DUnit testers for a number of platforms. I looked at using a pure JavaScript
  version, but instead got frustrated and decided to write DEWBUnit in pure EWB code to
  integrate better this environment.
  There are many reasons you might want to use Painting on the form, some include:
  - Bar/pie/line graphs
  - Schematics
  - Simple maps
  - Modifications to images (which we do in the FileSave example)
  When you place a TPaint on your form, you create a surface called a canvas on which you
  can draw using:
  For example, to draw a box, set the canvas FillColor to a color of your choosing and call
  FillRect( x, y, width, height), and it and all other things will be drawn in that color until
  you specify a new color.
  Call FillText( caption, x, y) to place text on the canvas using the current color.
  Several line oriented functions follow a path which you can later fill or leave unfilled.
  For example, when we are going to draw a pie segment, we start a path at the center, move
  to and create an arc,, then ClosePath back to the centre, and finally we set a color and tell it
  to fill.
  // create an arc
  Arc(CHART_COORD_X,CHART_COORD_Y
  ,CHART_RADIUS,StartAngle,EndAngle);
  // finish the pie wedge ClosePath;
  The following example shows how to create pie and bar graphs from the same data.
  Place a TPaint surface on your form, make it quite large or the following code will clip
  meaning it goes beyond the size of the TPaint and is therefore not displayed.
  Add two TButtons, Button1 and Button2 in the upper left hand corner, these will each draw
  a graph.
  unit pie;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebPaint, WebBtns;
  type
  TForm1 = class(TForm)
  Paint1: TPaint;
  Button1: TButton;
  Button2: TButton;
  procedure Button1Click(Sender: TObject); procedure
  Button2Click(Sender: TObject);
  private
  { Private declarations }
  procedure ClearChart;
  public
  { Public declarations }
  procedure DrawPie;
  procedure DrawBars;
  end;
  var
  Form1: TForm1;
  implementation
  const
  CHART_COORD_X = 200; CHART_COORD_Y = 200;
  CHART_LABEL_X = 700;
  CHART_LABEL_Y = 100;
  CHART_LABEL_HEIGHT = 30;
  end;
  procedure TForm1.DrawPie;
  var
  I: Integer;;
  Total: Integer=0;
  Angles: array of Double;
  StartAngle: Double;
  EndAngle: Double;
  Begin
  ClearChart;
  // Total will be the sum total of all numbers in pie for
  I:=0 to Length(Data)-1 do
  Inc(Total,Data[I]);
  // create a list of angles SetLength(Angles,Length(Data));
  for I:=0 to Length(Data)-1 do
  Angles[I]:=((Data[I]/Total)*PI*2);
  StartAngle:=(-PI/2);
  with Paint1.Canvas do
  begin
  StrokeStyle:=dsColor;
  Font.Name:='Segoe UI';
  Font.Size:=14;
  Font.Color:=clElevateLightBlack;
  TextBaseLine:=blTop;
  StrokeColor:=clTransparent;
  LineWidth:=1;
  // cycle through the numbers drawing the pie for I:=0 to
  Length(Data)-1 do
  begin
  EndAngle:=(StartAngle+Angles[I]);
  with Paint1.Canvas do
  begin
  BeginPath; // start afresh
  // move to center
  MoveTo(CHART_COORD_X,CHART_COORD_Y);
  // create an arc
  Arc(CHART_COORD_X,CHART_COORD_Y
  ,CHART_RADIUS,StartAngle,EndAngle);
  // finish the pie wedge ClosePath;
  (LabelY+(CHART_LABEL_HEIGHT*I))+2); end;
  StartAngle:=EndAngle;
  end;
  Paint1.Canvas.BeginPath; // reset subpath for canvas end;
  procedure TForm1.DrawBars;
  var
  I : Integer;
  x, y: double;;
  MaxHeight: Integer=0;
  begin
  ClearChart;
  // get the height for scaling
  for I:=0 to Length(Data)-1 do
  MaxHeight := max( MaxHeight, Data[I] );
  with Paint1.Canvas do
  begin
  StrokeStyle:=dsColor;
  Font.Name:='Segoe UI';
  Font.Size:=14;
  Font.Color:=clElevateLightBlack;
  TextBaseLine:=blTop;
  StrokeColor:=clTransparent;
  LineWidth:=1;
  end;
  (LabelY+(CHART_LABEL_HEIGHT*I))+2);
  end;
  end;
  DrawPie;
  end;
  procedure TForm1.Button2Click(Sender: TObject); begin
  DrawBars; end;
  end.
  Unit: WebUI
  Alpha
  CompositeOperation
  FillColor
  FillGradient
  Global Alpha (Transparancy) of canvas, default 1.0
  How are source pixels combined with destination pixels during drawing operation, default
  coSourceOver
  FillPattern
  FillStyle
  LineCapStyle
  LineJoinStyle
  LineWidth MiterLimit
  ShadowBlur
  ShadowColor ShadowOffsetX ShadowOffsetY StrokeColor
  StrokeGradient StrokePattern StrokeStyle
  TextAlign
  TextBaseLine
  Pattern to use when FillStyle set to dsPattern One of: dsColor, dsGradient, dsPattern
  How are lines terminated when drawn, default csButt, other options are csRound and
  csSquare How are lines joined when they intersect, default jsMitre, others jsLevel,
  jsRound
  Line width for drawing (stroking) on the canvas Upper limit when LineJoineStyle is set to
  jsMitre, default 10
  How much blur, default is 0, which is crisp What color is the shadow if ShadowBlur is not
  zero Horizontal offset of shadow, default 0
  Veritcal offset of shadow, default 0
  Line color when StrokeStyle is set to dsColor Line gradient when StrokeStyle set to
  dsGradient Line pattern when StrokeStyle set to dsPattern
  BeginPath
  Add an arc along the current subpath.
  Add a straight line and an arc to the current subpath Discard any existing subpath and begin
  new subpath with no defined starting point.
  BezierCurveTo Add a cubic Bezier curve to the path.
  ClearRect Draw a transparent clBlack rectangle, does not affect current path Clip
  ClosePath
  Compute the intersection of the inside of the current path with the current clipping region
  and use the smaller region as the new clipping region.
  ConvertToDataURL
  Close the path by adding a line back to the first point, then start a new
  Path
  DrawImage Fill
  Draw an image onto the canvas
  fill the current path of the canvas with the color, gradient, or pattern specified by the
  FillStyle, FillColor, FillGradient, and FillPattern
  FillRect
  FillText
  IsPointInPath
  LineTo
  MeasureText
  MoveTo
  QuadraticCurveTo
  Rect
  Rotate
  Save
  Fill the specified rectangle with the color, gradient, or pattern specified by the FillStyle,
  FillColor,
  FillGradient, and FillPattern properties.
  Draw the specified text at the specified point with the font specified
  by the Font property, and the color, gradient, or pattern specified by
  the FillStyle, FillColor, FillGradient, and FillPattern properties.
  Does the point fall within or on the edge of the current path?
  Add a line segment to the current path starting at the current point.
  Measure the length of the specified text if drawn with the current font settings
  Move the current point to the specified location and begin a new
  Subpath
  Add a quadratic Bezier curve to the current path, and the new position will be the ending
  point.
  Add a rectangle to the current path of the canvas. The added rectangle has its own subpath
  not connected to any other subpaths in the current path. After this
  method is called, the current point on the canvas is set to the point specified by the first two
  parameters
  Scale
  SetTransform
  Stroke
  StrokeRect
  StrokeText
  Transform Translate
  Change the transformation matrix to scale the future X and Y drawing by these factors.
  Directly set the
  transformation matrix.
  Stroke (draw) the current path of the canvas with the color, gradient, or pattern specified
  by the StrokeStyle, StrokeColor, StrokeGradient, or StrokePattern properties. The
  LineCapStyle, LineJoinStyle, MiterLimit and LineWidth properties control how lines
  of the current path are drawn.
  Stroke (draw) the specified rectangle with the color, gradient, or pattern specified by the
  StrokeStyle, StrokeColor, StrokeGradient, or StrokePattern properties. The LineCapStyle,
  LineJoinStyle, MiterLimit and LineWidth
  properties control how the lines of the rectangle are drawn.
  Draw the outline of the specified text at the specified point with the font specified by the
  Font property, and the color, gradient, or
  pattern specified by the StrokeStyle,
  StrokeColor, StrokeGradient, or StrokePattern properties. The LineCapStyle,
  LineJoinStyle, MiterLimit and LineWidth properties control how the lines that make up
  the outline of the font characters are drawn. See online notes about condensed text if the
  specified text does not fit within the specified width.
  Move the following commands to the horizontal and vertical offsets specified, ie. slide the
  image in a given direction.
  I recommend ‘The JavaScript Bible’ which has details on using these thinly disguised
  JavaScript functions.
  Sometimes you must know a little bit about JavaScript or HTML5 to do what you want.
  Such is the case with resizing images or manipulating them.
  Here we have a little program with a ButtonComboBox whose five items are set to 100
  percent, 50 percent, 33 percent, 25 percent and 200 percent. Its onChange property is set to
  ButtonComboBox1Change;
  We add a TImage Image1 used to load an image. We set its URL property to any picture of
  our choosing. Its OnLoad property is set to Image1Load which resizes the image to its fully
  loaded size and makes it invisitble.
  TForm1 = class(TForm)
  ButtonComboBox1: TButtonComboBox;
  Image1: TImage;
  Paint1: TPaint;
  procedure ButtonComboBox1Change(Sender: TObject); procedure
  Image1Load(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  external function eval( s: string) : object; implementation
  context : THTMLCanvasRenderingContext2D;
  paint, img : THTMLElement;
  begin
  paint := THTMLElement(
  window.document.getElementById('paint'));
  context := THTMLCanvasElement( Paint ).getContext('2d');
  EWB does not use HTML IDs, so we set the clientID that in turn sets the HTML ID to
  something recognizable, in this case ‘image’ and ‘paint’.
  The variable Paint is set to the HTML element JavaScript finds with the ID paint.
  The variable is set to the HTML element JavaScript with the ID image, but EWB uses the
  container of the Paint1 object which is a DIV, so we have to get its one and only child,
  which is the true paint.
  From there, it’s a simple matter of getting a HTML5 2d drawing context, and then drawing
  the image on using whatever size we want.
  Providing attractive displays is not enough, we often need the ability to transfer files
  between the web client and server, and the other direction too.
  The ability to upload files is one of the important functions of web pages.
  The power of EWB can lead you to forget that it is limited by the JavaScript restrictions,
  one of which is that file access is severally crippled to prevent web sites from stealing
  files from your hard drive.
  It is possible to upload files to a web server using techniques similar to other web page
  editors.
  First, drop a Containers | THTMLForm onto your form. This will be the HTML form that is
  uploaded to the web server. Only controls inside this form are uploaded.
  Place a TFileComboBox into the THTMLForm, and also a Edit and a TButtton. If these are
  not inside the THTMLForm the whole thing will fail.
  Place a Web | TBrowser elsewhere on the form. It will hold the output from the web server.
  Set HTMLForm1’s Output to Browser1 which you just placed on the form.
  Now when you run your web page, you can select a file to upload, enter a text string in
  Edit1, and press Button1 to upload the file. The WebBrowser1 will display the output from
  the web page.
  By default, HTMLForm1 will POST the data as a MultiPartForm, which is appropriate for
  binary data. You can change this in the Encoding parameter to feTextPlain or
  feURLEncoded, and in Method to any valid HTTP method.
  To download a data file you act as though you are going to replace the current web page
  with a new one. This causes the browser to do an HTTP/HTTPS GET of the specified
  URL.
  uses webdom; …
  url := ‘report.php’;
  s := url + ‘?report=transaction.csv’
  window.location.replace( s );
  Then the HTTP/HTTPS server script indicates through MIME (Multimedia Internet Mail
  Extensions) that the file is not HTML but rather some other format, and that its filename is
  whatever, and that the file should be downloaded and not displayed. If you do not indicate
  that the file should be saved with a filename, it will instead open up in the appropriate
  application (eg. PDF viewer, Excel, Word, etc.).
  report.php :
  header('Status: 200');
  header('Content-type: text/csv');
  $u = "answers.csv";
  header("Content-disposition: attachment; filename=$u;");
  If you wish, you can download the file in a Web | TBrowser, which will load the new file
  into an HTML IFRAME simply by setting the TBrowser’s URL to the appropriate web
  address. This has the benefit that you can use POST to download the file, and POST
  arguments are hidden from web server logs unlike GET arguments.
  EWB uses a totally event driven model where nothing ‘blocks’.
  There is no sleep() function, no waiting for network events like a return to our
  HTTP/HTTPS request, no waiting for user input. Instead we use a TTimer to schedule a
  delay, a network request invokes HTTP/HTTPS request handler when the request fails or
  success, keystrokes and other input generate event methods for affected components.
  This is a change from Delphi, where ShowMessage() or MessageBox() would block until
  the user accepted the results… we cannot block, we can only complete event handlers.
  (The exceptions to this non-blocking are described under window.alert() and similar
  functions of the JavaScript chapter.)
  There is also no concept of a TThread or multithreading in normal EWB (though we
  present a multithreading solution in a later chapter). But there are workarounds; we can
  schedule several short programming segments to occur in sequence. This is accomplished
  with the async keyword.
  begin
  for i := 1 to 10000 do begin
  Edit1.Text := IntToStr( i );
  for j := 1 to 1000 do
  k := j;
  end;
  end;
  It is a for loop that would update Edit1’s Text to the numbers 0 through 10,000. And since
  there is an internal for j := loop, it would delay between each update. The for j loop is not
  intended to provide a specific delay, it’s just an example of something keeping the cpu
  busy.
  Try it. It doesn’t work the way you thought. The only things that happen are that there is a
  five second delay while it calculates, and then the number 10000 is displayed.
  EWB executes all code, then schedules an update to the display when all changes are
  made.
  In this example, if you want to show intermediate results, the trick is to use async to
  schedule future code to execute. Async saves the state of all parameters necessary to
  complete the call sometime in the future.
  begin
  async UpdateOneEdit1( 0 );
  end;
  for j := 1 to 1000 do
  k := j ;
  if ( v < 1000 ) then async UpdateOneEdit1( v + 1 )
  else HideProgress;
  end;
  In normal operations like generating a web request, you will call ShowProgress() and then
  the request function without using async. The request will start the HTTP/HTTPS
  connection then return to the event handler.
  When the HTTP/HTTPS result is returned, your request handler is called, so you process
  the data and then call HideProgress.
  Tag is a property on every component that has no declared use, it’s usable by you for any
  purpose you want.
  For example, when you write a calendar app, you can use Tag to hold the datetime or an
  event number of the calendar event you are displaying in a TLabel. Then when the user
  clicks on the TLabel, you know exactly when it will happen.
  Another popular use is to set a TEdit’s Tag := 0 in the OnShow event, and set it to 1 in an
  OnChange event. Then you would know if the user changed any details, and which details
  since the edit was available.
  You can set the Tag to an ordinal in an array of objects or a TObjs or TStringList, so the
  Tag will give an index to which object or string it references.
  You are limited only by your imagination and the 52 bits of the signed Integer type.
  Every environment seems to have a different format for storing datetimes. In EWB we use
  the 52 bit integer to hold the number of milliseconds since the Epoch of January 1, 1970
  UTC (universal time coordinates).
  Very likely UTC is not your current timezone, so you often want to present local time to the
  user, and read local time from them, but often servers store UTC time if they are expected
  to serve a world-wide market.
  There are many functions to convert between DateTime and other formats, usually integers
  or strings:
  YearOf( x : DateTime , optionalUTC :boolean ) returns the year as an integer. If you do not
  specify the optionalUTC parameter, it defaults to false, meaning local time.
  h The hour number (12-hour clock) with no leading zero hh The hour number (12-hour
  clock) with a leading zero if the hour number is less than 10
  H The hour number (24-hour clock) with no leading zero
  HH The hour number (24-hour clock) with a leading zero if the hour number is less than 10
  m The minute number with no leading zero
  mm The minute number with a leading zero if the
  minute number is less than 10
  s The second number with no leading zero
  ss The second number with a leading zero if
  the second number is less than 10
  tt The AM/PM designation for a 12-hour clock literal
  DateTimeToISOStr() returns a standard ISO string which is computer parseable and yet
  human readable. It is based on UTC time.
  The ability to do animations can give your application a nice look. You can animate any
  control, including containers as well as individual TButtons, etc.
  The animations will occur whenever there is a change to the size or visibility of a control.
  You do not have to schedule a TTimer to do the animation, animations are built-in.
  The following minimalist program shows how to animate a TButton and TListBox. Every
  time you press the TButton, the TButon and TListBox will grow 50% by slowly expanding.
  unit main;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebLabels,
  WebLists, WebBtns;
  type
  TForm1 = class(TForm)
  ListBox1: TListBox;
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  implementation
  procedure EaseIn( Ctrl : TControl ); var
  h : integer;
  begin
  ctrl.BeginUpdate;
  h := Ctrl.Height;
  with Ctrl.Animations.Height do begin
  Duration := 1000;
  Style := asQuadEaseIn;
  end;
  Ctrl.Height := h +(h div 2);
  ctrl.EndUpdate;
  end;
  Nomally you would click on the Object Inspector and set the Animations as constants
  rather than entering them in code.
  asBackEaseOutIn Easing equation function for a back easing in: accelerating from zero
  velocity.
  Easing equation function for a back easing in/out: acceleration until halfway, then
  deceleration. Easing equation function for a back easing out: decelerating from zero
  velocity.
  Easing equation function for a back easing out/in: deceleration until halfway, then
  acceleration.
  Easing equation function for a quadratic easing in: accelerating from zero velocity.
  Easing equation function for a quadratic easing in/out: acceleration until halfway, then
  deceleration.
  Easing equation function for a quadratic easing out: decelerating from zero velocity.
  Easing equation function for a quadratic easing out/in: deceleration until halfway, then
  acceleration.
  Easing equation function for a quartic easing in: accelerating from zero velocity.
  Easing equation function for a quartic easing in/out: acceleration until halfway, then
  deceleration.
  asQuartEaseOut
  asQuartEaseOutIn
  asQuintEaseIn
  asQuintEaseInOut
  asQuintEaseOut
  asQuintEaseOutIn
  asSineEaseIn
  asSineEaseInOut
  asSineEaseOut
  asSineEaseOutIn Easing equation function for a quartic easing out: decelerating from zero
  velocity.
  Easing equation function for a quartic easing out/in: deceleration until halfway, then
  acceleration.
  Easing equation function for a quintic easing in: accelerating from zero velocity.
  Easing equation function for a quintic easing in/out: acceleration until halfway, then
  deceleration.
  Easing equation function for a quintic easing out: decelerating from zero velocity.
  Easing equation function for a quintic easing in/out: acceleration until halfway, then
  deceleration.
  Easing equation function for a sinusoidal easing in: accelerating from zero velocity.
  Easing equation function for a sinusoidal easing in/out: acceleration until halfway, then
  deceleration.
  Easing equation function for a sinusoidal easing out: decelerating from zero velocity.
  Easing equation function for a sinusoidal easing in/out: deceleration until halfway, then
  acceleration.
  There are a lot of choices. Most developers follow some theme rather than a random attack
  of the GUI on the poor user. Use them tastefully. As we will see later, TGrid is very useful
  in database applications. But sometimes you will use TGrid on its own, just as a
  convenient way to display and maybe update data.
  One noteworthy application is in generating an online receipt for a transaction. The grid
  looks good, and it can have a variable number of rows and columns.
  For our TGrid example, place a TButton on the form and a TGrid. The rest we can do in
  code.
  procedure TForm1.Button1Click(Sender: TObject); begin
  end;
  Columns[1].ControlType := ctEdit; Rows.Row[0].Value[0] :=
  'Name'; Rows.Row[0].Value[1] := 'Erick';
  Rows.Row[1].Value[0] := 'Org'; Rows.Row[1].Value[1] :=
  'Engineering';
  end; end;
  We first check the column count, otherwise we’d keep appending columns every time you
  press the button.
  We set column[1] as editable so a user can change its values. Not so for column[0], it is
  readonly.
  A popular question that appears on the message board asks how to make color versions of
  TButtons or TGrids.
  The long answer is that you can create class decendant controls. That is truly the best
  possible result, as these controls can then be added to the component palette and employed
  in all your subsequent projects.
  The source code to the component library is included with your EWB license, so you can
  refer to many example components there.
  But doing that takes a lot of coding and clicking and perfecting. Suppose you want a quick-
  and-dirty solution which solves your particular problem without all the effort.
  The first thing to do is pick the parent control on which you wish to base your new control.
  Consider TButton, we’ll add a color to it so there is a new property called color of type
  TColor.
  unit tcolorbutton1;
  interface
  uses Webdom, WebCore, WebUI, WebForms, WebCtrls, WebBtns,
  WebLabels;
  type
  TForm1 = class(TForm)
  Button1: TButton;
  Label1: TLabel;
  procedure Form1Show(Sender: TObject); procedure
  Button1Click(Sender: TObject);
  private
  { Private declarations }
  butRed, butGreen, butBlue : TColorButton;
  function MakeColorButton( caption : string;
  color : TColor ; myleft : integer ):TColorButton; public
  { Public declarations }
  end;
  TColorButton = class(TButton)
  protected
  fFillColor : TColor;
  procedure InitializeProperties; override; procedure
  UpdateInterfaceState; override; function getFillColor :
  TColor;
  procedure setFillColor(const col : TColor );
  published
  property FillColor : TColor read getFillColor write
  setFillColor;
  end;
  var
  Form1: TForm1;
  implementation
  procedure TColorButton.InitializeProperties;
  begin
  inherited InitializeProperties;
  fFillColor := clRed; // default is some vibrant color end;
  end;
  // user application code
  end;
  procedure TForm1.Form1Show(Sender: TObject);
  begin
  butRed := MakeColorButton( 'red', clRed, Button1.Width + 10
  +
  Button1.Left );
  butGreen := MakeColorButton( 'green', clGreen,
  2*(Button1.Width + 10 ) + Button1.Left );
  butBlue := MakeColorButton( 'blue', clBlue, 3*(Button1.Width
  +
  10) + Button1.Left );
  end;
  Looking at TForm, we declare three buttons (butRed, butGreen and butBlue) and a
  MakeColorButton() function which creates the buttons parallel to a normal TButton we
  dropped on the form.
  private
  { Private declarations }
  butRed, butGreen, butBlue : TColorButton; function
  MakeColorButton( caption : string;
  MakeColorButton just makes a regular button, but adds a FillColor which is new.
  So now we just need a class that does everything TButton does, but adds a color
  background. We declare it as a descendant of TButton class, and we add an fFillColor
  value and two helper function getFillColor and setFillColor which get and set the
  published property FillColor.
  published
  property FillColor : TColor read getFillColor write
  setFillColor;
  end;
  We also define two protected override functions. The system calls these overridden
  functions instead of the default functions of TButton of the same name.
  procedure TColorButton.InitializeProperties;
  begin
  inherited InitializeProperties;
  fFillColor := clRed; // default is some vibrant color end;
  It calls the usual UpdateInterface of the TButton, but then reasserts the Background Fill
  Color as whatever we’ve defined.
  That’s it. Of course, you have to know that UpdateInterfaceState is called to get the
  component to update itself. But now you know.
  Creating color, bold, italics, underline and strikeout options on grids is quite easy.
  The result looks like this
  The trick is simply to create an OnCellUpdate event handler which adjusts the font
  characteristics.
  First, add a TGrid to your form, then use the OnShow event to add data to your Grid.
  unit colorgrid1;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebGrids;
  type
  TForm1 = class(TForm)
  Grid1: TGrid;
  procedure Form1Show(Sender: TObject);
  private
  { Private declarations }
  procedure OnCellUpdate( Col : TGridColumn ;
  ACell: TGridCell );
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  implementation
  procedure TForm1.OnCellUpdate( Col : TGridColumn ;;
  procedure TForm1.Form1Show(Sender: TObject); begin
  with Grid1 do begin
  end;
  Columns[1].ControlType := ctEdit; Rows.Row[0].Value[0] :=
  'Name'; Rows.Row[0].Value[1] := 'Erick';
  Rows.Row[1].Value[0] := 'Org';
  Rows.Row[1].Value[1] := 'Engineering';
  First, add a TGrid to your form, then use the OnShow event to add data to your Grid.
  procedure TForm1.Form1Show(Sender: TObject); begin
  with Grid1 do begin
  end;
  Columns[1].ControlType := ctEdit; Rows.Row[0].Value[0] :=
  'Name'; Rows.Row[0].Value[1] := 'Erick';
  Rows.Row[1].Value[0] := 'Org';
  Rows.Row[1].Value[1] := 'Engineering';
  Notice that we hard code the values above. In practice you can either set them to variables
  or use the database to query the value.
  The trick to getting color is simply to create an OnCellUpdate event handler which adjusts
  the font characteristics.;
  TextCell.index contains the row number of the value, so this example bases color and font
  information on the particular row. And remember, in the OnShow event we only applied
  the OnCellUpdate handler to Column #1. In practice you could apply it to many columns.
  Finally, you may want to base your decision of particular colors on other factors. For
  example, if the data is N/A, or < 0, or whatever, you may want to flag data problems with
  red.
  Persistence is the topic of storing data and recovering it later. Serialization is the ability to
  take an object, flatten it out to some intermediate format for sending over a network or
  storing in a database. Deserialization is the inverse, taking the intermediate format and
  converting it back into a usable object (though possibly in a different environment and/or
  programming language).
  1. We have an object holding some data, say a customer record, or an accounting record, or
  an inventory item sitting on the server database.
  2. We want to get the data from that object into a usable format on the Web client written
  with EWB.’
  3. To get to that client, the data must traverse the Internet in some intermediate format as a
  series of bytes.
  EWB knows how to convert data from structures into two common formats: JSON
  (JavaScript Object Notation). We will see just how easy it is with the first example below.
  unit readerwriter1a;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebEdits, WebBtns;
  type
  published
  property ClientID : integer read fClientID write fClientID;
  TForm1 = class(TForm)
  MultiLineEdit1: TMultiLineEdit;
  Button1: TButton;
  procedure Form1Show(Sender: TObject); procedure
  Button1Click(Sender: TObject); procedure Form1Create(Sender:
  TObject);
  private
  { Private declarations }
  client : TClient;
  Reader : TReader;
  Writer : TWriter;
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  implementation
  procedure TForm1.Form1Create(Sender: TObject); begin
  client := TClient.Create;
  Reader := TReader.Create;
  Writer := TWriter.Create;
  end;
  The data structure TClient is a bit special in that we have defined published properties
  such as FirstName, with read and write properties that save the data into private data
  properties. For convention sake, we name the private properties f…
  When we start our application, the onCreate method creates an empty TClient variable and
  a TReader and TWriter. We will use later
  In the OnShow event hander we display the JSON of the TClient structure in a few short
  lines:
  Then the user is free to edit the JSON and press Button1 which reloads the TClient from
  the MultiLineEdit1 text box.
  By calling Form1Show(), the procedure rereads the JSON notation and updates it on the
  display.
  The output of this simple program looks like this:
  You can see, edit and update the JSON and thus the TClient.
  Now add an fBirthday to the private part of TClient, and Birthday to the published part.
  Private
  …
  fBirthday : DateTime
  Published
  …
  property Birthday : DateTime read fBirthday write
  fBirthday;
  When you rerun the program it displays the date as the number of milliseconds since
  January 1, 1970 UTC. Eg:
  "birthday": 1469207693068
  If you prefer, you can change the default output to ISO date/time by changing
  "birthday": "2016-07-22T17:24:37.585Z"
  or something similar which is more human readable. But it may still be confusing because
  the time is UTC zoned.
  To the novice programmer it seems annoyingly redundant to specifiy private and published
  properties. But there are several good reasons.
  Published properties are used by TReader and TWriter. Having a private property such as
  Phone number could exist without being copied to and fro in the JSON.
  Another benefit is that you can have handlers which correct or interpret the data. For
  example, many systems like to specify gender of someone. Depending on your location and
  current views of gender identity, it may allow Male, Female and Unspecified, or maybe
  other designations. But people often just enter M or F or U. So what if the system
  automatically fixed the data to the long accepted formats.
  ..
  fSex : string;
  procedure LocalWriteSex( s : string );
  Published
  …
  property Sex : string read fSex write
  LocalWriteSex;
  end;
  Sometimes you know you will have arrays of items and will want to often code them as
  JSON arrays – eg. party guests from your TClients. The easiest way to accomplish this
  uses TCollections. But to do so, you must have TClient inherit from TColllectionItem
  (which is a descendant of TPersistent) instead of TPersistent.
  If you took the above examples and substituted TCollectionItem for TPersistent, everything
  works identically.
  Consider the case where we have people and their cousins, who are also people.
  We will build a program which dumps a person and their cousins to persistent storage…
  actually just to a MultiLineEdit box. And we will have a button which rereads that
  MultiLineEdit box and reloads it into our structure. You can tell it works if you change the
  spacing or the entries, and they revert back to EWB’s spacing after you hit the button.
  unit persistarray1;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebEdits, WebBtns;
  type
  published
  property name : string read fname write fname; property
  cousins : TPeople read fcousins write fcousins;
  end;
  TPeople = class( TCollection )
  private
  fPerson : TPerson;
  published
  property person : TPerson read fPerson write fperson;
  procedure TForm1.Form1Create(Sender: TObject); var
  cousin : TPerson;
  begin
  me := TPerson.Create;
  me.name := 'Erick';
  me.cousins := TPeople.Create( TPerson );
  writer.Initialize;
  me.Save( writer );
  MultiLineEdit1.Lines.Text := writer.Output; end;
  procedure TForm1.Button1Click(Sender: TObject); begin
  me.Free; // totally destroy previous copy to start fresh
  me := Nil;
  me := TPerson.Create;
  reader.Initialize( MultiLineEdit1.Lines.Text ); me.Load(
  reader );
  Form1Show( Sender );
  end;
  end.
  In our OnCreate routine we initialize me to be Erick and set two of my cousins. We also
  create a TReader and TWriter for use later.
  procedure TForm1.Form1Create(Sender: TObject); var
  cousin : TPerson;
  begin
  me := TPerson.Create;
  me.name := 'Erick';
  me.cousins := TPeople.Create( TPerson );
  {
  "name": "Erick", "cousins": { } }
  end;
  AWriter.EndArray( Count > 0 ); end;
  So we simply write out the property name (which we call items), start an array, cycle
  through the array and write each member, then end the array.
  In our situation, TPeople has only one field/array we want to persist, the items field. But if
  there were other useful fields, we could use the inherited function to persist them. So for
  future expansion we included the inherited function at the start.
  The process of reading in the data is a little bit more complicated. When you look at the
  above JSON, cousins is a member of TPerson returning a TPeople, and to TPeople we are
  adding an array called items. So we need to extend TPerson and TPeople with some more
  overrides.
  And if the PropertyName is not one of the ones we are specifically looking for, we are a
  good citizen and pass it along to the default handler.
  PropertyName := AReader.GetPropertyName;
  PropertyName := AReader.GetPropertyName;
  LoadArray( AReader );
  end else
  result := inherited LoadProperty(AReader );
  tempperson : TPerson;
  propertyname : string;
  begin
  end;
  The complete code is below. I’ve used {$ifdef} / {$endif} to comment out the code to
  show the initial version and the complete version so you can see what needed to be added.
  unit persistarray1;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebEdits, WebBtns;
  type
  {$DEFINE DEMO}
  published
  property name : string read fname write fname; property
  cousins : TPeople read fcousins write fcousins;
  {$IFDEF DEMO}
  protected
  function LoadProperty( AReader : TReader ):boolean;
  override;
  {$ENDIF}
  TPeople = class( TCollection )
  private
  fPerson : TPerson;
  published
  property person : TPerson read fPerson write fperson;
  {$IFDEF DEMO}
  protected
  procedure SaveProperties( AWriter : TWriter ); override;
  function LoadProperty( AReader : TReader ):boolean;
  override;
  function LoadArrayElement( AReader : TReader ):boolean;
  override;
  {$ENDIF}
  {$IFDEF DEMO}
  procedure TPeople.SaveProperties( AWriter : TWriter ); var
  person : TPerson;
  i : integer;
  begin
  end;
  AWriter.EndArray( Count > 0 ); end;
  PropertyName : string;
  begin
  result := False;
  PropertyName := AReader.GetPropertyName;
  PropertyName := AReader.GetPropertyName;
  LoadArray( AReader );
  end else
  result := inherited LoadProperty(AReader ); end;
  {$ENDIF}
  begin
  me := TPerson.Create;
  me.name := 'Erick';
  me.cousins := TPeople.Create( TPerson );
  me := TPerson.Create;
  reader.Initialize( MultiLineEdit1.Lines.Text ); me.Load(
  reader );
  Form1Show( Sender );
  end;
  end.
  If you are planning to use persistence to deal with MySQL, you will want to exchange data
  in MySQL’s time format, and to most people’s delight, the local timezone is used rather
  than UTC.
  I’ve used {$IFDEF DEMO} to mark the small bit of code you need to add to a class or to
  its ancestor class.
  Much of the code for for this example is stolen from the previous examples. Again, we
  display the serialized version, and when you press the button, it deserializes it back to the
  object.
  unit persistime1;
  interface
  uses WebCore, WebUI, WebForms, WebCtrls, WebEdits, WebBtns;
  type {$DEFINE DEMO}
  published
  property name : string read fname write fname; property
  birthday : DateTime;
  {$ENDIF}
  procedure TForm1.Form1Create(Sender: TObject); var
  cousin : TPerson;
  begin
  me := TPerson.Create;
  me.name := 'Erick';
  me.birthday := now;
  me := TPerson.Create;
  reader.Initialize( MultiLineEdit1.Lines.Text ); me.Load(
  reader );
  Form1Show( Sender );
  end;
  end.
  When we save a class, the class calls SaveProperty for each property passing a name, so
  we use an overload method on SaveProperty. We call PropertyType() to get the property
  type of the property, and if it is a DateTime we handle it ourselves. Otherwise we just call
  the inherited function to handle all other types. We need to change the default date and time
  formatting properties, so we temporarily save their formats and return them again when we
  are done.;
  The code to deserialize is also straightforward. We just check if the type is DateTime,
  swap around the format strings, read in the value, and restore the format string.
  PropertyName := AReader.GetPropertyName;
  PropType:= PropertyType(PropertyName); if PropType =
  TYPE_INFO_DATETIME then begin AReader.SkipPropertyName;
  AReader.SkipPropertySeparator;;
  Creating database web applications is where EWB truly shines. This makes sense because
  Elevate Software was traditionally a database technology company.
  Since version 2.05, EWB supports multiple TDatabase components, how many, it’s
  actually unlimited. Database is created automatically at application startup time for both
  visual and non-visual projects. It keeps track of all datasets used by the application and
  contains properties, methods and events for starting and commiting data transactions as
  well as rolling them back.
  TDataSet manages data between the application and the database for both visual and non-
  visual projects. You typically have one TDataSet for each SQL table in use.
  TDataSets can be dropped on the visual form at design time or created at runtime.
  The important Columns property contains the column definitions for the dataset.
  Database.LoadColumns loads the columns for the dataset directly from the database,
  transparently marshalling the values through a JSON (JavaScript Object NotatioN) string
  across a network connection for the user. TDataSet.LoadColumns similarly loads the
  columns using a JSON format, but it is up to your application to provide that JSON string.
  This provides a handy way of locally inserting values without having the baggage of a
  whole database setup.
  Rows of data are loaded from the server using Database.LoadRows, or
  TDataset.LoadRows following the same server versus local
  Once the TDataSet is loaded, you can navigate using the First, Prior, Next and Last
  methods.
  The TDataSet can also call Insert, Update and Delete to deal with various row operations.
  Insert takes a parameter: Append:Boolean. If true, the TDataSet is extended at the end,
  otherwise the new row is inserted at the current position. Remember to Save after your
  insert.
  Update prepares the current TDataSet row for an update. Call Save when done.
  Delete deletes the current TDataSet row.
  TDataset.Find is used to find a specific or nearest match. It can specify a case insensitivity
  and a Locale insensitivity.
  The nearest match requires an active sort on the database (Sorted = True).
  If there is an active sort on the dataset, CaseInsensitive must match the SortCaseInsensitive
  property.
  TDataSet.Sort invokes the sorting if and only if Sorted is True and sort columns have been
  specified for the dataset.
  SortCaseInsensitive and SortLocaleInsensitive control how the sort is performed.
  You only need call Sort after the sort directions are initially assigned for the columns.
  Subsequent to the sort, any row operations will automatically maintain the correct order of
  the active sort.
  Our first database app will be a static local database on the Web client itself and is simple
  enough to show the principles without getting into the challenges of network
  communications and server configuration.
  Create a new project. Drop a Database | TDataSet onto the form, it’s a nonvisual
  component, so it can be placed anywhere. Name it People. It will be our list of people.
  Double-click on People’s Columns property in the Object Inspector, this opens the
  Columns editor. In the Columns Editor, press the + button to add a new column, it will be
  called PeopleDataColumn1 by default. In the Object Inspector, change the column name to
  PeopleID and the DataType to dtString. Repeat to add a column named PeopleName with
  DataType dtString and Length 50.
  Place two edit boxes on the form, name one edID and the edName. Set their DataSet
  properties to People (to match our DataSet), and their DataColumns to PeopleID and
  PeopleName respectively – do this by clicking the down arrow on the TEdit’s DataSet and
  selecting people, and down arrow on DataColumn and selecting the appropriate column.
  Add a Toolbars | TDataSetToolBar to the form and set its DataSet to People. Now click on
  the main form and add the following OnShow handler and add
  procedure TForm1.Form1OnShow(Sender: TObject); begin
  Database.AutoTransactions := False;
  People.Open;
  People.LoadRows(
  '{ "rows": [
  { "PeopleID": "1",
  "PeopleName": "Hon" },
  { "PeopleID": "2",
  "PeopleName": "Daniel" }]}', False); end;
  Press F9 and you will have a navigable database application, albeit a minimalist one. You
  can insert, delete, modify and search the records. Since there is no backend, all the data
  changes are lost.
  You can add additional records programmatically with the following code in a TButton
  OnClick handler:
  Let’s add a Master-Detail relationship. Add a TGrid, set its DataSet property to people,
  and press F9. The TGrid automatically uses the correct column names and displays when
  you run it.
  Clicking on a name in the master table brings it into the current record field for the TEdits.
  Change a field in its TEdit, hit update, and the master table reflects the change. The
  TDataSet replaces large amounts of code you would think you might have to write.
  If you typed in the previous example, you may have run into problems entering the JSON
  code.
  JSON is a popular standard for data exchange, not unlike XML. But it differs from XML in
  that it is quite compact and fast for machines to parse. It is also relatively human-readable.
  But entering it manually is a pain, you should never have to do that.
  EWB supports database transactions, where you make a bunch of changes on the client
  dataset and then can either commit the to the server or rollback the changes.
  First set:
  Database.AutoTransactions := False;
  The code is basically:
  Database.StartTransaction;
  … do some operations …. if happy then
  Database.Commit Else
  Database.RollBack;
  The transactions are not Database Locks, they do not prevent others from making changes.
  They are only pertinent to the client dataset – ie. the dataset in memory.
  There is an excellent example in the EWB samples, see the transactions folder.
  Automatic transactions are a feature you can use if you set
  Database.AutoTransactions := True;
  When you use AutoTransactions, the simple act of inserting or editing a row in the database
  locks the row in the client dataset until you commit with a Save operation. No transaction
  code needs to be written – assuming your database supports EWB’s locking. Many
  databases do not, so then you should turn off Automatic Transactions.
  That remains true even if you have a more complicated setup, like a master/detail form.
  When you start inserting or editing the master row, EWB starts a transaction that does not
  commit until you save the master row. And during that time, any changes in the detail view
  will be executed in a nested transaction.
  The single call to Save on the master row will commit all nested changes at once.
  I recommend re-reading/refreshing the data rows periodically as other users may have
  changed them, and also EWB can get out of sync after making changes it doesn’t
  understand. For example, when you create a new SQL record with SQL CREATE/Database
  Insert, the key field (eg. Index number) does not get assigned until the database enters the
  transaction, but it never updates the client. So you shoud refresh the client after every
  operation, and otherwise after long periods of inactivity.
  For this chapter we will only consider PHP databases using SQL. The reader is assumed to
  know some PHP and SQL. We will construct a skeletal PHP program less than 100 lines
  long that simulates a database server and logs the EWB-intended operations from the
  JSON based RESTful database operations.
  This database server code is in lieu of an official PHP database from Elevate which was
  planned for release 2.05. My implementation is basic in many ways. The functionality it
  lacks: is a long list
  • localization
  • datetime support
  • sorting
  • full UTF8 character support (non-alphanumeric characters may change)
  • BLOBs
  • SQL string length limiting
  • Type validation
  • Error checking
  • Access controls
  • Etc.
  REST is a truly open standard of how to represent large collections of data objects over a
  network connection. Using JSON (or XML on some other systems) over HTTP/HTTPS,
  REST allows one to specify the CRUD (create, read, update, delete) operations of a
  database. But it is truly stateless, you can reboot your server or replace it with a new
  server, and the REST operations will still make sense.
  EWB uses two REST HTTP verbs: GET which gets one or more entries (akin to SQL
  SELECT), and PUT which batch uploads a transaction of one or more operations (such as
  SQL’s UPDATE, CREATE, DELETE).
  The rest of this section is optional, you can read it to learn, or you can skip to the
  example.
  All operations specify a Database name and a DataSet name to the server in the
  $_SERVER variable and a request=operationname. Also, if you specify a Userid and
  Password, they are transferred in the X-EWBUser and X-EWBPassword parameters of
  $_SERVER.
  Then it will contain a JSON array of the list of operations to be completed in the
  transaction with a dataset. Each operation will have an opcode: 1 for INSERT, 2 for
  UPDATE, and 3 for DELETE, as well as a list of before and after parameters specifying
  the object in question before the operation and the values after the operation.
  I think this represents the bare minimum client you would want to consider for an EWB
  database application.
  The form has an empty TGrid named Grid1, a TDataSet named DataSet1 and buttons names
  btInsert, btUpdate and btDelete.
  unit sqlclient1;
  interface
  uses WebDom, WebCore, WebUI, WebForms, WebCtrls, WebData,
  WebGrids, WebBtns;
  type
  TForm1 = class(TForm)
  DataSet1: TDataSet;
  Grid1: TGrid;
  btInsert: TButton;
  btUpdate: TButton;
  btDelete: TButton;
  procedure Form1Show(Sender: TObject);
  procedure btInsertClick(Sender: TObject);
  procedure btUpdateClick(Sender: TObject);
  procedure btDeleteClick(Sender: TObject);
  private
  { Private declarations }
  procedure Select_Query;
  procedure CommitError(Sender: TObject; const ErrorMsg:
  String);
  procedure AfterCommit(Sender: TObject);
  public
  { Public declarations }
  end;
  var
  Form1: TForm1;
  implementation
  Grid1.Dataset := Dataset1;
  Grid1.NewColumn;
  colgrid := Grid1.Columns[0];
  colgrid.Header.Caption := 'StaffID'; colgrid.DataColumn :=
  'StaffID';
  Grid1.NewColumn;
  colgrid := Grid1.Columns[1]; colgrid.Header.Caption :=
  'Name'; colgrid.DataColumn := 'Name';
  HideProgress;
  ShowMessage( ErrorMsg , 'SQL Error');
  if window.confirm('Do you want to retry the commit ?') then
  begin
  ShowProgress('Retrying commit...');
  Database.RetryPendingRequests;
  end;
  end;
  procedure TForm1.AfterCommit(Sender: TObject); begin
  HideProgress;
  end;
  procedure TForm1.Select_Query;
  begin
  Dataset1.Params.Add('dept=Engineering');
  Database.LoadRows( DataSet1 );
  end;
  end.
  The most important setup details appear in the page’s onShow handler. The
  AutoTransactions is new for 2.05 and eliminates the need to start and end a transaction to
  do simple operations. BaseURL is the URL to our database server PHP application.
  We also set the user name and the user password. These will be passed to our server. In a
  modern OAuth2 environment, you would replace the password with a JSON Web Token
  (JWT), but that’s another story.
  Next in the function we add zero or more criteria to narrow the search/SELECT, by adding
  “dept=Engineering” we are saying only Engineering users will be considered. Then we
  load the DataSet.
  Dataset1.Params.Add('dept=Engineering');
  Database.LoadRows(DataSet1);
  The rest of the operations are straightforward.
  This code is very incomplete, it is meant to show you how to access the parameters to
  produce SQL commands. To keep it simple, there little error checking, no data validation
  or access controls in this sample, so it would be a nightmare to place on the big bad
  Internet in its present form. This is an educational tool only.
  In about 90 lines of boilerplating, and a few lines PHP to SQL conversion code you will
  replace (functions starting with sql_...), this code can function with most EWB database
  examples, including the transaction example.
  It does not handle BLOBs (binary large objects) for things like pictures, but it can return a
  URL and you can use that to reference a picture for download. simple.php <?php
  function sql_select($user, $pass, $database, $dataset,
  $inputargs)
  {
  $i = 0;
  foreach ( $outputargs as $a=>$b) {
  if ( $i++ > 0) {
  $sqla .= ',';
  $sqlb .= ',';
  }
  $sqla .= $a;
  $sqlb .= "'$b'";
  }
  savelog( "SQL: INSERT INTO $dataset ( $sqla ) VALUES ( $sqlb
  )");
  return '';
  }
  {
  return 1;
  }
  //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  =-=
  =-=-=-=-=-=
  define("EWB_OPERATION_UNKNOWN", 0);
  define("EWB_OPERATION_INSERT", 1);
  define("EWB_OPERATION_UPDATE", 2);
  define("EWB_OPERATION_DELETE", 3);
  header('Cache-Control: no-cache');
  //header('Content-Type:vapplication/json; charset=utf-8');
  function safetext( $src )
  {
  return( htmlentities( $src, ENT_QUOTES ));
  }
  function savelog( $msg )
  if ( $f = fopen("log","a+")) { fwrite( $f, "$msg\n" );
  fclose( $f );
  }
  }
  function getpostdata()
  {
  $postdata = file_get_contents("php://input"); return
  ($postdata);
  }
  function rest_error($msg) {
  header("EWB_HTTP_ERROR", "HTTP/1.0 500 $msg"); exit(0);
  }
  {
  case 'rows':
  $options = array();
  if( ! isset($_REQUEST['dataset']))
  rest_error('missing dataset');
  $dataset = safetext( $_REQUEST['dataset'] ); if( !
  isset($_REQUEST['database']))
  rest_error('missing database');
  $database = safetext( $_REQUEST['database'] );
  foreach($_REQUEST as $directive=>$value) if(($directive !=
  'database') && ($directive != 'dataset') && ($directive !=
  'method'))
  $options[safetext($directive)] = safetext($value); }
  $output = sql_select($user, $pass, $database, $dataset,
  $options);
  break;
  case 'commit':
  $data = getpostdata();
  $json = json_decode($data, TRUE);
  $json2 = $json['operations'];
  foreach($json2 as $operation) {
  if( ! isset($operation['operation'])) rest_error('missing
  operation');
  $op = $operation['operation'];
  if( ! isset($_REQUEST['database']))
  rest_error('missing database');
  $database = safetext( $_REQUEST['database'] ); if( !
  isset($operation['dataset']))
  rest_error('missing dataset');
  $dataset = safetext( $operation['dataset'] );
  $inputargs = array();
  foreach ( $operation['beforerow'] as $a=>$b)
  $inputargs[safetext($a)] = safetext($b);
  $outputargs = array();
  foreach ($operation['afterrow'] as $a => $b )
  $outputargs[safetext($a)] = safetext($b);
  switch($op) {
  case EWB_OPERATION_INSERT:
  ?>
  You can see we handle the two types of requests described ealier, rows for SELECT and
  commit for all INSERT, DELETE and UPDATE commands.
  This simple program produces an output log file called log in the local subdirectory
  (assuming it has write permissions).
  For this example output, I ran the web page which called rows to get a list of Engineering
  people, and then I called UPDATE and DELETE by starting a commit, editing, deleting,
  and closing commit.
  You may wonder why we pass the userid and password (or its cousin the JWT token) to the
  SQL function. As you build more complex systems, undoubtedly you will start using other
  REST services to answer your queries, and you will need to either identify the user or pass
  the OAuth2 JWT token. Until then, it doesn’t hurt to have an unused parameter present.
  I would recommend that you reopen the dataset after closing any commit if you use
  commits, or after you make any change if you use autocomits, because the master table can
  get out of sync when a person makes nonsensical edits. For example, it allows you to set,
  change or clear the person id number, which no database ever should allow, and as we saw
  in the output above, unassigned values like StaffID of INSERTed records may be missing,
  making the subsequent DELETE fail.
  I built the JSON by hand in the request= rows response. Sometimes the PHP internal JSON
  building library consumes too much memory and the process terminates, so building JSON
  by hand avoids that problem.
  For a production database you would replace the sql_... functions with your own. They
  would clean up the arguments, test their sanity, and then test user permissions before
  performing any database operation.
  What is surprising to many developers from other technologies, when you write these
  functions you are enabling them to be used by whomever and however that person may
  choose. There is no guarantee the database request came from any specific line of your
  code, it could be another developer, or it could be a hacker. Code wisely my friend.
  SQL table JOINs allow you to SELECT and UPDATE on multiple tables at once.
  Suppose you were showing a table of userids joined with addresses. You could
  SELECT * FROM userids NATURAL JOIN addresses WHERE dept = ‘Engineering’
  Likewise, you can update fields on the JOIN
  UPDATE userids NATURAL JOIN addresses SET street=’king’ WHERE userid = ‘tomk’
  You only need to differentiate tables during INSERT and DELETE operations. Normally
  you will add the three A’s, Access control, Authorization and Auditing.
  Only the simplest databases do not care for who is connected – say perhaps a phone book
  app. But if one can enter or change data, usually some form of access control and
  authorization is required to keep the bad people on the Internet from destroying your data.
  Even read-only data is precious. If your customer list were exposed, your competitors
  could steal your customers.
  As mentioned previously, you will sometimes want to download a BLOB, such as a PDF
  document, or a jpeg image.
  While this code does not handle BLOBs, it can reference a URL. That might seem
  awkward, wouldn’t the URL have to check the user’s permission to view the file? Not
  really, you can specify a difficult-to-guess and impossible-toenumerate filename and that
  will secure your files.
  YouTube does exactly that with its videos. It generates a random URL with a packed
  base64 encoding for each filename at store time. If another file exists with that name, it
  tries other names until it finds a free one. But the namespace is so enormous, multiple hits
  are rare.
  Also, the odds of a person requesting the any correct filename are miniscule and can be
  made infitessimal if we also check for excessively many failed attempts from a given IP
  address and impose an exponential backoffs after n failures.
  The code to accomplish this is relatively straightforward, but be sure you are using a good
  random number generator, or else your filenames will be predictable.
  ObjectPascal over JavaScript can only do so much on the client. Eventually you will want
  to communicate with a server for:
  - Database transactions
  - Messaging/Email
  - Any number of things not doable by the client directly
  - The EWB environment includes built-in functionality to marshal data into a standard
  format (JSON) and use protocols (HTTP/HTTPS) to connect to servers and ask them to do
  things.
  They can also perform RPC (remote procedure calls) where the Delphi code in the client
  ends up calling a PHP function in the server, passing parameters to and fro.
  The RPCs on the server can talk to other services, such as Google’s or Microsoft’s
  network services, and perform all manner of tasks such as geolocation, scheduling,
  messaging, etc.
  Some of our examples follow the Elevate strategy directly, others are mashups of our own.
  We will be sure to explain each.
  Remember CORS (Cross Origin Resource Sharing) imposes limitations on your web page:
  it means your web page only communicates with the server that is hosting the page. If you
  intend other servers to be used, you must enable Cross-Origin Resource Sharing on both
  the development site, and the production site. This is not specifically a EWB topic, it
  applies to all web client technologies.
  If data is going across a network, you really want it encrypted. The following functions can
  CheckHTTPS determines if either the connection is HTTPS, or if the connection is to
  localhost (ie. the local machine) which means unencrypted is okay. function
  CheckHTTPS: boolean;
  var
  hostname : string;
  protocol : string;
  begin
  protocol := LowerCase(window.location.protocol);
  hostname := LowerCase(window.location.hostname);
  result := ( hostname = 'localhost')or( protocol = 'https:');
  end;
  MakeHTTPS makes the current page HTTPS unless it is on the localhost, in which case it
  can stay unenecrypted.
  procedure MakeHTTPS;
  var
  s : string;
  hostname, port, search : string;
  pathname , name : string;
  begin
  if not CheckHTTPS then begin
  hostname := window.location.hostname; port :=
  window.location.port; search := window.location.search;
  pathname := window.location.pathname;
  s := 'https:' + hostname;
  if ( port <> '' ) then s := s + ':'+ port; if (pathname <>
  '') then s := s + pathname; if ( search <> '' ) then s := s
  + search;
  window.location.replace( s ); end;
  end;
  This first example does not follow Elevate’s standard exchange of data, but it is easy to
  read and will set the stage for future examples.
  We will define a protocol where our Object Pascal client send data parameters to a PHP
  application’s function, and that function returns data variables to the client. This is an RPC
  or Remote Procedure Call.
  For our first simple example, we will get a message-of-the-day for a given user, so we
  need to pass the userid, a password to verify it is truly our trusted user, and a function name
  for the request.
  Eg.
  userid = ‘erick’
  password = ‘happy’
  method = ‘advice’ : remote function call
  And we will get returned
  result = 0 : meaning failure result = 1 : meaning success
  and if result =1, we will be returned some advice in the variable wisdom. Eg.
  wisdom = ‘the secret to life is EWB’
  For our example, use a TEdit to hold a userid, a TPasswordEdit to enter a password, a
  TButton to invoke the transaction, and a TLabel to hold the result. Here are the two main
  EWB functions: We call GetWisdom and it has a callback called GetWisdomResults that
  updates the TLabel.
  procedure
  TForm1.GetWisdomResults(results:Boolean;wisdom:string);
  begin
  if results then
  Label1.Caption := wisdom
  else
  Label1.Caption := 'results not found';
  end;;
  This code allocates a TServerRequest if we don’t already have a previous one, sets the
  request handler and marshals in the data and the method name.
  When the server replies, the following code is invoked:
  procedure TForm1.GetWisdomRequestComplete(Request:
  TServerRequest);
  var
  rpcresults : TStringList;
  begin
  if (Request.StatusCode <> HTTP_OK) then begin
  ShowMessage('Error: '+Request.ResponseContent.Text);
  GetWisdomResults( False, '');
  end
  else
  begin
  rpcResults := TStringList.Create;
  rpcResults.Text := Request.ResponseContent.Text;
  else
  {
  $method = $data['method']; switch($method)
  {
  case 'GetWisdom': GetWisdom($data);
  default: print "result=0\nerror=method $method not
  found\n";
  exit();
  }
  This code parses the POST data, checks for a method, and if we understand the method,
  invokes it with the data.
  Here is the parse_data() function:
  function parse_data() {
  global $HTTP_RAW_POST_DATA;
  $z = array();
  $s = $HTTP_RAW_POST_DATA; $xx = explode("\n", $s);
  foreach($xx as $a=>$b) {
  $z[$yy[0]] = $yy[1]; }
  return ($z);
  function GetWisdom($data) {
  if(CheckPassword($data)) {
  $res = 'Secret to life is EWB'; print "result=1\n";
  print "secret=$res\n";
  }
  else
  {
  print "result=0\n"; }
  Nice and simple. Note, it calls CheckPassword which would normally be an LDAP
  lookup, or an OAuth2 call, or a database lookup, or a RADIUS call. We’ll just hard code it
  for now:
  function CheckUserid($data) {
  if(isset($data['userid']) && isset($data['password'])) {
  $userid = $data['userid'];
  $password = $data['password'];
  if(($userid == 'erick') && ($password == 'happy')) return
  (1);
  }
  return (0);
  }
  I’m not recommending you follow this path, but it shows the steps involved if you choose
  to roll your own protocol or support an existing system. And once you have one function,
  like our GetWisdom() in PHP, adding more is trivial.
  TForm1 = class(TForm)
  Button1: TButton;
  Edit1: TEdit;
  PasswordEdit1: TPasswordEdit;
  Label1: TLabel;
  Browser1: TBrowser;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  WebRequest : TServerRequest;
  procedure GetWisdom( userid, passwordtext : string );
  procedure GetWisdomResults( results : Boolean ; wisdom :;
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  =-==-=-=-=-=-=-=-=-=-=
  procedure TForm1.GetWisdomRequestComplete(Request:
  TServerRequest);
  var
  rpcresults : TStringList;
  begin
  if (Request.StatusCode <> HTTP_OK) then begin
  ShowMessage('Error: '+Request.ResponseContent.Text);
  GetWisdomResults( False, '');
  end
  else
  begin
  Browser1.DocumentText := Request.ResponseContent.Text;
  rpcResults := TStringList.Create;
  rpcResults.Text := Request.ResponseContent.Text;
  if rpcResults.Values['result'] = '1' then
  if results then
  Label1.Caption := wisdom
  else
  Label1.Caption := 'results not found'; end;
  end.
  $z = array();
  $s = $HTTP_RAW_POST_DATA; $xx = explode("\n", $s);
  foreach($xx as $a=>$b) {
  $z[$yy[0]] = $yy[1]; }
  return ($z);
  function CheckUserid($data) {
  if(isset($data['userid']) && isset($data['password'])) {
  $userid = $data['userid'];
  $password = $data['password'];
  if(($userid == 'erick') && ($password == 'happy')) return
  (1);
  }
  return (0);
  }
  function GetWisdom($data) {
  if(CheckPassword($data)) {
  $res = 'Secret to life is EWB'; print "result=1\n";
  print "secret=$res\n";
  }
  else
  {
  print "result=0\n"; }
  }
  $data = parse_data();
  if( ! isset($data['method']))
  print "result=0\nerror=No method specified\n";
  else {
  $method = $data['method']; switch($method)
  {
  case 'GetWisdom': GetWisdom($data); break; default: print
  "result=0\nerror=method $method not
  found\n";
  exit();
  }
  }
  ?>
  Setting Address0 to 3 indicates there are three Address lines. It’s not hard, but it’s not
  great.
  Unlike the standards, it’s not self-specifying. You need to make up and know what all the
  parameters are.
  EWB likes results in JSON format, and that solves these problems. Only minor changes are
  needed to the client and server.
  First, the server:
  We will use the PHP json_encode() function which takes a PHP object as its parameter. So
  first we will define the results type:
  class result {
  public $wisdom = "";
  }
  We will define a global $error set to null. If an error is found, functions just need to set
  $error to a value and the PHP code will return an HTTP error with the error code returned
  as the sole text.
  $data = parse_data();
  $result = new result();
  if( ! isset($data['method'])) {
  function GetWisdom($data ) {
  global $error, $result; if(CheckPassword($data)) {
  $res = 'Secret to life is EWB'; $result->wisdom= $res;
  }
  else
  {
  $error = 'bad userid or password';
  }
  }
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // boilerplate
  function parse_data()
  {
  global $HTTP_RAW_POST_DATA;
  $z = array();
  $s = $HTTP_RAW_POST_DATA; $xx = explode("\n", $s);
  foreach($xx as $a=>$b) {
  $z[$yy[0]] = $yy[1]; }
  return ($z);
  global $result;
  if(isset($data['userid']) && isset($data['password'])) {
  return (1);
  }
  return (0);
  }
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // updated GetWisdom
  function GetWisdom($data ) {
  global $error, $result; if(CheckPassword($data)) {
  $res = 'Secret to life is EWB'; $result->wisdom= $res;
  }
  else
  {
  $error = 'bad userid or password'; }
  }
  } else {
  print json_encode( $result );
  }
  ?>
  The major changes to the client program is that we use a TWisdom to hold the result set:
  type
  TWisdom = class ( TPersistent )
  private
  fwisdom : string;
  published
  property wisdom : String read fwisdom write fwisdom; end;
  The data receiver is greatly simplified:
  procedure TForm1.GetWisdomRequestComplete(Request:
  TServerRequest);
  begin
  TForm1 = class(TForm)
  Button1: TButton;
  Edit1: TEdit;
  PasswordEdit1: TPasswordEdit;
  Label1: TLabel;
  Browser1: TBrowser;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  WebRequest : TServerRequest;
  Wisdom : TWisdom;
  reader : TReader;
  procedure GetWisdom( userid, passwordtext : string );
  procedure GetWisdomResults( results : Boolean ; errmsg::='jsonserver.php';
  Method:=rmPost;
  RequestHeaders.Values['Content-Type']:='text/plain';
  RequestContent.Values['userid']:= userid;
  RequestContent.Values['password']:= passwordtext;
  RequestContent.Values['method'] := 'GetWisdom';
  Execute;
  end;
  end;
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  =-= procedure TForm1.GetWisdomRequestComplete(Request:
  TServerRequest);
  begin
  end
  else
  begin
  Label1.Caption := wisdom.wisdom
  else
  Label1.Caption := 'results not found:' + errmsg; end;
  end.
  In this chapter we will deal with interfacing with JavaScript by loading JavaScript
  modules, calling JavaScript functions, interfacing with the Document Object Model, and
  learning how to translate code fragments into Object Pascal.
  There are a number of reasons why you would want to call JavaScript routines.
  •
  •
  •
  •
  •
  In some cases, you will call JavaScript for the above reasons, other times you will choose
  to implement the functionality in EWB Object Pascal. Personally, I prefer Object Pascal
  for the reasons I outlined in the first chapter, even though the resulting code that executes is
  in fact JavaScript.
  For the rest of this chapter and any units you write which involve JavaScript, include
  WebDom in your uses line. It contains the essentials needed to interface with JavaScript
  and you will get random errors if you forget it.
  Define your types in the interface section. Declare all types before you declare variables.
  Things written in JavaScript are of class object according to EWB terminology, whereas
  most EWB classes are of class TObject. JavaScript itself is a classless language, it’s an
  object language.
  Type
  TDog = class( TObject ) public
  petname : string;
  end;
  var
  mydog : TDog;
  begin
  mydog = TDog.Create;
  mydog.petname := ‘harry’; end;
  which gives a similar but slightly different result than usual JavaScript: mydog := new
  Object();
  mydog.petname := ‘harry’;
  In many cases the default class(TObject) will work, but there are some libraries which
  will get upset because the mydog object is different due to the creation technique.
  If you get an error and need to simulate the above JavaScript code, you have to do things
  slightly differently. First, declare the class of no ancestor type, or of type object, either
  way it will be a descendant of object. You will also have to declare it external.
  Type
  External TGlobalDog = class
  Public
  begin
  myglobaldog := TGlobalDog(
  eval( ‘new Object();’)); myglobaldog.petname := ‘harry’;
  end;
  EWB has two types we will use frequently in this chapter: variant and object. Object refers
  to classes. Variant refers to any type: it can be an integer, string, object, etc.
  When you need to access a JavaScript function, declare it external as we did above with
  eval().
  External function eval ( s : string ) : object;
  If you do not care about the result of a JavaScript function, you can declare it as a
  procedure rather than function.
  Variant is the type of JavaScript variables if you are not concerned about the type, and cast
  it to the type you want.
  var
  External myArg : variant; S : string;
  Begin
  S := string( myArg );
  End;
  If the external object is a class with methods and properties, declare them as such. Declare
  the class of no particular type, or declare it of type object, which is the same thing. For
  example, consider a JavaScript class we call library, declared to the EWB class TLibrary.
  Type
  External Tlibrary emit library = class
  Public
  Property name : string read; Property obj : integer read
  write; Function init( arg1: integer;
  Begin
  Result := Library.init( 1, 3 );
  End;
  Note, EWB does not reference the global variable until your code does. So if you load the
  library later, you must wait until it’s fully loaded before accessing the variables. The
  easiest way to do this are to use TScript to load the library, then either call the library from
  its onload handler, or set a flag during onload that indicates the library is available for use.
  We’ll see an example of this flagging later in the OAuth 2.0 example.
  Some of these preliminaries are difficult now, but they should become clearer with the
  examples shown next.
  The DOM is used to access parts of your web page to read, change, or create new ones.
  You can also use the DOM to add JavaScript or CSS files if you wish. Google is your
  friend to learn about the DOM.
  To access the DOM, include the WebDom EWB module to your source file. It exposes the
  external (meaning JavaScript) variable window of class type TWindow.
  var
  external window: TWindow;
  And TWindow is defined by the EWB uses files as:
  I will not normally show the whole classes, but this one is quite useful and I wanted to
  pique your interest. The emit word means to use the following JavaScript class but refer to
  it with an EWB name, usually starting with T for convention sake.
  Some of the methods and values are specific to certain web browsers, eg. Orientation,
  OuterHeight, etc.
  What can you do with it? Almost anything!
  You can call window.print and the page will ask the user if the current window should
  print.
  If you want to pop up a message and temporarily stop your code, call
  window.alert(‘some message’). It creates a modal dialog.
  You can see that window.screen returns a TScreen, which is defined as:
  external TScreen emit Screen = class
  public
  { Properties }
  property availHeight: Integer read; property availWidth:
  Integer read; property colorDepth: Integer read; property
  height: Integer read; property width: Integer read;
  end;
  So you could use that to see the color depth, the screen height, etc.
  Look at THTMLElement:
  If you are given a TDOMElement for an HTML element, you can cast it to THTMLElement
  and then call the THTMLElement methods or access its properties.
  For example, suppose you were given an HTML <div id=’qunit’></div> tag pair
  and wanted to insert a message between them:
  The JavaScript way would be to call the DOM;
  Suppose you wanted to create that ‘qunit’ DIV on the fly, you could use
  window.document.body.appendChild and window.document.createElement.
  Procedure createqunit;
  Var
  ele : TDomElement;
  html : THTMLDocument;
  begin
  ele := window.document.createElement('div');
  ele.setAttribute('id','qunit');
  html := THTMLDocument(window.document );
  html.body.appendChild( ele );
  end;
  If you wanted to load an external CSS file, you could do that by extending the HEAD DOM
  element.
  Procedure loadqunitcss;
  Var
  css : TDomElement;
  html : THTMLDocument;
  url : string;
  begin
  url := 'qunit.css';
  css := window.document.createElement('link');
  css.setAttribute('rel', 'stylesheet');
  css.setAttribute('type', 'text/css');
  css.setAttribute('href', url);
  html := THTMLDocument(window.document );
  html.body.appendChild( css );
  end;
  While you could do something similar to our loadqunitcss to load a JavaScript file, I prefer
  to use the EWB strategy and either have a GUI created TScript, or call TScript when you
  need it with:
  Procedure Form1.loadqunitscript; begin
  script := TScript.Create( self );
  script.onerror := script1error;
  script.onload := script1load;
  script.url :='qunit.js';
  end;
  And then define script1error which displays an error, and script1load which can then call
  the loaded script.
  In JavaScript redirecting to a different page is accomplished with
  window.location.href = ‘’;
  EWB Object Pascal is almost identical:
  window.location.href := ‘’;
  It is common to include libraries for specific functionality because including a library is a
  lot easier than recoding it in EWB ObjectPascal.
  In general, you will usually call either global procedures/functions, or deal with JavaScript
  classes.
  We will work with the Clippy.JS library that provides simulated Microsoft Office Clippy
  characters. See the documentation and demonstrations at:-
  js
  A typical use would load clippy with the EWB external libraries code, or a TScript
  strategy as discussed in the previous chapter. You will also need to have it load a JQuery
  library using the same technique.
  To do that from EWB, you need to define a subset of the class. You don’t need the whole
  class, just the methods and attributes we will access. And you declare the global variable
  of the class.
  Type
  end;
  // we define the global function TYPE Tclippyproc =
  procedure( agent : TAgent );
  Sometimes you need a form of RichEdit to accept user input. There are several free and
  several commcerical ones available. I picked CK Editor as it has support for spellchecking
  in many languages and an obscene number of plugins.
  To use CK Editor you place a normal MultiLineEdit on the page at design time, we’ve
  named ours MultiLineEdit1, and we will tell CK Editor to replace the MultiLineEdit1 with
  its own editor at run time.
  We’ve also created an HTML DIV which will hold the rich text we create, and placed it to
  the side. When you run your program it will look like this:
  unit richeditor1;
  interface
  uses Webdom, WebCore, WebUI, WebForms, WebCtrls, WebComps,
  WebEdits, WebLabels, WebBrwsr;
  type
  TForm1 = class(TForm)
  Script1: TScript;
  MultiLineEdit1: TMultiLineEdit;
  Browser1: TBrowser;
  procedure Script1Load(Sender: TObject); procedure
  MultiLineEdit1Change(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  implementation
  MultiLineEdit1.clientID := 'Edit1';
  CKEDITOR.replace('Edit1');
  text1 :=
  '<h1>Hi There</h1><p>Welcome to <i>our</i> editor.</p>';
  eval('CKEDITOR.instances.Edit1.setData("'+ text1+'" );');
  p := MultiLineEdit1Change;
  eval('CKEDITOR.instances.Edit1.on("change", p );');
  MultiLineEdit1Change( Nil ); end;
  procedure TForm1.MultiLineEdit1Change(Sender: TObject);
  begin
  browser1.DocumentText := string(
  variant( eval('CKEDITOR.instances["Edit1"].getData();')));
  end;
  end.
  In order to tell CK Editor to replace the default MultiLineEdit with itself, it needs to know
  MultiLineEdit1’s HTML ID. EWB does not normally set IDs, but we can set it with
  clientID. So we say:
  MultiLineEdit1.clientID := 'Edit1';
  CKEDITOR.replace('Edit1');
  Next we want to set the data string, so we call setData(). We could have defined the whole
  Pascal objects, but it was simpler just to call JavaScript’s eval() routine and let it deal
  with the complicated mess.
  We need to update the screen after each keystroke or mouse change, so we want to set
  CKEditor’s Change function. You would think we could specify a typical function to do
  this, but EWB changes the functions names, especially when you compress your output. So
  first we set variable p to the name of the function we want to call – EWB automatically
  knows the correct function name at compile time, so it fills it in. Then we assign the
  Change event to p at run time.
  p := MultiLineEdit1Change;
  eval('CKEDITOR.instances.Edit1.on("change", p );');
  MultiLineEdit1Change( Nil );
  We call MultiLineEdit1Change to update the DIV right away, so it displays the supplied
  text the instant one opens the web page.
  MultiLineEdit1Change() just copies the getData() data from the CK Editor into the DIV. But
  remember I was lazy and did not create all the structures but just called eval(), well eval()
  returns an object but I need a string. I cannot cast an object to a string, but I can cast it to a
  variant, and variants can be cast to strings. So we get this nasty casting that throws out all
  the protections of EWB but convinces the compiler it makes sense.
  You may wonder why I have Sender : TObject as a passed parameter. Again, laziness. I
  used MultiLineEdit1’s OnChange default handler to create this. Unlike some programming
  enviroments where passed parameters must be cleaned up by the function, JavaScript (and
  thus EWB) can be passed any number of unused parameters. JavaScript is just that way.
  EWB creates applications with the speed and flair of real applications. But traditionally
  JavaScript could not read local files as that would be a security hole. That changed with
  the File Reader. Now you can have the ability to load local files into your application and
  process the data any way you like. An example of this would be to have a YouTube-like
  uploader which sends files upstream and gives a visual indicator of the progress.
  For our example we will ask the user for a file to read, then load it into a multiline edit
  control. Obviously text files would look best in that editor.
  Since the user may load a large file, we display the EWB busy message while the file
  loads. In fact, try loading a huge file like a movie, it will take forever but at least the busy
  message explains why.
  TForm1 = class(TForm)
  HTMLForm1: THTMLForm;
  FileComboBox1: TFileComboBox;
  Timer1: TTimer;
  Label1: TLabel;
  MultiLineEdit1: TMultiLineEdit;
  Label2: TLabel;
  Label3: TLabel;
  procedure Timer1Timer(Sender: TObject);
  private
  { Private declarations }
  procedure StartReading( f : TFileType ; r : TFileReader);
  function readSingleFile( evt : TMyEvent):boolean;
  public
  { Public declarations }
  end;
  end;
  end;
  var
  Form1: TForm1;
  external function eval( arg : string ) : object;
  implementation
  function myreader( x : TArgFileReader ):integer; var
  contents : string;
  begin
  contents := x.target.result;
  HideProgress;
  Form1.MultiLineEdit1.Lines.Text := contents ;
  Form1.MultiLineEdit1.Visible := True; result := 0;
  end;
  begin
  Timer1.Enabled := False;
  // set the ID of FileComboBox1 to FileComboBox1
  FileComboBox1.ClientID := 'FileComboBox1';
  ele := TDOMElement(window.document.getELementByID(
  'FileComboBox1'));
  ele.addEventListener('change',readsinglefile, False );
  FileComboBox1.Visible := True;
  end;
  end.
  Some explanation is necessary. Look at Timer1Timer event. First we cancel the timer so
  we don’t get subsequent events. The EWB normal onchange handler does not pass the
  Event, just the Sender, but we need the Event from from the FileComboBox1 change event
  as it contains the file information. So we need to call addEventListener to tell the DOM to
  call our readsinglefile routine in the event of a filename change.
  That introduces a second problem, DOM likes to refer to elements by their ID, but EWB
  does not use ID’s and so doesn’t bother setting them. So first we set the ID by setting the
  clientID = ‘FileComboBox1’. Then we can use getElementByID(‘FileComboBox1’) and
  make our changes.
  ReadSingleFile could contain all the code of StartReading, but we call it Async so that
  ShowProgress() can start first and Label1.Caption will be displayed.
  MyReader is called when the file loading is complete, so it does something with the data
  and clears the progresss meter.
  For production code you would need to better test with try/except to detect browsers that
  cannot handle the reader. We left them out of this sample to keep it shorter.
  This example lets you select a local file and then upload it using JavaScript. We will
  indicate the filename and filesize while uploading.
  unit fileuploader1;
  interface
  uses WebDom, WebHttp, WebCore, WebUI, WebForms, WebCtrls,
  WebBrwsr, WebEdits, WebBtns, WebComps,
  WebLabels;
  type
  TForm1 = class(TForm)
  HTMLForm1: THTMLForm;
  FileComboBox1: TFileComboBox;
  Timer1: TTimer;
  Label2: TLabel;
  Label3: TLabel;
  procedure Timer1Timer(Sender: TObject);
  private
  { Private declarations }(
  base64 : string );
  public
  { Public declarations }
  end;
  public
  property name : string read; property size : integer read;
  property type : string read;
  //
  end;
  external TFileReader = class
  public
  property onload : TArgFileReaderFn read write; procedure
  readAsText(f : TFileType); procedure readAsDataURL( f :
  TFileType );
  end;
  var
  Form1: TForm1;
  external function eval( arg : string ) : object;
  implementation
  const
  theurl = 'PostBase64.php';
  with HttpRequest do
  begin
  method := rmPost;
  onComplete := UploadComplete;
  RequestHeaders.Clear;
  RequestContent.Clear;
  url := theurl;
  RequestHeaders.add('Content-Type: application/x-www-
  formurlencoded');
  RequestContent.add('imagedata=' + base64 );
  RequestHeaders.add('Content-Length: ' + IntToStr( Length(
  RequestContent[0])));
  execute;
  end;
  end;
  begin
  contents := x.target.result;
  HideProgress;
  ShowProgress('Uploading File :' + fname +', '+IntToStr(
  fsize)
  + ' bytes');
  UploadFile( contents );.
  We use the readAsDataURL() method which reads the file and converts it to a Base64
  notation then calls myreader().
  Base64 is quite compact, it store 6 bytes of data in every 8 printable characters. We will
  see Base64 again in the Camera examples under Cordova.
  function TForm1.myreader( x : TArgFileReader ):integer; var
  contents : string;
  begin
  contents := x.target.result;
  HideProgress;
  ShowProgress('Uploading File :' + fname
  +', '+IntToStr( fsize) + ' bytes'); UploadFile( contents );
  result := 0;
  end;
  myreader is given the contents of the file in base64 and calls the UploadFile() function
  after informing the user of our activity.
  with HttpRequest do
  begin
  method := rmPost;
  onComplete := UploadComplete;
  RequestHeaders.Clear;
  RequestContent.Clear;
  url := theurl;
  //need to specify the content type
  RequestHeaders.add(
  'Content-Type: application/x-www-form-urlencoded');
  RequestContent.add('imagedata=' + base64 );
  RequestHeaders.add('Content-Length: '
  So it does some GUI stuff to indicate the upload worked or it didn’t. Usually servers
  discard files larger than an arbitrary size, and they may not handle this failure gracefully.
  So your app should double-check that the file was copied, and you can even make
  decisions based on the fileszie before you upload. Eg. ‘Hmmm, 33GB, no, that’s not going
  to work.’
  The disadvantage of this upload strategy is that the file must be able to be copied to
  memory, in expensive Base64 sizing.
  Before we continue, here is the PHP upload code. This is a very simple version, you will
  need to add error checking and file storage, and you can look at the MIME type which I just
  discard here. I assume I can write to the local subdirectory and write the data to junk.txt
  (Base64 encoded) and junk.png (binary). Don’t be fooled by the png extension, you can
  upload any file using this.
  PostBase64.php
  <?php
  $imageFilename = 'junk';
  $img = $_POST['imagedata'];
  file_put_contents( "$imageFilename.txt", $img );
  ?>
  $offset is the offset of the end of the header as it always ends in a comma. So we construct
  a string of the remaind of the incoming string after the comma. Our Uploader2 sample
  builds on the previous examples by cutting the file into manageable segments or chunks and
  uploading each segment. After each segment is uploaded, we can update our progressbar so
  the user knows something is happening. And by using smaller segments, we get around the
  maximum upload size limit of the PHP server. On the downside, both the client and server
  must still have enough available RAM to hold the complete file in Base64 encoding, though
  we will explain how to alleviate that server problem in the followup text..
  SEGMENTSIZE can be any number of bytes for each segment. In this example we set it
  incredibly low, at 512 bytes each just to show how it works. The TCP/HTTP setup for
  each segment eats into performance and adds to the HTTP server logs. In reality, TCP and
  HTTP/S get more efficient with larger byte sizes, so you will want to tradeoff between
  efficiency bigger sizes, and user updates which are less frequent with bigger sizes. I
  suggest setting SEGMENTSIZE to 16kB or 64kB.
  You will need to add a ProgressBar1 to your form. I suggest setting the ProgressBar’s
  Background FillColor to something other than White, maybe a dull gray.
  unit fileuploader2a;
  interface
  uses WebDom, WebHttp, WebCore, WebUI, WebForms, WebCtrls,
  WebBrwsr, WebEdits, WebBtns, WebComps,
  WebLabels, WebProgs;
  type
  TForm1 = class(TForm)
  HTMLForm1: THTMLForm;
  FileComboBox1: TFileComboBox;
  Timer1: TTimer;
  Label2: TLabel;
  Label3: TLabel;
  ProgressBar1: TProgressBar;
  Label1: TLabel;
  procedure Timer1Timer(Sender: TObject);
  private
  { Private declarations }
  segment : integer; // 0=EndOfFile, 1 is first, 2, 3, ...
  contents : string; // moved to HERE to store between;
  public
  { Public declarations }
  end;
  //
  end;
  external TFileReader = class
  public
  property onload : TArgFileReaderFn read write; procedure
  readAsText(f : TFileType); procedure readAsDataURL( f :
  TFileType );
  end;
  var
  Form1: TForm1;
  external function eval( arg : string ) : object;
  const
  SEGMENTSIZE = 512;
  implementation
  procedure TForm1.UploadComplete( sr : TServerRequest );
  begin
  if segment > 0 then begin
  inc( segment );
  UploadFile;
  end else begin
  HideProgress;
  if (sr.StatusCode <> HTTP_OK) then
  ShowMessage('Error: '+sr.ResponseContent.Text, 'Results')
  else
  ShowMessage('Done','Results');
  end;
  end;
  const
  theurl = 'PostBase64Seg.php'; // handle segments
  procedure TForm1.UploadFile;
  var
  base64 : string ; // now compute this
  len : integer;
  begin.
  result := 0; end;
  We save the Base64 text into the Form’s contents variable, initialize the segment to 1 and
  call UploadFile which now has no arguments.
  UploadFile is called repeatedly, and is the workhorse of this version.
  procedure TForm1.UploadFile;
  var
  base64 : string ; // now compute this
  len : integer;
  begin
  end;;
  UploadFile;
  end else begin
  HideProgress;
  if (sr.StatusCode <> HTTP_OK) then
  ShowMessage('Error: '+sr.ResponseContent.Text, 'Results')
  else
  ShowMessage('Done','Results');
  end; end;
  switch ( $seg ) {
  case 1 : // new file
  file_put_contents( $imageTEXT, $img ); break;
  The PHP needs more error checking and all sorts of sanity tests, but I wanted to keep the
  example simple.
  To overcome the server memory requirements, you could simply append the incoming data
  to a text file with file i/o, then run base64 –D (available on most Unix systems) to convert
  the text file to binary. See man base64 for details. The EWB progress animation prevents
  user input. If you do not use ShowProgress/HideProgress, you could put up a cancel button
  which permits users to interrupt transfers at the end of the current segment by adding a
  segment=-1 state which does not call the upload function, and which displays a ‘Cancelled’
  Uploads on many Internet connections are one fifth to one tenth the speed of downloads, so
  uploading is often annoyingly slow for users. Your users will greatly appreciate the user
  friendliness of the progress bar and a cancel button. Local file i/o is not limited to reading.
  HTML5 has a wonderful file writing function which will someday make it trivial to write
  files from JavaScript… once that function is implemented by the browser authors.
  Until that time, you have the choice of writing a hugely complex subroutine which is
  compatible with every browser by employing their multitude of strategies or enjoy the
  benefits of the filesaver.js library which has done exactly that.
  Here is an editor which lets you write/edit data and then save to a local file.
  The source code is quite simple. Note, we have to specify the MIME type of the file.
  unit firefoxsave1;
  interface
  uses WebDom, WebCore, WebUI, WebForms, WebCtrls, WebBtns,
  WebBrwsr, WebComps, WebEdits;
  type
  TForm1 = class(TForm)
  Button1: TButton;
  Script1: TScript;
  MultiLineEdit1: TMultiLineEdit;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  end.
  You will need to define a TScript to load filesaver.js. Again, production code should check
  that the script loads successfully.
  The exact outcome of using filesaver.js depends on the browser. Current versions of
  Chrome and IE and Edge display an indicator saying the file is downloaded and available
  on the bottom of the window. FireFox displays a Save/Open popup box. Safari opens the
  new text in a new browser window and it is up to the user to use File | Save.
  You can do more than text. This next project downloads an Image from the Web, uses the
  graphics routines to copy the image and place a red circle in the corner, then lets you save
  the image to a local file. It uses filesaver.js and a library named canvastoblob.js which
  takes a canvas and creates a PNG file from it suitable for saving locally. You will need
  two TScripts, one for filesaver.js and one for canvastoblob.js.
  Here I load a shopping cart image into a TImage. Then when you press ‘draw graphics’ the
  app copies the image and adds a circle.
  Press ‘save graphics’ to save the new image as a PNG file. Note, any area not drawn on by
  our circle or the source picture will be saved as transparent. If this is a problem, first
  cover the paint image with a background color.
  TForm1 = class(TForm)
  Script1: TScript;
  btSaveGraphics: TButton;
  Paint1: TPaint;
  Image1: TImage;
  Script2: TScript;
  btDrawGraphics: TButton;
  procedure btDrawGraphicsClick(Sender: TObject); procedure
  btSaveGraphicsClick(Sender: TObject);
  private
  { Private declarations }
  savefilename : string;
  procedure savefn( blob : object );
  public
  { Public declarations }
  end;
  end;
  end;
  Paint1.clientID := 'mycanvas';
  paint :=
  THTMLElement(window.document.getElementById('mycanvas'));
  context := THTMLCanvasElement( Paint ).getContext('2d');
  eval( 'context.drawImage(image, 1,1);');
  DrawCircleAt( Paint1, 25 ,25, 25 ); end;
  procedure TForm1.savefn( blob : object ); begin
  saveAs( blob, savefilename);
  end;
  procedure TForm1.btSaveGraphicsClick(Sender: TObject); var
  paint : TCanvasToBLob;
  begin
  Paint1.clientID := 'mycanvas';
  paint :=
  TCanvasToBlob(window.document.getElementById('mycanvas'));
  savefilename := 'test.png'; paint.toBlob( savefn ); end;
  end.
  If you are looking at this example to see how to copy an image into a TPaint, you will be
  confused by:
  image := THTMLElement(
  window.document.getElementById('myimage'));
  image := THTMLElement( image.childNodes[0] );
  The thing is: EWB puts the image inside a DIV, and the clientID is assigned to the DIV, not
  the IMG. So when we use getElementById we get the DIV but we want its child IMG. The
  next line extracts the first (and only) child of the DIV, which is the IMG.
  Smoothie is a scrolling chart JavaScript library. Use it to display real-time graphs of your
  data.
  Our example just plots two random numbers between 0 and 1000, using slight colorization
  to make the charts interesting. In your real-world uses you could plot any real-time data.
  For this project you will need a TTimer, a TPaint (which is really a JavaScript Canvas),
  and a TScript to load the smoothie.all.js file.
  unit smoothi1;
  interface
  uses Webdom, WebCore, WebUI, WebForms, WebCtrls, WebLabels,
  WebComps, WebPaint;
  type
  TForm1 = class(TForm)
  Label1: TLabel;
  Script1: TScript;
  Paint1: TPaint;
  Timer1: TTimer;
  procedure Timer1Timer(Sender: TObject); procedure
  Script1Load(Sender: TObject);
  private
  { Private declarations }
  smoothie : TGlobalSmoothieChart; line1, line2 :
  TGlobalTimeSeries;
  public
  { Public declarations }
  end;
  );
  procedure addTimeSeries( s : TGlobalTimeSeries; options
  : TGlobalSmoothieLineOptions );
  end;
  var
  Form1: TForm1;
  external function eval( s : string ) : object;
  implementation
  function LocalTime : integer; begin
  result := integer(now); end;
  end;
  end;
  procedure TForm1.Script1Load(Sender: TObject); var
  options : TGlobalSmoothieLineOptions;
  begin
  Paint1.clientID := 'mycanvas';
  smoothie := TGlobalSmoothieChart(
  eval('new SmoothieChart();'));
  smoothie.streamTo(window.document.getElementById(
  'mycanvas'),1000);
  // Add to SmoothieChart
  options := TGlobalSmoothieLineOptions( eval('new
  Object();')); options.strokeStyle := 'rgb( 0, 255, 0 )';
  options.fillStyle := 'rgba( 0, 255, 0, 0.4 )';
  options.lineWidth := 3;
  smoothie.addTimeSeries(line1, options );
  options.strokeStyle := 'rgb(255, 0, 255)';
  options.fillStyle := 'rgba( 255, 0, 255, 0.3 )';
  smoothie.addTimeSeries(line2, options );
  end;
  end.
  The streamTo() call takes an options delay parameter we set to 1000. This is the number of
  milliseconds to buffer before displaying data. Since we only provide new data every 1000
  ms (TTimer’s default), the output would appear jerky if we did not buffer it for a full
  second.
  For the options, JavaScript’s rgb() returns an red green blue color-space value, whereas
  rgba() returns the color-space with an opacity alpha, meaning the fill is semi-transparent.
  Google Charts is an excellent way to add an interactive graph to your program. If the user
  mouses over parts of the graph they will highlight and give various data information.
  Pie, bar and other charts are easy once you see how to use the library.
  Add a TScript which loads the library from Google. Set its onload to
  You will need a DIV with ID set to chart_div to hold the graph. Simply place a
  TBasicPanel on the form, it’s a DIV, and set its ID property with clientID := ‘chart_div’
  before you use it.
  For this example I used eval() more liberally to compute parameters for various functions.
  Data is supposed to be an array of arrays by two, where the first element is a string and the
  second is a number. We declare it as an array of array of variants, as variants are
  compatible with strings and numbers. We must use SetLength() to set the length when
  adding values.
  The code is about 100 lines, and the results are very effective.
  unit googlecharts1;
  interface
  uses WebDom, WebCore, WebUI, WebForms, WebCtrls, WebComps,
  WebCtnrs, WebLabels;
  type
  TForm1 = class(TForm)
  Script1: TScript;
  BasicPanel1: TBasicPanel;
  Label1: TLabel;
  procedure Script1Load(Sender: TObject);
  private
  { Private declarations }
  options : TGVChartOptions ;
  chart : TGChart;
  data2 : array of Tdatum;
  data : TGVis;
  procedure drawChart;
  public
  { Public declarations }
  end;
  TDatum = array of variant; TDrawProc = procedure of object;
  external TGChart = class
  public procedure draw( data : variant ; options : variant );
  end;
  end;
  end;
  end;
  external TGoogle emit google = class public
  property charts : TGCharts read write; end;
  var
  Form1: TForm1;
  external google : TGoogle;
  external function eval( s : string ) : object;
  implementation
  begin
  // Create the data table.
  data := TGvis( eval('new
  google.visualization.DataTable()'));
  data.addColumn('string', 'Topping');
  data.addColumn('number', 'Slices');
  setlength( data2, 5 );
  data2[0] := [ variant('Mushrooms'), variant(3)]; data2[1] :=
  [ variant('Onions'), variant(1)]; data2[2] := [
  variant('Olives'), variant(1)]; data2[3] := [
  variant('Zucchini'), variant(1)]; data2[4] := [
  variant('Pepperoni'), variant(2)];
  data.addRows( data2 );
  chart.draw(data, options);
  end;
  end.
  OAuth 2.0 is a protocol which allows social sharing. You can use it to find the identity of a
  user from such social networks as Google, Microsoft, Facebook, Linked In, etc. You can
  even use it to access friend lists, pictures, Google Drives, etc. Pinterest, for example, uses
  it to determine your identity and your friends so it can notify them with what strikes your
  fancy.
  Unlike protocols of yore, OAuth 2.0 does not require your userid or password. Through a
  complex handshake, it pops up a window which either asks for your credentials at the
  social host (eg. Google), or it will find cached credentials from a previous time.
  There are whole books on OAuth 2.0 and countless web sites explaining it We will use the
  popular JavaScript library called Hello.JS which does most of the heavy lifting. A key
  benefit of Hello.JS is that it makes it easy to support multiple vendor OAuth 2.0
  implementations and hides the ugly differences.
  <html><head>
  <script src='hello.all.js'></script>
  </head>
  <body>
  <button onclick="hello('google').login( function (){
  token = hello('google').getAuthResponse.access_token;
  });">Google</button>
  <script>
  var GOOGLE_CLIENT_ID =
  '5770808996983asdfasdfasdfasdfasdfasdf.apps.googleusercontent.co
  m' ;
  hello.init(
  {google : GOOGLE_CLIENT_ID },
  {redirect_uri:'redirect.html',
  scope: 'basic'}
  );
  hello.on('auth.login', function(auth) {
  });
  });
  </script></body></html>
  Note, you will need to get your own IDs from Facebook, Microsoft and Google for this
  project. See the Hello.JS documentation to learn how to do this.
  This simple program loads the Hello.JS library and adds a button which pops up an alert
  with the URL to the user’s Google thumbnail picture.
  In order to work, it also needs a redirect.html file that looks like this and is registered as
  the redirect page for your ID:
  <!DOCTYPE html>
  <html>
  <head>
  <title>Hello, redirecting...</title>
  <div
  class="loading"><span>•</span><span>•</span>
  <span>&bul l;</span></div>
  We will reuse the redirect.html file exactly as the JavaScript example did, there is no
  benefit to recoding it in EWB, and EWB is bigger and slower to load.
  How can it be both a variable and a function? To be honest, it is more complicated than
  most libraries to decipher.
  A quick perusal of the hello.all.js source file indicates that hello( network )… is an
  alias for hello.use( network )… So substituting that is our first step.
  I built a sample application which displays the user’s name and thumbnail using EWB. It’s
  a bit longer than the above JavaScript, but that’s because it does more, and it uses the
  strong Object Pascal typing.
  The source code is as follows:
  unit test;
  interface
  uses Webdom, WebCore, WebUI, WebForms, WebCtrls, WebBtns,
  WebComps, WebBrwsr, WebLabels;
  type
  TForm1 = class(TForm)
  Script1Load(Sender: TObject);
  procedure Timer1Timer(Sender: TObject);
  procedure btFaceBookClick(Sender: TObject); procedure
  btWindowsClick(Sender: TObject); private
  { Private declarations }
  inited : integer; // when set to 1, timer enables the
  buttons, then sets to 2
  public
  { Public declarations }
  end;
  end;
  end;
  TProc = procedure;
  TOnFn = procedure( auth : TAuth ); TThenFn = procedure( r :
  TLoginUser );
  // Hello.JS promise
  external TApi = class
  public
  procedure then( r : TThenFn); end;
  external TAuthResponse = class
  public
  property access_token : variant read; end;
  external THello emit hello = class
  public
  property services : array of variant read write; function
  use( vendor : string ) : THello; procedure init( args :
  TGlobHelloArgs ; arg2 :;
  myargs : TGlobHelloArgs;
  myargs2 : TGlobHelloRedirect;
  begin
  myargs := TGlobHelloArgs( eval( 'new Object()')); myargs2 :=
  TGlobHelloRedirect( eval( 'new Object();'));
  myargs.facebook := '1490242342342845';
  myargs.google :=
  myargs.google :=
  39nj9os1muja453trrp54dt50crthhv3.apps.googleusercontent.com'
  ; myargs.windows := '223423432f-07d8-234233-9940-
  0233daf9ecd6';
  myargs2.redirect_uri :=
  '';
  myargs2.scope := 'basic';
  form1.Label1.Caption := r.name;
  form1.Image1.URL := r.thumbnail;
  except
  form1.Label1.Caption := 'error reading response'; end;
  end;
  inc( inited );
  HelloEWBInit; // initialize the library btGoogle.Visible :=
  True;
  btFacebook.Visible := True; btWindows.Visible := True;
  end;
  end;
  procedure TForm1.btGoogleClick(Sender: TObject); begin
  hello.use('google').login(loginfn );
  end;
  procedure TForm1.btFaceBookClick(Sender: TObject); begin
  hello.use('facebook').login(loginfn ); end;
  procedure TForm1.btWindowsClick(Sender: TObject); begin
  hello.use('windows').login(loginfn);
  end;
  end.
  The buttons are initially set to invisible, so users do not click them before the library is
  fully initialized.
  Script1 loads hello.all.js, and calls the Script1 onload. I had it increment a variable, and
  then that variable reaches the number of libraries we need to load (one in this case), timer1
  enables the buttons. If you decide to load more libraries, repeat this step and enable the
  buttons when all the libraries have loaded. There is a slight delay because Timer1 defaults
  to one second intervals. The program is now pretty easy to read. Pressing a button calls the
  appropriate vendor’s login with loginfn, and loginfn calls the ‘me’ function with loginfn2.
  Loginfn2 updates the GUI. If case you are wondering, the reason we pass functions like
  loginfn, loginfn2 to these functions is because they are called asynchronously after the
  network calls complete.
  OAuth2 is all about sharing. Having the client believe you are a certain identity is useful,
  but often you will want to convince a server of your supposed identity. Enter the token.
  OAuth2 returns a token which can be used to verify you identity and various other attribtues
  about you.
  unit test2;
  interface
  uses Webdom, WebHttp, WebCore, WebUI, WebForms, WebCtrls,
  WebBtns, WebComps, WebBrwsr, WebLabels;
  type
  TForm1 = class(TForm)
  Script1: TScript;
  Script2Load(Sender: TObject); procedure Timer1Timer(Sender:
  TObject); procedure btFaceBookClick(Sender: TObject);
  procedure btWindowsClick(Sender: TObject);
  private
  { Private declarations }
  inited : integer;
  procedure HelloEWBInit;
  procedure RequestComplete( req : TServerRequest ); procedure
  loginfn2( r : TLoginUser );
  procedure loginfn( auth : TAuth );
  public
  { Public declarations }
  end;
  end;
  //promise
  external TApi = class
  public
  public
  property access_token : variant read;
  end;;
  implementation
  procedure TForm1.RequestComplete( req : TServerRequest );
  begin
  ShowMessage( req.ResponseContent.Text ,'results');
  HideProgress; end;
  ServerRequest := TServerRequest.Create(Self);
  with ServerRequest do begin
  method := rmGet;
  url :=
  'assure.php?token='+token+'&brand='+network+'&name='+name;
  onComplete := RequestComplete;
  execute;
  end;
  ShowProgress('Waiting for local server to verify with
  '+network );
  end;
  procedure TForm1.HelloEWBInit;
  var
  myargs : TGlobHelloArgs;
  myargs2 : TGlobHelloRedirect;
  begin
  myargs := TGlobHelloArgs( eval( 'new Object()'));
  myargs.facebook := '149024688853845';
  myargs.facebook := '149024688853845';
  39nj9os1muja453trrp54dt50crthhv3.apps.googleusercontent.com'
  ;
  myargs.windows := '24d7e37f-07d8-4703-9940-0233daf9ecd6';
  except
  Label1.Caption := 'error reading response'; end;
  end;
  procedure TForm1.loginfn( auth : TAuth );
  begin
  Label1.Caption := 'reading....';
  localnetwork := auth.network;
  localtoken :=
  hello.use(auth.network).getAuthResponse.access_token; try
  hello.use( auth.network ).api('me').then( loginfn2 ); except
  Label1.Caption := 'Your login failed.';
  end;
  end;
  inited := 3;
  HelloEWBInit;
  btGoogle.Visible := True;
  btFacebook.Visible := True; btWindows.Visible := True;
  end;
  end;
  procedure TForm1.btGoogleClick(Sender: TObject); begin
  hello.use('google').login(loginfn );
  end;
  procedure TForm1.btFaceBookClick(Sender: TObject);
  hello.use('facebook').login(loginfn ); end;
  procedure TForm1.btWindowsClick(Sender: TObject); begin
  hello.use('windows').login(loginfn);
  end;
  end.
  The major changes start where we grab the token and the network in the loginfn()
  localnetwork := auth.network;
  localtoken :=
  hello.use(auth.network).getAuthResponse.access_token;
  And when it’s done, RequestComplete() is called to cancel the progress message and
  display the message from the PHP server.
  end;
  All we need now is the PHP code and some hope that everyone implements something
  similar:
  assure.php
  <?php
  // given a token, brand, check it is genuine
  $server['facebook'] = "";
  $server['github'] = "";
  $server['google'] = "";
  $server['windows'] = "";
  {
  if ( $f = fopen("log","a")) { fwrite( $f, "$info\n"); fclose( $f );
  }
  }
  ?>
  In any case, we take what we get and log it to a log file in the same subdirectory. On unix,
  the file can be marked write-only so nobody can read it but those we intend.
  Our OAuth adventure has been fun. There are surprisingly many things you can now do
  with JavaScript, and most of them can be easily accomplished with JavaScript libraries.
  Luckily EWB can interface to most JavaScript libraries with just a little effort. And you do
  not need to wait for Elevate software to adopt your preferred JavaScript library, you can
  usually interface to it yourself.
  Most web browsers now run on multi-core CPUs, so it only makes sense that
  multithreading would make its way to JavaScript, and thus to EWB through Web Workers.
  Note: not all browsers support multithreading, and some do, but are still only co-operative
  threading based.
  The main page is the primary thread, it is the only thread that can access the GUI.
  Other threads cannot:
  There are no synchronization objects like in most other multithreaded environments;
  instead it acts much like a network-connected service: you post messages to and from the
  thread using postMessage() and receiving through onmessage().
  Each thread is loaded from a JavaScript source file. It too can spawn additional threads
  with some limitations. Read the Web Workers documentation for more details.
  Here is a very simple HTML/JavaScript web page which loads and talks to a thread, and
  can terminate the thread when needed:
  <!doctype html>
  <html>
  <head>
  <meta charset="UTF-8" />
  <title>Web Worker Example</title>
  <script type="text/javascript">
  function QueryableWorker (sURL, fDefListener, fOnError) {
  var oInstance = this, oWorker = new Worker(sURL);
  };
  this.sendQuery = function ( v ) {
  oWorker.postMessage({ "fn" : 0 , 'value' : v });
  };
  this.postMessage = function (vMsg) {
  oWorker.postMessage(vMsg);
  };
  this.terminate = function () {
  oWorker.terminate();
  };
  };
  // your custom "queryable" worker
  var oMyTask = new QueryableWorker("worker1.js");
  </script>
  </head>
  <body>
  <ul>
  <li><a id="firstLink" href="javascript:oMyTask.sendQuery( 0
  This line loads and starts running our worker1 JavaScript file. Our example will simply
  count seconds and send the second count to the main GUI every second.
  oWorker.onmessage is called whenever the thread sends us data, and we display it in the
  DIV we created with ID ‘answer’.
  Whenever we want to send a message, in this case to reset our counter, we call sendQuery
  which executes:
  oWorker.postMessage({ "fn" : 0 , 'value' : v });
  The function (fn) will be ignored in our example, but 0 is the value the second counter is
  reset to.
  We can terminate the thread at any time with oWorker.terminate().
  Now we will write the worker1.js file in EWB Object Pascal. Create a NONVISUAL
  project called worker1. The main source should look like this:
  project worker1; contains workunit;
  uses Webdom, WebCore;
  begin
  myOnMessageInit; // initialize the library
  // log something to say we are started
  console.log('started');
  TMyEvent = class
  public
  fn : string ;
  value : integer;
  end;
  TProc = procedure;
  TProcEvent = procedure( e : TEvent );
  external TConsole emit console = class public procedure log(
  msg : string ); end;
  external function eval( s : string ):object;
  var
  external console : TConsole;
  external onmessage : variant; // we will fill this with our
  own onmessage handler
  external procedure postMessage( v : variant );
  external procedure setTimeout( fn : TProc ; interval :
  integer );
  procedure doOne;
  procedure myOnMessageInit;
  procedure myOnMessage( e : TEvent );
  implementation
  procedure findPrimes; var
  i : integer;
  begin
  i := 2;
  repeat
  var
  count : integer = 0;
  procedure doOne; var
  my : TMyEvent; begin
  inc( count ); console.log('uploading ' + IntToStr( count ));
  my := TMyEvent.Create; my.value := count;
  postMessage( my );
  setTimeout(doOne, 500 ); end;
  var eventcount :integer = 0;
  procedure myOnMessage( e : TEvent );
  var
  my : TMyEvent;
  declares the TEvent passed by the Web Workers library. All we care about is the data
  property.
  We will cast the TEvent.data to class
  end;
  It is TMyEvent which the two threads will pass back and forth. Fn refers to a function
  name, so that they can specify different functions if you want. We won’t use fn in this
  example, but it’s handy for more complex ones.
  The myOnMessage procedure takes these incoming events and processes them. So if the
  other side said the new value should be 100, we will blindly set our counter to that value.
  We also log to the console, because otherwise debugging is terrible difficult with threads.
  The doOne procedure increments our lucky counter, logs it to the console and posts the
  updated counter to the main thread. It also schedules itself to run again in 500 milliseconds.
  end;
  The lines:
  if False then
  myOnMessage( nil ); // links it in but never executes
  never actually run myOnMessage, but by writing this condition we tell the linker to copy
  the myOnMessage() function into the output JavaScript. Otherwise the linker optimization
  will skip it because it is not otherwise referenced by anything.
  creates that global variable and sets it to our function. Note that the function name is
  workunit_myonmessage(), which EWB creates because this unit name is workunit and the
  function within the unit is myonmessage (no capitalization).
  Compile your code and make one last critical change, edit the resulting worker1.js into an
  editor and add the last line:
  worker1_load();
  Now load the master web page (main.html) and be amazed. The counter will increment
  frequently, and you can reset the counter or kill the counter by clicking on the labels.
  Consider the implications of what you have just seen. It is possible to write a program in
  EWB Object Pascal and teach any JavaScript application to load and exchange data with
  that program in real-time, let alone with multithreading with only a few additional lines of
  JavaScript.
  EWB is preferable to JavaScript for many of these threading situations because the
  compiler should find most of your mistakes and you will spend less time debugging.
  Create a Visual EWB project, we’ll call it mainewb, and a main form in a unit called
  workmain.
  unit workmain;
  interface
  uses WebDom, WebCore, WebUI, WebForms, WebCtrls, WebBtns,
  WebLabels;
  type
  TForm1 = class(TForm)
  btReset: TButton;
  btTerminate: TButton;
  Label1: TLabel;
  procedure Form1Show(Sender: TObject); procedure
  btTerminateClick(Sender: TObject); procedure
  btResetClick(Sender: TObject);
  private
  { Private declarations } worker : TQueryableWorker;
  public
  { Public declarations }
  end;
  oInstance : variant;
  procedure init;
  procedure onMessageHandler( msg : TEvent ); procedure
  postMessage( msg : TMyEvent ); procedure terminate;
  end;
  var
  Form1: TForm1; external function eval( s : string ):object;
  implementation
  procedure TQueryableWorker.onMessageHandler( msg : TEvent );
  begin
  Form1.Label1.Caption := IntToStr(msg.data.value); end;
  procedure TQueryableWorker.init;
  begin
  oWorker := TWorker( eval('new Worker("worker1.js");'));
  oWorker.onmessage := onMessageHandler;
  end;
  begin
  my := TMyEvent.Create;
  my.fn := 'whatever';
  my.value := 0;
  worker.postmessage( my ); my.Free;
  end;
  end.
  The only confusing things are that onMessageHandler() receives a TEvent which it must
  convert into a TMyEvent, and the capitalization of onmessage is different from the
  capitalization of postMessage… it’s just not consistent.
  A very real use of threads is when you need to do scientific calculations or Internet
  communications and want to offload them to other CPU cores to leave your GUI fast and
  responsive. Again, not all browsers will do that, and some users still have single-core
  machines out there. But the option exists for you to use, and as it is a standard, it is
  becoming quite common. Check the web for latest compatibility news of Web Workers.
  And EWB’s Object Pascal is perfect for doing complex calculations.
  It is possible to write applications that will run natively on cell phones, tablets, set-top TV
  boxes and other devices using EWB. Unike mere web pages, these applications will have
  access to the built-in compass, GPS, gyrometer, camera, local file storage, etc.
  What is spectacular is that native PhoneGap/Codova modules are available which can do
  all sorts of things as add-in libraries. They are written in the language native to the device,
  and they present a JavaScript-callable interface. As we saw earlier, if it’s accessible to
  JavaScript: you can probably access it from EWB.
  You have choices about how you convert these web pages into mobile apps: you can
  download the free Cordova toolkit, and android toolkit, and Java toolkit, and IOS toolkit
  (in which case you better be on a Mac), etc. Or you can spend $9.99 on an Adobe
  PhoneGapBuild monthly subscription where they do all the work maintaining the libraries.
  I’ve done it both ways in the past, using the PhoneGapBuild when I was lazy, and local
  verions when I was cheap.
  If you decide to do it locally, installation takes about an hour of downloading with a good
  network connection. I won’t copy the instructions here because they seem to change every
  month. Refer to the web for details. You’re probably wondering why I am discussing
  distribution before even writing the app. Well, to test and share an Apple IOS app, you
  have to get digital signatures from Apple. And everyone who tests your app has to have
  their device entered into a list you maintain, up to 100 test users per app, no more. It’s all
  quite complicated.
  Testing Android apps is much easier. You will just generate an APK file, which is really
  just a ZIP file, with a certain layout. Any android device can test it by downloading your
  app from a web page.
  mkdir cordova
  cd cordova
  cordova create hello
  cd hello
  cordova platform add android cordova platform add camera
  Copy in your HTML and JavaScript files to the www subdirectory that you find.
  cordova build android
  You can copy almost any EWB project to the index.html its associated JavaScript file. In
  fact, you can have an EWB project named: HappyDancer.html and HappyDancer.js. Just
  rename the HTML file to index.html and keep HappyDancer.js, and it will work.
  The project uses config.xml in the www subdirectory – cordova create hello put
  it there. By default, the project uses the default icon. You can edit it and add your own
  icons, etc. You really should edit the author field too. Read the whole file, but I recommend
  keeping a backup in case you accidentally mess up the fields.
  For our examples we will leave the config.xml file in its default state.
  As we just discussed, you can place any html5/JavaScript code in index.* and it will make
  an installable application. But what is really cool is that you can do more: you can access
  hardware and software services on the device using Cordova/PhoneGap extensions.
  Accessing those libraries and services is the challenge we shall solve.
  Our first example will be a Camera will be able to take pictures and display them in an
  TImage. You could also extend the program to upload images, keep inventory records, etc.
  unit camera1;
  interface
  uses WebDom, WebCore, WebUI, WebForms, WebCtrls, WebComps,
  WebBtns, WebBrwsr, WebSizer,
  WebCtnrs;
  type
  TForm1 = class(TForm)
  Script1: TScript;
  Button1: TButton;
  ScrollPanel1: TScrollPanel;
  Image1: TImage;
  procedure Script1Error(Sender: TObject);
  procedure Form1Create(Sender: TObject);
  procedure Button1Click(Sender: TObject);
  procedure Image1Load(Sender: TObject);
  private
  { Private declarations }
  procedure onDeviceReady;
  procedure onCameraSuccess( s : string ); procedure
  onCameraFail( s : string );
  public
  { Public declarations }
  end;
  end;
  external TNavigator2 = class (TNavigator) public property
  camera : TCamera read write;;
  end.
  You will need TScrollBox set with both scrollbars enabled, and its Layout set to cover the
  form. Also you need a TScript we will explain in a second, a Button1 set to Visible:=
  False and its caption set to ‘Take Photo’. And we need a TImage to hold the picture.
  First, onCreate is called. It registers a callback which occurs sometime later when
  PhoneGap is loaded and ready.
  TCordovaDocument(window.document).addEventListener(
  'deviceready', onDeviceReady, false); Width :=
  window.Screen.Width;
  Height := window.Screen.Height;
  Then we have a TScript (not shown) which loads the URL cordova.js from the local
  directory. Which cordova.js, there is none? At compile time, the Cordova system will
  automatically place the correct JavaScript for this target OS in the local target
  subdirectory.
  Cordova fires an event called deviceready when it’s up and ready to do things. And
  remember, we scheduled onDeviceReady to be called in onCreate. So it get’s called.
  As you can see, it enables the user button to take a photo. Until now we had the button’s
  Visible set to false so that they couldn’t take a picture before the system was ready.
  Options is a class of options. We create the class (see chapter on JavaScript if it looks
  strange). Then we call what JavaScript knows as
  window.Navigator.camera.getPicture(). PhoneGap/Cordova has added a camera.getPicture
  to the Navigator object. EWB is much more sensible than JavaScript-do-whatever-you-
  want, so we must cast window.Navigator to a class we defined as Navigator2 above, and
  TCamera
  and
  external TCamera = class
  public property
  end;
  If the picture is taken, onCameraSuccess is called, and it copies the data url to the TImage
  url property.
  procedure TForm1.onCameraSuccess( s : string ); begin
  Image1.url := s;
  end;
  Finally, when the image loads, we tell the system to expand the TImage to the size of the
  Photograph by making space inside the TScrollPanel.
  This creates a HelloWorld.app which can run under OS/X. Unfortunately, it does not
  appear to support the camera, but at least it does not give errors. The screen looks like this
  In all honesty, EWB added very little to this partiular project. It would have been faster to
  code it in JavaScript. But where EWBl pays off is when you construct something more
  heavy-duty, because that’s where EWB shines.
  But first, let’s make this example more exciting. What good is taking an image until you can
  upload it.
  This example extends the previous one. It takes a picture then lets you upload the file if you
  wish by pressing the Upload Button2.
  Base64 encoding
  • We use TServerRequest to upload the data with a POST
  This builds on previous examples from other chapters.
  What is not done in any previous chapters is that we set the host name of the URL. This
  would break CORS on web pages, but it’s perfectly safe on an application.
  unit camera1;
  interface
  uses WebDom, WebHTTP, WebCore, WebUI, WebForms, WebCtrls,
  WebComps, WebBtns, WebBrwsr, WebSizer,
  WebCtnrs, WebPaint;
  type
  TForm1 = class(TForm)
  Script1: TScript;
  Button1: TButton;
  ScrollPanel1: TScrollPanel;
  Image1: TImage;
  Button2: TButton;
  Script2: TScript;
  Paint1: TPaint;
  procedure Script1Error(Sender: TObject); procedure
  Form1Create(Sender: TObject); procedure Button1Click(Sender:
  TObject); procedure Image1Load(Sender: TObject); procedure
  Button2Click(Sender: TObject);
  private
  { Private declarations }
  strimg : string;
  HttpImageRequest : TServerRequest; procedure onDeviceReady;
  procedure onCameraSuccess( s : string ); procedure
  onCameraFail( s : string ); procedure UploadPicture;
  procedure CopyPictureToImage;;
  procedure TForm1.UploadComplete( sr : TServerRequest );
  begin
  if (sr.StatusCode <> HTTP_OK) then
  const
  host = ''; theurl =
  '/PostBase64PNG.php';
  image := THTMLElement(
  window.document.getElementById('myimage')); image :=
  THTMLElement( image.childNodes[0] );
  Paint1.clientID := 'mycanvas';
  paint := THTMLElement(
  window.document.getElementById('mycanvas')); context :=
  THTMLCanvasElement( Paint ).getContext('2d'); eval(
  'context.drawImage(image, 1,1);');
  end;
  procedure TForm1.UploadPicture;
  var
  s : string;
  begin
  // similar to the filesave example earlier in the book
  CopyPictureToImage;
  // s will be a Base64 version of the image
  s := Paint1.Canvas.ConvertToDataUrl( 'image/png', 100 );
  UploadPicture2( s );
  end;
  with HttpImageRequest do
  begin
  method := rmPost;
  onComplete := UploadComplete;
  RequestHeaders.Clear;
  RequestContent.Clear;
  'Content-Type: application/x-www-form-urlencoded');
  RequestContent.add('imagedata=' + blob );
  RequestHeaders.add('Content-Length: ' +
  end;
  procedure TForm1.Button2Click(Sender: TObject); begin
  UploadPicture;
  end;
  end.
  Of course you will need a script on the server to accept the uploaded image.
  PostBase64PNG.php
  <?php
  $imageFilename = 'junk';
  $img = $_POST['imagedata'];
  file_put_contents( "$imageFilename.txt", $img );
  This upload PHP script tries to save the file in the local subdirectory, you will want to
  change that and also add code to ensure you trust this user to upload. The Map and GPS
  example will create a working GPS system. It will get updates from the GPS every few
  seconds and display our changing position on a Google Map. Elevate software has taken
  the hassle out of Google Maps, and so this program is surprisingly short for what it
  accomplishes.
  unit geo1;
  interface
  uses Webdom, WebCore, WebUI, WebForms, WebCtrls, WebBtns,
  WebLabels, WebMaps, WebComps;
  type
  TFormGeo = class(TForm)
  Button1: TButton;
  Label1: TLabel;
  Label2: TLabel;
  Map1: TMap;
  Button2: TButton;
  Script1: TScript;
  Label3: TLabel;
  procedure Button1Click(Sender: TObject); procedure
  Button2Click(Sender: TObject); procedure
  Script1Error(Sender: TObject); procedure
  FormGeoCreate(Sender: TObject);
  private
  locallocation : integer;
  watch : string;
  procedure onSuccess( res : TGeoResults ); public procedure
  onError( error : TGeoError ); procedure onDeviceReady;
  end;
  // which options can we supply to GPS?
  external TGeoOptions = class
  public
  end;
  onGeoSuccess : TGeoSuccessFn ;
  onGeoError : TGeoErrorFn;
  options : TGeoOptions ):string;
  var
  FormGeo: TFormGeo;
  external function eval( s : string ):object;
  implementation
  procedure TFormGeo.Script1Error(Sender: TObject); begin
  ShowMessage('cordova did not load','ERROR'); end;
  procedure TFormGeo.onDeviceReady; begin
  Button1.Visible := True;
  end;;
  begin
  options := TGeoOptions( eval('new Object();')); options.
  maximumAge := 3000;
  options.timeout := 5000;
  options.enableHighAccuracy := true;
  watch :=
  TGeoNavigator(window.navigator).geolocation.watchPosition(
  onSuccess, onError , options );
  Button1.Enabled := False; Button2.Enabled := True; end;
  procedure TFormGeo.Button2Click(Sender: TObject); begin
  if watch <> '' then begin
  TGeoNavigator(window.navigator).geolocation.clearWatch(
  watch );
  watch := '';
  Button2.Enabled := False;
  Button1.Enabled := True;
  end;
  end;
  end.
  The OnCreate event is almost identical to our last project, so it doesn’t need a explanation
  except to say it disables the Disable GPS button.
  When we get the deviceready, we enable the Start GPS button. So far so simple.
  When the user clicks Button1, we prepare to call watchPosition() with two event handlers
  and some options. This function tells the GPS to upcall our event handlers when changes
  happen to the GPS position, or errors results such as when we are out of range of the
  satellites. It will update the location usually every 3000 ms, or timeout after 5000ms of no
  position recording.
  Options.enableHighAccuracy means to use the GPS and not the cell towers location.
  Higher accuracy results from this decision, but it also drains the batteries more quickly.
  begin
  options := TGeoOptions( eval('new Object();')); options.
  maximumAge := 3000;
  options.timeout := 5000;
  options.enableHighAccuracy := true;
  watch :=
  TGeoNavigator(window.navigator).geolocation.watchPosition(
  onSuccess, onError , options );
  Button1.Enabled := False; Button2.Enabled := True; end;
  The watchPosition returns a string token which we will use again when we want to turn off
  the GPS.
  procedure TFormGeo.Button2Click(Sender: TObject); begin
  if watch <> '' then begin
  TGeoNavigator(window.navigator).geolocation.clearWatch(
  watch );
  watch := '';
  Button2.Enabled := False;
  Button1.Enabled := True;
  end;
  end;
  And an important part of this project is the onSuccess handler called by the GPS system:;
  It displays the latitude and longitude and adds a marker to the map. Markers are an indexed
  array, so we need to inc( locallocation) to record the next location to a new marker.
  You could use an upcall to Google services to convert the GPS coordinates to an
  approximate street location. My experience is that it’s usually accurate to the street name
  and approximate house, but not necessarily the exact house.
  Note that Google starts charging for or blocking access to location awareness nformation
  when you use it too much. So be careful to limit requests to a reasonable number per day
  where reasonable is defined by Google.
  Look at the Apache Cordova web site and you will find extensions that do all sorts of
  things. They can make your program
  run in the background
  accept asynchronous notifications like facebook does
  access files
  access an SQL-lite based database system
  and much more
  All the libraries use the same sort of calls as we did in our two examples, so there is no
  excuse for not persuing these options.
  The next steps are generally to register for Android, IOS and other developer keys and
  signatures. This will cost some money but it is the frustration with endless web pages
  which will probably be the hardest part. Also, Apple is picky about what it will allow on
  its store, you need to meet their user interface guidelines and various other criteria.
  Not every developer will feel a need to make a mobile app, but with EWB it is relatively
  easy to accomplish, and definitely no harder than competing environments.
  even more)
  • ability to use Microsoft embedded / IIS server
  • connectivity to every major brand of SQL server and NOSQL server
  Personal Aside
  It was while researching my unfinished Mormot book that I got sidetracked by discovering
  EWB, eventually leading me to write this book. My first Mormot book will likely be my
  This short chapter will not introduce Mormot in detail. It’s an environment much more
  complex than EWB. But we will create three examples which work with programs that
  ship as Mormot’s own server samples.
  Mormot can be used as an Object Relational Mapping or ORM, which means you do not
  have to write a line of SQL, and using it this way offers some benefits. But if you want to
  write SQL, that’s fine too, you just bypass the ORM layer.
  The following chapter describes my EWBMormot interface library and applications that
  use it.
  The first step in your EWB web page unit is to include both EWBmormot and WebHTTP.
  Then there are two important classes for all Mormot EWB applications:
  TMormotConnection class which communicates with the Database/Web server
  TMormotTable class from which classes you create will descend.
  In all Momot applications on all platforms you utilize a class that knows how to
  communicate with the database/web server: TMormotConnection, somewhat akin to the
  TDatabase of EWB.
  Also, you define data objects as classes that descend from an ancestor Mormotrelated class
  which knows how to express them to the aforementioned connection class.
  For our first two examples, we will use the Project 18 database server that comes with
  Mormot. Project18 is a password-free database that lets you create, read, update and
  delete Fish names.
  In all EWBMormot applications you start by defining the class that describes the database
  object you will connect to.
  In our case, it’s TFish that describes Fish.
  Noticed that it descends from TMormotTable rather than TPersistent. Otherwise it should
  be quite familiar.
  Next, in our form we define instances of the Web/Database and a Fish.
  private
  { Private declarations } fish : TFish;
  mormot : TMormotConnection;
  unit sample2a;
  // Demonstrates typical Mormot style of CRUD on tables
  interface
  TForm1 = class(TForm)
  MultiLineEdit1: TMultiLineEdit;
  procedure Form1Show(Sender: TObject);
  private
  { Private declarations } fish : TFish;
  mormot : TMormotConnection;
  procedure PostAddFish( sr : TServerRequest;
  method : TRequestMethod ;
  statuscode : integer; rh : TStrings; Response : TStrings );
  var
  Form1: TForm1;
  implementation
  //
  MultiLineEdit1.Lines.Add('Fish ['+ IntToStr(Fish.ID)+'] = '
  + Fish.Name );
  end;
  procedure TForm1.Form1Show(Sender: TObject);
  begin
  //
  mormot := TMormotConnection.Create;
  Mormot.InitServer(
  '',
  self);
  fish := TFish.Create; fish.Name := 'Bobby';
  MultiLineEdit1.Lines.Add('Default ID for fish is ' +
  IntToStr( fish.Id ));
  Our next example merges Mormot with TDataSet, so you can use EWB DataSet-enabled
  controls with Mormot-proven database backends.
  Specifically, we will use TGrid to display a number of fish in a master-detail view, with
  TEdits and other controls showing the details.
  For this example we need a screen layout that looks like this:
  It also has a invisible TDataSet1 which is connected to the edit boxes, the date box, and the
  TGrid.
  I used Layout to make the TGrid shrink or swell to the size of available space. You can
  learn more about that in our chapter on Responsive Design. The other controls were not
  made responsive in this simple example.
  Instead of Get, we call GetAllData, which downloads the data into our DataSet1 and it
  flows beautifully into our table.
  But to get it into the dataset, we have to implement a very short OnPopulate helper:
  Much of the rest of the code couldn’t be simpler. For example, when a user pressed
  btDelete, our code reads the ID number from the TDataSet cursor and deletes it.
  The Create and Update functions are both wrapped into the Save button. First, pressing
  Create or Update will set a flag to indicate if we are creating new or updating existing
  data, that flag is stored in the insert Boolean.
  fish.LoadFromDataset( DataSet1 );
  if mormot.Inserting then
  Mormot.Post(fish )
  else
  end
  fish.LoadFromDataSet(..) loads the TFish structure with the values in the current dataset.
  If it’s new, we Post( fish), which is the RESTful way to send a new object, otherwise we
  Put( fish , and it’s ID ) to update the existing object.
  The entire program is about 120 lines, including 65 lines of Interface.
  unit sample1a;
  interface
  uses WebHTTP, WebCore, WebUI, WebForms, WebCtrls, WebCtnrs,
  WebGrids, WebLabels, WebData,
  WebBtns, WebEdits, ewbmormot;
  type
  TForm1 = class(TForm)
  BasicPanel1: TBasicPanel; BasicPanel2: TBasicPanel; Label1:
  TLabel;
  Grid1: TGrid;
  DataSet1: TDataSet;
  GridColumn1: TGridColumn; GridColumn2: TGridColumn;
  GridColumn3: TGridColumn; GridColumn4: TGridColumn; Label2:
  TLabel;
  Label3: TLabel;
  Label4: TLabel;
  Edit1: TEdit;
  DateEditComboBox1: TDateEditComboBox; Edit2: TEdit;
  btCreate: TButton;
  btUpdate: TButton;
  btDelete: TButton;
  btRefresh: TButton;
  Label5: TLabel;
  btSave: TButton;
  Label6: TLabel;
  procedure DataSet1Show(Sender: TObject); procedure
  btCreateClick(Sender: TObject); procedure
  btUpdateClick(Sender: TObject); procedure
  btDeleteClick(Sender: TObject); procedure
  btRefreshClick(Sender: TObject); procedure
  btSaveClick(Sender: TObject);
  private
  { Private declarations }
  fish : TFish;
  mormot : TMormotConnection;
  public
  { Public declarations }
  procedure OnPopulate( s : string );
  end;
  var
  Form1: TForm1;
  fish := TFish.Create;
  mormot := TMormotConnection.Create;
  Mormot.InitServer(
  '', self);
  Mormot.Populate := OnPopulate;
  Mormot.GetAllData( fish );
  end;
  fish.LoadFromDataset( DataSet1 );
  if mormot.Inserting then
  Mormot.Post(fish )
  else
  end;
  end.
  The two preceding examples demonstrate Mormot Server’s REST API. Mormot also
  supports interfaces for remote procedure calls (RPC). With the RPC you can send data to
  the server, implement any server functionality, and return results that may but need not be
  database results.
  RPCs are great for implementing business logic, so the logic is defined and carefully
  controlled by the server and not the possibly hacked web client.
  For our simple example we define an RPC that just adds two numbers and wish to execute
  it on the server for the client. The client gets an upcall when the results are done, and it
  displays the results graphically.
  Mormot’s own example 14 includes a server which does exactly that. It accepts two
  numbers, parameters: num1 and num2, and adds them to return a result.
  However, unlike the previous examples, it requires a login – which is probably more akin
  to what you will encounter in a typical non-public database. All your production code
  should use HTTPS rather than HTTP. But is that enough to make you safe? Certainly not.
  HTTPS traffic is not immune to manin-the-middle (MITM) attacks. In fact, even a typical
  user can press F12 on most browsers to see your passwords in clear text.
  In addition to HTTPS, Mormot uses an excellent api where the client and server verify
  who each other is, thereby preventing a man-in-the-middle attack by: never transmitting a
  clear-text password, keeping it a secret
  always putting a timestamp on requests to prevent attacker replays
  digitally signing every message from client to server
  So the client and the server keep a hash of the shared password, but they never
  communicate it to each other. Instead, the server presents a challenge to the client saying
  “use this challenge number in a mathematical formula with the secret hash”, to which there
  is exactly one answer in 4 billion random attempts. The client can easily solve the problem
  if he knows the hash, but can only guess if he does not. If the client just guesses, the server
  knows and can take action to thwart further hacking attempts.
  Our interface library does all that work for you. You just supply the userid/password pair
  with a call to Authenticate.
  For this sample program we have two edit boxes for the two numbers to add, two more
  edits for the userid and password, two buttons (login and calculate) and a few labels for
  the + plus sign and the answer. We also need a TScript pointing to the sha256.js JavaScript
  because at the time of writing I have not yet converted sha256.js to EWB.
  The whole EWB program is here:
  unit sample3a;
  interface
  uses WebHTTP, EwbMormot, WebCore, WebUI, WebForms, WebCtrls,
  WebEdits, WebLabels, WebBtns,
  WebComps;
  type
  TForm1 = class(TForm)
  Edit1: TEdit;
  Label1: TLabel;
  Edit2: TEdit;
  Label2: TLabel;
  Button1: TButton;
  edUserName: TEdit;
  edPassword: TEdit;
  Button2: TButton;
  Script1: TScript;
  procedure Button1Click(Sender: TObject);
  procedure Button2Click(Sender: TObject);
  procedure Form1Show(Sender: TObject);
  private
  { Private declarations }
  mormot : TMormotConnection; contract : string;
  procedure sum( num1, num2 : string ; proc : TFnOnSum );
  procedure OnSum( s : string );
  public
  { Public declarations }
  end;
  published
  property n1 : integer read fn1 write fn1; property n2 :
  integer read fn2 write fn2;
  end;
  s : string;
  i, j : integer;
  begin
  if statuscode < 300 then begin
  s := Response.Text; // eg. {result: [5]}
  i := Pos('[',s ); // find first
  j := Pos(']',s, -1 ); // search backwards from end s :=
  Copy( s, i+1, j-i-1 );
  s := '';
  mormot.PostOp := PostSumOp;
  mormot.RawPost( s, sum1, '') ; // or call RawPost(s, Nil, '[
  '+num1+', '+num2+']' );
  sum1.Free;
  end;
  begin
  mormot := TMormotConnection.Create;
  Mormot.InitServer(
  '',
  self);
  mormot.OnLogin := OnMyLogin;
  mormot.Authenticate( hostport , edUserName.Text,
  edPassword.Text );
  end;
  procedure TForm1.Form1Show(Sender: TObject);
  begin
  end.
  The first step is Form1Show which disables the Calculate button until the user is logged
  into the system.
  Button1.Enabled := False; // disable Calculate button until
  logged in
  Ensure your application always makes it clear that a user must login before accessing the
  server.
  Button2 is the login button.
  var
  hostport : string = '';
  begin
  mormot := TMormotConnection.Create;
  Mormot.InitServer(
  '', self);
  mormot.OnLogin := OnMyLogin;
  mormot.Authenticate( hostport , edUserName.Text,
  edPassword.Text );
  end;
  The login button sets an OnLogin pointer to our OnMyLogin function to change the user
  interface when we are logged in. Then it stores and processes the login
  connection/userid/password.
  Within a fraction of a second Mormot will reply and, if your password is correct, you will
  get an upcall to OnMyLogin.
  In addition to showing the user we are logged in, and re-enabling the Calculate button, it
  calls sum_contract to verify the sum procedure works. Mormot replies with a contract
  number. On a more advanced implementation, this would do something clever, but ours just
  discards this contract number.
  Now the user is free to enter two numbers and press Button1 which is the calculate button.
  procedure TForm1.Button1Click(Sender: TObject); var
  num1, num2 : string;
  begin
  num1 := Edit1.Text; num2 := Edit2.Text;
  Label2.Caption := ' = calculating...';
  sum( num1, num2, OnSum ); end;
  Button1Click converts the text entries into number and calls sum() which is a local function
  call… but it calls a remote function call to do the work.
  s := '';
  mormot.PostOp := PostSumOp;
  mormot.RawPost( s, sum1, '') ; // or call RawPost(s, Nil, '[
  '+num1+', '+num2+']' );
  sum1.Free;
  end;
  There are a variety of ways you can transfer the numbers to the sum() RPC. The easiest is
  what we’ve shown, to declare a structure and populate it with the parameters needed. In
  our case, the reference document said the two parameters are num1 and num2. If you use
  names, as we have, you do not need to worry about ordering.
  PostSumOp is called by both the contract setup sequence and by the sum() function. But we
  know the difference between the two because at contract time the contract number is ‘’,
  whereas at sum() time it will have already been set by our previous call.
  s : string;
  i, j : integer;
  if statuscode < 300 then begin
  PostSumOp is passed something a 200 series result code and a string like { result : [ 5] }.
  Rather than make a complicated result parsing system, I just remove the
  surrounding [ ]’s and process the middle text.
  If this is our first call, we know it’s a contract number (which we just note but do nothing),
  and on subsequent results we know we have the result of the remote Sum() function, so we
  update the label saying the resut.
  If the StatusCode is 300 or higher, there is an error of some sort, so we display it.
  There are a large number of samples that ship with Mormot, and with the three examples
  given here demonstrate four important components of Mormot development:
  This is my fourth book and it was a pleasure to research and write. I think I’m getting better
  with each book, but that’s just my take. I know the project has taught me a lot. And I find the
  experience very intimate with the reader, trying to anticipate your questions all while trying
  to remain short and concise.
  I learned long ago that elegance means beautifully simple, though in English we often
  confuse it with ornate which is actually the opposite. The simpler your code is, the less
  likely it is to confuse you and contain errors. My code is usually simple, and I also try to
  exend that to my writing style; you are the judge of whether that has been successful.
  Your feedback will help make the book better. If there was something I glossed over or
  missed entirely or maybe got wrong, please do let me know so I can improve the
  experience for future readers.
  One of the benefits of modern publishing is small batches and on-demand printing, so we
  can make new revisions without a large write-off of inventory. For the consumer this means
  authors are encouraged to update their material.
  I also offer consulting services if you have a difficult problem and need assistance.
  Finally, I wish you the best of luck with your future EWB projects. Maybe our paths will
  cross again.
  Erick Engelke
  erickengelke@gmail.com
  Alpha Arc
  ArcTo
  asSineEaseIn
  asSineEaseInOut asSineEaseOut asSineEaseOutIn
  asBackEaseIn
  asBackEaseInOut asBackEaseOut
  asBackEaseOutInIn
  asElasticEaseIn
  asQuartEaseInOut asQuartEaseOut
  asQuartEaseOutIn asQuintEaseIn
  asQuintEaseInOut asQuintEaseOut
  asQuintEaseOutIn
  BeginPath
  BezierCurveTo
  ClearRect
  Clip
  ClosePath
  CompositeOperation
  ConvertToDataURL FillColor
  FillGradient FillPattern
  FillStyle
  LineCapStyle LineJoinStyle
  LineWidth
  ShadowBlur
  ShadowColor ShadowOffsetX ShadowOffsetY
  M iterLimit
  TextAlign
  TextBaseLine