Tuesday, December 15, 2009

Let’s cook a simple yet powerful HTML Editor with Delphi

N.B. You might need to read Using Scintilla in Delphi 7 before reading this tutorial.

I'm cooking a simple WYSIWYG HTML Editor which allows editing a webpage from design mode and source mode just like FrontPage and DreamWeaver do. Things like auto-completion, Style editor and flash are beyond the scope of this tutorial.

When cooking a simple IDE, syntax highlighting is the ingredient that makes it different from a text editor like notepad. If syntax highlighting never existed and all we had was notepad, I don't think I would have learnt HTML.

Step 1: Warm the interface
Drop a TScintilla (from the Scintilla tab), a TWebBrowser (from the Internet tab) , 3 buttons and a TOpenDialog on the form.
Set the language of the Scintilla control to HTML. So you should have something like this:

The first button will be for loading the file you want to edit, the second for refreshing the Preview and the third for switching to design mode.

Step 2 (Add some code)
In order to get juice out of the TWebBrowser component, you must add the mshtml unit to the code. This unit is interesting because it exposes some of the stuff that make up the engine used by Internet Explorer and other Microsoft programs. An expert HTML user will be very familiar with some of the methods and properties in this module. Here’s the code:
{$R *.dfm}
Step 2 (Loading the HTML file)
the first button will simply load an html file onto the webbrowser. Add this code for the Click Event on button1:
procedure TForm1.Button1Click(Sender: TObject);
  doc: IHTMLDocument2;
  if not OpenDialog1.Execute then

  doc:= WebBrowser1.Document as IHTMLDocument2;

  while doc.readyState <> 'complete' do Application.ProcessMessages;

  Scintilla1.Lines.Text:= doc.body.innerHTML;
To load the file I used WebBrowser1.Navigate(OpenDialog1.FileName);
Because I’ll need to retrieve the text from the WebBrowser at some stage, I used a IHTMLDocument2 interface to allow me to read the innerHTML of the document’s body. The head isn’t much needed here. Unfortunately the outerHTML property of the body is read-only. This pauses a problem because I can’t edit attributes set in the tag. You can use file handling routines or another method to be able to access the full source code but we'll stick to this simple method from its simplicity.

The line while doc.readyState <> 'complete' do Application.ProcessMessages; is useful because we’ll get an exception if we try to use the body element because it becomes ready.

Running the program should give you something like this:

Step 3 (I can smell it)
Now I can edit the html but nothing will happen if I try to preview.
So to connect the two controls, I’ll write the code for button2. It copies the text  from the scintilla control into the innerHTML of the document’s body.
procedure TForm1.Button2Click(Sender: TObject);
  doc: IHTMLDocument2;
  doc:= WebBrowser1.Document as IHTMLDocument2;
  doc.body.innerHTML:= Scintilla1.Lines.Text;
Now you can test the source code editor. But get the WYSISWYG part we got to the Next step…

Step 4 (The food is ready)
The last button will switch the designMode ‘on’ for the WebBrowser:
procedure TForm1.Button3Click(Sender: TObject);
  doc: IHTMLDocument2;
  doc:= WebBrowser1.Document as IHTMLDocument2;
  doc.designMode:= 'on';
 OK, That's it! We get this:

1 comment: