There are a lot of really great controls in the ASP.Net AJAX Control Toolkit. For those of you who are unfamiliar with the toolkit, it is an open source project that is built on top of the Microsoft ASP.Net AJAX framework (the framework was formerly known by its code-name: Atlas). It contains over 40 controls that you can use to build highly responsive and interactive Ajax-enabled Web applications. It is a joint effort between Microsoft and the development community.
Today, I’m going to talk about one of the controls specifically. The HTMLEditor control. This control allows you to create and edit html content directly from within your browser. There are a lot of toolbar buttons available, and you can edit your content using the WYSIWYG (What you see is what you get) pane or the html text pane, and view the results using the Preview pane.
The control allows a good deal of customization. By modifying the CSS stylesheet, you can change the look and feel of the editor. By creating your own editor class and inheriting the editor control, you can specify which toolbar buttons should be available, and which panes to enable. Unfortunately, you can’t easily change the state of a toolbar button on startup. A user on stackoverflow.com asked if it were possible to pre-set the ‘right to left direction’ toggle button from the server. The control’s server-side properties do not allow this, but I was able to help him find a solution. Here is what we found:
When you add the editor control on your page like this:
<HTMLEditor:Editor runat="server" Id="editor" />
You end up with a few lines like this at the bottom of your page (one for each toolbar button, one for the toolbar itself, and one – like this one - for the editor):
Sys.Application.add_init(function() {
$create(AjaxControlToolkit.HTMLEditor.Editor, null, null, { "changingToolbar": "ctl00_SampleContent_editor_ctl01", "editPanel": "ctl00_SampleContent_editor_ctl02" }, $get("ctl00_SampleContent_editor"));
});
Notice that the line starts with a Sys.Application.add_init function call. This adds an event handler to the init event (the init event is raised after all scripts have been loaded but before page objects are created). This is when the objects are created. If we want to set the state of a button, we have to at least wait until the button is created.
While looking at the JavaScript code for the editor, I found that although the editor is created during init, it is not actually initialized until the load phase (it must ensure that all of its objects are created before it can initialize itself). The way it ensures that all objects are created before it initializes is by calling the Sys.Application.add_load function (the load event is raised after all scripts have been loaded and the objects in the application have been created and initialized).
We need to attach our own code after the editor has been initialized. This means that we need to inject code AFTER the load event, but before the user interacts with it. To do this, add this code to your page, or to an external JavaScript file referenced by the page. When adding this script to the page, be sure to add it below the ScriptManager. By adding the ScriptManager to your page, you’re including the ASP.Net AJAX framework (which is needed in order to access the Sys namespace).
Sys.Application.add_load(myFunction);
function myFunction() {
window.setTimeout(myOnLoad, 0);
}
This will tell the framework to call the myFunction during the load event. We can’t customize the editor or its buttons yet, though, because it may not be finished with its initialization. Remember, we have to inject our code AFTER the load event. So our ‘myFunction’ function calls window.setTimeout.
By using setTimeout, we are setting up myOnLoad to be called in 0 milliseconds. This seems pointless, but its not. Before myOnLoad can run, it has to wait until the current stack has completed (then it waits the specified amount of time). The current stack includes all load event handlers). When myOnLoad is called, we can be sure that the editor has been initialized, and it is ready to be modified.
In order to modify the control, we need to access its JavaScript object. The framework exposes methods to find components in the page. Here is what we’ll need in order to find the editor and its toolbar buttons:
var editor = $find('<%=editor.ClientID %>');
We start by using the $find function, which returns the specified Component object. You may have noticed the server tags in the above code. When you add a control to a page in ASP.Net, it ensures a unique id in the page by prefixing the id with text that is based on the control tree (for example, in the sample page, the editor’s id is ‘ctl00_SampleContent_editor’). The id rendered is not yet known at design time. In order to render the correct id in my script at runtime, I use this server tag and reference the ClientID property of the editor control.
If you added this script into an external JavaScript file, then you wont have access to server side properties and the server tags will not be replaced by anything. Therefore, you will have to do something different to get the id of the editor. Instead, add this script to your page:
var myEditorId = '<%=editor.ClientID %>';
and then change the above code to this:
var editor = $find(myEditorId);
Once we have access to the editor, we need to use it to get access to its toolbar, and then to its buttons.
var editor = $find('<%=editor.ClientID %>');
var toolbar = editor.get_changingToolbar();
var toolbarButtons = toolbar.get_buttons();
The above code will result in an array of objects that represent the toolbar buttons in the editor. From here, we can loop through the buttons until we find what we’re looking for. Once we find it, we can change its properties or run methods against it.
Here is the entire script:
// Attach a handler to the load event.
Sys.Application.add_load(myFunction);
function myFunction() {
//Setup myOnLoad to run AFTER the load event handlers have all completed
window.setTimeout(myOnLoad, 0);
}
function myOnLoad() {
//Find the instance of editor
var editor = $find('<%=editor.ClientID %>');
//Access the editor's toolbar
var toolbar = editor.get_changingToolbar();
//Get an array of toolbar buttons
var toolbarButtons = toolbar.get_buttons();
//Loop through the buttons array looking for the one we need
for (var i = 0; i < toolbarButtons.length; i++) {
//If this button is the right to left direction button, then toggle
if (toolbarButtons[i] instanceof AjaxControlToolkit.HTMLEditor.ToolbarButton.Rtl) {
//first, make sure the button has an edit panel set
toolbarButtons[i].set_activeEditPanel(editor.get_editPanel());
//Call the callMethod function (toggles the button)
toolbarButtons[i].callMethod();
}
}
}
In this case, we were looking for the ‘right to left direction’ button. We found it by checking each button to see if it was an instance of the ToolbarButton.Rtl object.
The first line after that sets the active edit panel. The control itself will do this, but not until later. We need this to be done before we can call the callMethod function (which is used to change the toggle state of a toggle button in the editor’s toolbar).
So that’s it. We’ve changed the default state of the toolbar button. Check back soon for more ways to customize the controls that are part of the toolkit.