Monday, 21 January 2008

Email Source Edit Function

If you've ever used email quick campaigns or email activities in normal campaigns you've likely been frustrated at the spontaneously re-formatting that sometimes happens when you paste in some content from your favourite HTML editor program. Oh, why doesn't the editor have a 'View Source' button to see what's actually there? Well, this post shares with you how you can add such a feature in an unsupported but minimally invasive way.

First of all the concept. We know the page is generated in code and we're not about to hack into this territory! Fortunately though, it's quite easy to hook into the onload event and run some javascript to add a button which will do what we want. After this we need to use the (toggle) button to replace the standard WSIWUG editor iFrame with a textarea for the source view and a few lines of code to shift your content between the different elements. Really the only thing we have to ensure is that when editing in source mode we ensure the body tag is contentEditable to be able to edit again in WSIWYG!

Note: I have found that an invaluable tool in any exploit of this kind is the IE DOM Explorer (downloadable from Microsoft), which allows you to easily locate elements and test dynamic manipulation of the document object. Although if you're trying to get to pages displayed in dialogs you have to be a little inventive ;-)

Step 1: So to begin with we'll add a script to the page of interest (say emailForm.aspx) and attach an event handler to run this button with document.body.onload. You can see that basically we're going to replace the first toolbar button with a longer piece of HTML which also includes the new button and a spacer. An alternative and more elegant way would be to clone(deep) the element, setting the desired properties and then inserting the new element in the DOM.

//this is the spacer
sp = "<td unselectable="'on'">";
sp += " <div unselectable="'on'"></div></td>";

function addViewSourceBtn(){
var t = document.getElementById("HTMLBAR");//get the toolbar
var c = t.getElementsByTagName("TD")[0].outerHTML; //get the first btn
var v = c.replace("cmd-cut.gif","cmd-insertKB.gif"); //clone and change
v = v.replace("Cut","Source");
v = v.replace("HTMLBAR.htmlExec('cut')","ViewSource()");
t.outerHTML = t.outerHTML.replace(c,v+sp+c); //recreate the toolbar
}

Step 2: Anyway, the major part of the task is in the function which is called by the button.

  1. First of all we're going to initialise a variable to hold the current [mode] of the button in the script. Alternatively, we could have stored this as an expando on the button and changed its appearance perhaps. We also have a variable [RichEdit] which holds the initial iFrame HTML outerHTML, but we could easily hardcode it as per [TextEdit].
  2. When we switch to source edit mode, we're going to disable any wizard buttons (say in the quick campaign wizard) and hide all the other toolbar buttons.
  3. So then when we toggle to source edit we set the value of the textbox, and the other way we need to write the document for the iFrame.

That's it! Enjoy.

UPDATE: Of course the better way to do this is use this code in the customisable email onload handler in MSCRM. This saves you having to make any edits to the pages themselves which is strictly unsupported.

function ViewSource(){
// define different editors
var TextEdit = '<textarea ID="descriptionIFrame" style="width:100%;height:100%;"></textarea>';
var editor_obj = document.all['descriptionIFrame'];

if (mode == "textedit") {
mode = 'wysiwyg';
with(window.parent){
document.all['btn_id_Next'].disabled=true;
document.all['btn_id_Back'].disabled=true;
}
var editdoc = editor_obj.contentWindow.document;
var contents = editdoc.documentElement.outerHTML;
editor_obj.outerHTML = TextEdit;
var editor_obj = document.all['descriptionIFrame'];
editor_obj.value = contents;

b = document.all['HTMLBAR'].getElementsByTagName("TD");//hide wysiwyg buttons
for (i=0;i<b.length;i++){with(b[i]){ if (title!='Source')style.visibility='hidden'; } }

} else {
mode = 'textedit';
var contents = editor_obj.value;
editor_obj.outerHTML = RichEdit;
var editor_obj = document.all['descriptionIFrame'];
var editdoc = editor_obj.contentWindow.document;

editdoc.open();
editdoc.write(contents);
editdoc.close();

b = document.all['HTMLBAR'].getElementsByTagName("TD");//show wysiwyg buttons
for (i=0;i<b.length;i++){b[i].style.visibility='';}

with(window.parent){
document.all['btn_id_Next'].disabled=false;
document.all['btn_id_Back'].disabled=false;
}
}
}

1 comment:

Murali Tharail Kunnath said...

Hi Chris Cohen,

Excellent piece of code. Immensely helpfull from me...

Thank u so much.