17 Dec 2010

Create your own custom Advanced Insert Image Dialog in a rich text editor with MOSS 2007

Posted by Alexander

Challenge

One of the biggest problems using content management in a non-publishing site of SharePoint is de way how images are inserted. This is especially a problem when editing a Wiki page in the Wiki template or a blogpost inside the Blog template. It gets even worse when using such templates in a SharePoint website which has publishing enabled. Those rich text editors have a cool asset picker for the images while your Wiki or Blog template based sites still request to fill in an Url by yourself.
 

It is a real problem and mostly a no-go explaining your customers that they will have to upload one or more images to an image library and then finding out the correct Url, copy its hyperlink and inserting it into the rich text editor “Insert image” dialog.

A solution for this problem could be getting a third-party vendor’s product to replace the existing rich text editor for a new fancy one. But in most cases you get more functionality you actuallly need or want to give to your users and licenses become expensive when your farm exist of multiple servers.

So would it be possible to replace it by something you made yourself? Actually… Yes!! That is possible. And it is even not that difficult without changing standard SharePoint files (a bad practice) or even changing to way how the image is inserted.

How does it work?

Changing the “Insert Image” functionality is not something you do through Xml in this case. Using Xml is only the correct way when you are talking about a publishing site. By using Fiddler and the Web Developer of Internet Explorer I found out how SharePoint actually shows the popup requesting the Url and inserts the image into the field.

Lets have a look at the EditPost.aspx file of the Blog template. If you create a blog based on the Blog template it uses the EditPost.aspx file to edit the blogpost. When using the Web Developer tool you will notice that it loads the FORM.JS file from the folder {12 Hives}\TEMPLATE\LAYOUTS\{LCID}.

This JavaScript file has an enormous amount of functions which are addressed to build the rich text editor and to handle the diversity of functions. For the “Insert image” button two functions are important:

  • RTE_InsertImage(strBaseElementID)
  • RTE_AdvancedModalDialog(strBaseElementID, strDialogName, width, height, dialogArg);

The important parameter is “strBaseElementID”. This is the id of the <textarea> element in the page used for the field. The RTE_InsertImage calles the RTE_AdvancedModalDialog to show the RteDialog.aspx dialog found at {12 Hives}\Template\LAYOUTS.  After the “OK” button is pressed inside the dialog the function RTE_InsertImage injects a piece of HTML based on the <IMG> element  at the current location inside <textarea> .

The solution

In the following example we have extended the rich text editor of the Blog template. The first step we need to do is making sure that we extend the JavaScript called by the button. But we do not want to change the existing FORM.JS file. To accomplish this we need to “override” the functions defined in the FORM.JS using a new separate JavaScript file. The fun thing about JavaScript is that when your overrides are loaded after the initial functions, they replace the initial functions.

Custom RTEAdvancedDialog.js

So first we need to create our own JavaScript file called RteAdvancedDialog.js.  We place the file in the following location {12 Hives}\Template\LAYOUTS\AdvancedDialog. The contents of the file is as follow:

var g_RTE_Advanced_Dialog_Width = “400″;
var g_RTE_Advanced_Dialog_Height = “125″;

function RTE_InsertImage(strBaseElementID) {
   
RTE_SaveSelection(strBaseElementID);
    var opts = RTE_AdvancedModalDialog(strBaseElementID, ‘InsertImage’, g_RTE_Advanced_Dialog_Width, g_RTE_Advanced_Dialog_Height, null);

 if (opts != null) {
       
var href = STSHtmlEncode(opts[1]);
        var altText = STSHtmlEncode(opts[0]);
        var fAllowRelativeLinks = false;
        var variables = RTE_GetEditorInstanceVariables(strBaseElementID);

        if (variables != null && variables.aSettings != null) {

            fAllowRelativeLinks = variables.aSettings.fAllowRelativeLinks;
        }

        if (IsSafeHrefAlert(href, fAllowRelativeLinks)) {

            var imgHtml = ‘<IMG SRC=”‘ + href + ‘” ALT=”‘ + altText + ‘”>’;
            RTE_GetSelection(strBaseElementID).pasteHTML(imgHtml);
        }

        if (RTE_UseDynamicHeightSizing(strBaseElementID)) {

            RTE_DocEditor_AdjustHeight(strBaseElementID);
        }
    }
}

function RTE_AdvancedModalDialog(strBaseElementID,strDialogName, width, height, dialogArg) {
   
var variables = RTE_GetEditorInstanceVariables(strBaseElementID);

    return showModalDialog(variables.aSettings.urlWebRoot + “/_layouts/AdvancedDialog/RteAdvancedDialog.aspx?Dialog=” + strDialogName + “&LCID=” + RTE_GetWebLocale(strBaseElementID), dialogArg, “resizable: yes; status: no; help: no; ” + “center: yes; dialogWidth:” + width + “px; ” + “dialogHeight:” + height + “px;”);
}

We override both functions RTE_InsertImage and RTE_ModalDialog  by copying them into our own JavaScript file. Secondly we rename the function RTE_ModalDialog  to RTE_AdvancedModalDialog. The third step is to change the call from RTE_InsertImage to the function RTE_ModalDialog to RTE_AdvancedModalDialog.  And as last step we need to call a different aspx file for the dialog.

Custom RteAdvancedDialog.aspx

Create a copy from the RteDialog.aspx , rename it to RteAdvancedDialog.aspx and move it to the location {12 Hives}\Template\LAYOUTS\AdvancedDialog. Add the following Register statement at the top of the file.

<%@ Register Tagprefix=”CMS” Namespace=”Microsoft.SharePoint.Publishing.WebControls” Assembly=”Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c” %>

Replace the second <input> element in the table inside the body with the following code:

<td><CMS:AssetUrlSelector runat=”server” /></td>

Now reassign the arr[1] value inside the script for the onclick event of the OKButton to the next value:

arr[1] = document.getElementById(“ImageSelector_AssetUrlInput”).value;

Remove the type=”submit” property from the <button> element of the OKButton like this:

<button id=”OKButton” class=”ms-ButtonHeightWidth”  type=”submit” >

Finally add a <form> element around the HTML inside the body like this:

<body …>
    <form runat=”server”>
    …
    </form>
</body>

Changing the pages of the blog

To get it to work we need to create our own custom template based on the Blog template by copying it. Inside the site definition  {Blog Template Name}\Lists\Posts you will find the EditPost.aspx and the NewPost.aspx files for changing and adding blogposts.

Add the JavaScript to the pages at the moment the FORM.JS file is already loaded. This is done by adding them inside the content placeholder called “PlaceHolderAdditionalPageHead”. Add the following code to the files:

<asp:Content ContentPlaceHolderID=”PlaceHolderAdditionalPageHead” runat=”server”>
    <script src=”/_layouts/Rabo/RteAdvancedDialog.js”></script>
</asp:Content>

Now run your SharePoint site and open the blog and try to add a new blogpost or edit an existing blogpost. As soon as you select the “Insert Image” button the new dialog appears:

Instead of having a textbox to fill in the Url, you get a nice “Browse…” button behind it. Clicking on that button we popup the asset selector dialog.

This dialog will allow you to upload new images and select an image from one of the image libraries. When after an image selection the “OK” button is clicked the Url is copied inside the textbox.

You are still able to change the Url by hand but thanks to the new dialog you have the ability to select one of the images. By pressing on the “OK” button the image is inserted into the blogpost.

Because we do exactly it as SharePoint did everything will work the same. Keep in mind that you need to have the Microsoft.SharePoint.Publishing.dll installed. But if you are working with WSS 3.0 you can create your own cool custom code to select an image from one of the libraries by replacin the AssetUrlSelector control we were using.

Conclusion

 By adding your own custom JavaScript and dialog you are able to create a nifty cool new Advanced “Insert Image” dialog which allows you to upload and select images from image libraries. Imagine what other stuff is possible by just overloading the RTE functions inside the FORM.JS file. Creating new buttons with new functionality or remove existing buttons. Everything is possible.

The example code can be downloaded here.

Leave a Reply

Message: