Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Code Project Article Editor with Live Preview

0.00/5 (No votes)
5 Aug 2009 1  
A tool to help author articles at The Code Project
screenshot_small.png

Click image for full screenshot - 306 KB

Table of Contents

{ Automatically generated Table of Contents }

Introduction

This is a short article about an HTML editor I assembled with special support for writing articles at The Code Project.

Background

Office 2007 doesn't contain a version of Frontpage, which I used to use to write articles. I didn't want to install Frontpage 2003 over Office 2007 "just in case!" So, I had a look around for an HTML editor that can show a preview side-by-side with the raw HTML. Visual Studio was the best one I found, but the preview has to be below the HTML, which is not what I want on my widescreen monitors. So I decided to write one myself. Here it is and I hope you find it useful.

Note: As Derek Bartram pointed out in the message board below, Visual Studio 2008 can split the source and design views vertically. The setting is:

Tools | Options | HTML Designer | General | Split views vertically

Assembly Instructions

It's a basic Windows Forms application with Weifen Luo's DockPanel Suite [^], so you can arrange the panes just how you want them. The editor is part of #develop from the ic#code [^] people. I also used their #ziplib. The preview pane is a plain old WebBrowser control.

Using BobBuilder

Window Types

There are two types of windows in BobBuilder: editor and preview. You must have exactly one editor window open for each document, but you can have any number of preview windows open.

Editor Windows

The TextEditor control from #develop has lots of nice features, like undo/redo and syntax highlighting. It also has loads of options that I have surfaced in the Tools | Options dialog. I have added shortcuts for some HTML tags like <code> and <pre>, which are often found in articles at The Code Project. Also, when you are in an opening tag, pressing TAB will close the tag for you and put the caret in the middle.

Autocomplete

To help prevent illegal HTML being rendered, there are a few "autocompleted" characters. Firstly, if you type a <, you will get <>. Then if you are inside a tag, the quote, ", and single quote, ', characters will double up.

Preview Windows

The preview windows update continuously while you use the editor. If you have a system sound set for the "Navigation Started" event, you might like to disable it! The preview windows attempt to remember their scroll positions at each update, but this is not possible if illegal HTML is rendered.

Toolstrips

There are buttons for the standard formattings like bold and italic. There is also an Action to insert a clickety.

Table of Contents

There are a menu item and a toolstrip button to insert a Table of Contents. This command parses the HTML using Regexs for all <hN> tags and inserts anchors around them. It then adds unordered lists of links to make the table. If a table already exists, then it will be replaced. Otherwise, the new table is inserted at the current caret position.

Known Issues

Links

Any relative hyperlinks, for example to anchors, do not work in the preview windows. This is because the HTML is passed to the WebBrowser controls using their DocumentText property. When this happens, the WebBrowser sets the URI to about:blank and things stop working...

However, before the HTML is passed to the WebBrowser control, it is modified a bit. Some JavaScript is added to help maintain the scroll position and a <base> tag is added to make any inline references work, such as images. You can always save the document and use Tools | External Browser to quickly check that your relative links are working.

Note: when you upload your article, the HTML will be put in one of the main directories, but all other files (images, ZIPs, ... ) will be put in a subdirectory named the same as the basename of the article. For example, BobBuilder.aspx is in /KB/cs/ and all other files are in /KB/cs/BobBuilder/. You might like to replicate this structure locally when you are writing your article.

Points of Interest

There are a couple of points to highlight:

Design Patterns

I implemented the MVC pattern, but with a twist: I used the Observer pattern with the views subscribing to the (Singleton) controller as publisher. When an action is initiated, a command is sent to the controller using a normal method call. The controller does its work, firing events to communicate with any participating views.

A neat feature of the .NET event implementation of Observer is that the subscribers can alter the EventArgs derived parameter, so passing information back to the publisher. This is demonstrated in the implementation of the CurrentDocument property:

partial class Controller
{
   public static Document CurrentDocument
   {
      get
      {
         return Instance
            .ExecuteCore( null, new Command.GetCurrentDocument() )
            .Document;
      }
   }
}

Instance gets the Singleton instance and ExecuteCore is a member method which returns its Command parameter. For the GetCurrentDocument command, all ExecuteCore does is raise the static Execute event. All the views have subscribed to this event and, when the currently active view handles it, it fills in the Document property of the command with its own (the current) document. So, when the event returns after calling all the views in its invocation list, the Document property has been set by the current view and is returned to whoever needs it.

This pattern made life easier than having the controller maintain a collection of some view interface. Now this is all taken care of by the built-in event handling, while reducing the coupling between the controller and the views.

System.Windows.Forms.Keys

I could not find a .NET way to determine the right member of this enumeration for a given char. In the end, I wrote this snippet:

[System.Runtime.InteropServices.DllImport( "user32.dll" )]
static extern short VkKeyScan( char ch );
   
static Keys ConvertToKeys( char c )
{
   short vk = VkKeyScan( c );
   int key = vk & 0x00FF;
   int mod = vk & 0xFF00;
   int iKeys = ( mod << 8 ) | key;
   Keys eKeys = ( Keys ) iKeys;
   return eKeys;
}

TODO

This is a short list of possible future enhancements. Please leave a comment below if you have any opinions or ideas.

  • Spelling checker
  • More common formattings
  • Configurable shortcuts
  • Macro compiler
  • Remember toolstrip positions
  • Handle exceptions better

References

History

2008 Feb 01:

Initial release

2008 Feb 01: Removed smileys
2008 Feb 03: Added auto-generation of Table of Contents
2008 Feb 07: Fixed auto-generation of Table of Contents
2009 Aug 05: Fixed preview placement with new DOCTYPE in template

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here