A Code Project Article Editor with Live Preview
Click image for full screenshot - 306 KB
Table of Contents
- Introduction
- Background
- Assembly Instructions
- Using BobBuilder
- Known Issues
- Points of Interest
- TODO
- References
- History
{ 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 Regex
s 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
- DockPanel Suite [^] by Weifen Luo
- ic#code [^] for
#develop
and#ziplib
History
- 2008 - 02 - 01: First version
- 2008 - 02 - 01: Removed smileys
- 2008 - 02 - 03: Added auto-generation of Table of Contents
- 2008 - 02 - 07: Fixed auto-generation of Table of Contents
- 2009 - 08 - 05: Fixed preview placement with new DOCTYPE in template
License
This article, along with any associated source code and files, is licensed under The Code Project Open License.
Contact
If you have any feedback, please feel free to CONTACT me.