Extending InternetExpress with Custom Components

By: John Kaster

Abstract: Nick Hodges explains how to enhance InternetExpress, complete with source code. This is an excerpt from his BorCon 2000 presentation

Internet Express adds a whole new dimension to Delphi's Internet development capabilities. By allowing you to hook data to HTML controls, you can easily build powerful, database-driven web pages. InternetExpress includes a large collection of classes to accomplish this, but the base component for all of it is the TMidasPageProducer.

You can download the source code for this article from CodeCentral.

TMidasPageProducer

TMidasPageProducer is the heart of InternetExpress, and all InternetExpress components are embedded within it. It is the component used to manage all the custom HTML that InternetExpress components emit. To fully take advantage of InternetExpress, you will want to create a TMidasPageProducer to set up the basic template for each page on your site. This means, of course, inheriting from TMidasPageProducer. Once you have done that, you can use that template for any or all the pages in your new site, giving it a consistent look throughout. In addition, understanding how TMidasPageProducer works is key to understanding how to build components that fit into it. This article will build a TMidasPageProducer descendent that will automatically insert <META> tags into the <HEAD> tag of your HTML document.

Descending from TMidasPageProducer

TMidasPageProducer descends from WebBroker's TPageProducer, with a couple of classes (TComponentPageProducer and TPageItemsProducer) in between. TMidasPageProducer handles the task of organizing and outputting the HTML produced by the various classes and components installed within it. It also does a lot of the work of managing the XML that it receives from the XMLBroker and allows you to process that XML data if you like before it gets sent out to the components. In addition, it manages all the Javascript that any of the InternetExpress components might use, allowing you to concentrate on the code and not the HTML.

Note: TMidasPageProducer will function just like a regular TPageProducer, so you can adjust the HTMLDoc property and use the OnHTMLTag just as always. It is likely that you won't want to do that, but you can.

GetDefaultTemplate is a key function in TMidasPageProducer. It gets the basic HTML code and pre-defined imbedded custom tags that let TMidasPageProducer provide it's content. It is implemented as follows:

Listing 1


function TCustomMidasPageProducer.GetDefaultTemplate: string;
begin
  Result := Format('<HTML>'#13#10 +
             '<HEAD>'#13#10 +
             '</HEAD>'#13#10 +
             '<BODY>'#13#10 +
             '<#%0:s><#%1:s><#%2:s><#%3:s><#%4:s>'#13#10 +
             '</BODY>'#13#10 +
             '</HTML>'#13#10, [sIncludesTag, sStylesTag,
               sWarningsTag, sFormsTag, sScriptTag]);
end;

GetDefaultTemplate produces a string using the Format function. It uses the constants in the array of constants to build a skeleton HTML document the body of which is filled with nothing but custom tags. Each of the custom tags represents the different portions of the resulting HTML document. Drop a TMidasPageProducer on a form, and look at the HTMLDoc property, and you will see the results:

Listing 2


<HTML>
<HEAD>
</HEAD>
<BODY>
<#INCLUDES><#STYLES><#WARNINGS><#FORMS><#SCRIPT>
</BODY>
</HTML>

The <#INCLUDES> tag is where any references to included files will be added. The <#STYLES> tag will be filled with style information. The <#WARNINGS> tag is actually used only at design-time to send messages to the programmer about errors in the linkages of the various components within the TMidasPageProducer. <#FORMS> will be replaced with the main part of the document and contain all the HTML that will be seen by the user. Finally, <#SCRIPT> is where all the Javascript produced by the components will be placed.

The GetDefaultTemplate method is virtual, so as you will see, you can change the above default template code, and add anything you like, including additional custom tags and HTML. However, you should include all the tags seen above. There's nothing stopping you from adding additional tags, but you shouldn't take any of them away.

TMidasPageProducer uses a helper class, TMidasPageElements, to handle the replacement of the default custom tags seen above. You can, and likely will, descend from this to provide your own custom handling of these tags. You can tell your TMidasPageProducer about your new TMidasPageElements descendent with the CreatePageElements method, and it will use the new class to provide HTML. You can add fields to the new class as well, thus handling any custom tags that you added to the default HTML template in GetDefaultTemplate.

TMidasPageElements has one method, BodyContent, which produces the HTML for the class. You can override this method and produce your own content.

TMetaMidasPageProducer

Many search engines make use of the HTML feature <META> tags. Meta tags provide information about the site including the author, the name of the site, and the type of content in site among other things. It is generally a good idea to add <META> tags to your site, and TMetaMidasPageProducer makes that easy.

TMetaMidasPageProducer adds properties that you can fill in to automatically insert <META> tags into your HTML documents. It does this by first declaring a class, TMetaTags, which holds all the information you can add to your page. TMetaTags knows how to produce the HTML that the TMetaMidasPageProducer needs. As a published property of the TMetaMidasPageProducer, it shows up in the Object Inspector where you can change the properties as you like.

Note: TMetaTags descends from TPersistent, and it is thus streamable. However, in order to get it to work properly in the Object Inspector, it needs its own property editor, which is included with the code for this article. In addition, you can add other string properties to the class if you like. Simply name them the same as the tag name you want added, and they will automatically be included in the code. TMetaTags uses RTTI to find all the string properties and turn them into <META> tags.

The TMetaTags class is declared as follows:


type
  TMetaTags = class(TPersistent)
  private
    FIdentifier: string;
    FTitle: string;
    FDescription: string;
    FCopyright: string;
    FKeywords: string;
    FAuthor: string;
    procedure SetAuthor(const Value: string);
    procedure SetCopyright(const Value: string);
    procedure SetDescription(const Value: string);
    procedure SetIdentifier(const Value: string);
    procedure SetKeywords(const Value: string);
    procedure SetTitle(const Value: string);
  published
    function GetMetaTagsHTML: string;
    property Author: string read FAuthor write SetAuthor;
    property Description: string read FDescription write SetDescription;
    property Keywords: string read FKeywords write SetKeywords;
    property Copyright: string read FCopyright write SetCopyright;
    property Title: string read FTitle write SetTitle;
    property Identifier: string read FIdentifier write SetIdentifier;
  end;

The key method is the GetMetaTagsHTML, which is implemented as follows:

Listing 4


function TMetaTags.GetMetaTagsHTML: string;
var
  TempStr: string;
  i: Integer;
  PropList: PPropList;
  PropCount: Integer;
  PropName, PropValue: String;
begin
  TempStr := '';
  New(PropList);
  PropCount := GetPropList(Self.ClassInfo, [tkString, tkLString, tkWString], PropList);
 
  for i := 0 to PropCount - 1 do
  begin
    PropName := PropList^[i].Name;
    PropValue := GetStrProp(Self, PropList^[i]);
    if PropValue <> '' then
    begin
      TempStr := TempStr + BuildMetaTag(PropName, PropValue);
    end;
  end;
  Dispose(PropList);
  Result := TempStr;
end;

Note that it uses RTTI to find all the string properties and their corresponding values, and turns them into <META> tags. This means that you can add <META> tags of your choosing to the TMetaTags class declaration, and they will automatically be added to the resulting HTML code, without having to change any more code.

As mentioned above, TMetaMidasPageProducer overrides GetDefaultTemplate. The new version is:

Listing 5


const
    MetaHTML = '<HTML>'#13#10 +
    '<HEAD>'#13#10 +
    '<#META>' +
    '</HEAD>'#13#10 +
    '<BODY>'#13#10 +
    '<#BODYELEMENTS>'#13#10 +
    '</BODY>'#13#10 +
    '</HTML>'#13#10;
 
function TMetaMidasPageProducer.GetDefaultTemplate: string;
begin
  Result := MetaHTML;
end;

You will notice that I have added an additional tag inside the <HEAD> portion of the document, <#META>. This custom tag will be replaced with the <META> tag information produced by the TMetaTags class.

Of course, this tag has to be handled somewhere, and that is where the DoTagEvent method comes in. This overridden, virtual method will pass all the tags, save one, on to the inherited method. The <#META> tag, however, is replaced with the <META> tags text from our trusty TMetaTags class. The method is implemented as follows:

Listing 6


procedure TMetaMidasPageProducer.DoTagEvent(Tag: TTag;
  const TagString: string; TagParams: TStrings; var ReplaceText: string);
begin
  if (Tag = tgCustom) and (CompareText(TagString, 'META') = 0) then
  begin
    ReplaceText := MetaTags.GetMetaTagsHTML;
    Exit;
  end;
  inherited DoTagEvent(Tag, TagString, TagParams, ReplaceText);
end;

When you drop a TMetaMidasPageProducer on your application, you can set the values for the <META> tags, and the component will take care of the rest. The TMetaTags class knows how to produce the HTML for the <META> tags, and does so in the GetMetaTagsHTML method.

From here, you can descend from TMetaMidasPageProducer to create more elaborate pages. You know how to override the GetDefaultTemplate method to control what goes into the new page, and you can handle your own custom tags in an overridden DoTagEvent method.

This paper was adapted from my presentation that will be given at the Borland Conference 2000 in San Diego in July. For a fuller treatment of this topic, and for a look at how to build classes and components that work with TMidasPageProducer, attend the conference and sit in on my presentation, "Building InternetExpress Components".

About the Author

Nick Hodges recently separated from the Navy and now works happily at Xapware Technologies, where he wears whatever he wants to work. He can be reached at nick@xapware.com.


Server Response from: ETNASC04