I have written this jQuery code that allows a single RadEditor instance to be used to edit multiple different editable areas (editable bodies) on the same page. It is very efficient and vastly improves page loading time but there are a few problems that I am unable to resolve and I hope you may be able to help.
To use the jQuery code, the markup on the page needs to be similar to this:
<div class="SKEditorWrapper"> |
<telerik:RadEditor using PageTop Toolbar goes here/> |
</div> |
<div id="BodyBlockPanel1" class="SKEditableBody"> |
<textarea name="BodyBlockHTML1" rows="2" cols="20" id="BodyBlockHTML1" class="SKEditableBodyText" style="display:none;"> |
This is editable body 1. |
</textarea> |
</div> |
<div id="BodyBlockPanel2" class="SKEditableBody"> |
<textarea name="BodyBlockHTML2" rows="2" cols="20" id="BodyBlockHTML2" class="SKEditableBodyText" style="display:none;"> |
This is editable body 2. |
</textarea> |
</div> |
<!-- ... and so on. We have 40 editable bodies on our page.--> |
The jQuery code hides the textareas and inserts a DIV after each of them, to render a WYSIWYG version of the markup. When the user clicks on the DIV, it is replaced with the RadEditor. The RadEditor is used with 'PageTop' toolbar and design mode only, to provide WYSIWYG in-place editing.
The jQuery code is as follows:
$(document).ready(function(){ |
var $bodyBlock; |
var $editorBody; |
var firstEdit = true; |
var $prevEditableBody = null; |
//Hide the RadEditor and its wrapper. |
$('SKEditorWrapper').hide(); |
var $radEditor = $('div.RadEditor').hide(); |
var saveEditorContent = function(){ |
//Copy the content from the RadEditor back into the TextArea. |
var editor = $find($radEditor.attr('id')); |
var edContent = editor.get_html('true'); |
$prevEditableBody |
.find('.SKEditableBodyText') |
.val(edContent); |
}; |
var moveEditorToBody = function(event){ |
var $editorPanel = $('.SKEditorWrapper'); |
var $editableBody = $(this); |
//Switch off the mouse-over styling on all editable bodies on the page. |
$('.SKEditableBody') |
.removeClass('SKEditableBodyHighlight'); |
//Attach highlighter class and mousout handlers to transfer editor content |
//to TextArea when the user clicks 'save'. |
$editableBody |
.addClass('SKEditableBodyHighlight') |
.unbind('mouseenter mouseleave') |
.mouseleave(saveEditorContent) |
.blur(saveEditorContent); |
//Remove the RadEditor from its current position in the DOM, replace |
//it with a DIV to render the markup and copy the editor content into |
//the TextArea ready for AJAX postback. |
if (firstEdit){ |
firstEdit = false; |
$editorPanel.remove(); |
} |
else { |
var editor = $find($radEditor.attr('id')); |
var edContent = editor.get_html('true'); |
$('<div/>') |
.addClass('SKEditableBodyBlockContent') |
.html(edContent) |
.replaceAll($editorPanel); |
saveEditorContent(); |
} |
//Insert the RadEditor into its new position in the DOM, i.e. in the |
//editable body the user clicked on. |
$editableBody.append($editorPanel); |
//Find the DIV showing the rendered markup of this editable body and |
//replace it with the RadEditor. |
var editor = $find($radEditor.attr('id')); |
$bodyBlock = $(event.target).closest('.SKEditableBodyBlockContent'); |
editor.set_html($bodyBlock.html()); |
var editorBody = document.all ? editor.get_document().body : editor.get_document(); |
$editorBody = $(editorBody); |
$bodyBlock.remove(); |
//Show the RadEditor and its wrapper. |
$editorPanel.show(); |
$radEditor.show(); |
//Delay a short time and then apply focus to editor to cause text cursor |
//to be displayed in the RadEditor. |
setTimeout(function(){ |
editor.setFocus(); |
},200); |
//Prevent the click event from activating any links from anchor tags in the |
//editable body. |
event.preventDefault(); |
//Re-Attach click and hover handlers to the editable body that was being |
//edited previously. |
if ($prevEditableBody){ |
$prevEditableBody |
.one('click', moveEditorToBody) |
.unbind('mouseenter mouseleave') |
.hover(function(){ |
$(this).addClass('SKEditableBodyHighlight'); |
}, function(){ |
$(this).removeClass('SKEditableBodyHighlight'); |
}); |
} |
$prevEditableBody = $editableBody; |
}; |
//Find the TextAreas for every editable body, hide them and insert a |
//DIV to show their rendered markup. |
$('.SKEditableBodyText').each(function(index){ |
$(this).hide(); |
$('<div/>') |
.addClass('SKEditableBodyBlockContent') |
.html($(this).val()) |
.insertAfter($(this)); |
}); |
//Make the editable bodies editable, using single RadEditor, when the user |
//clicks them and attach mouse-overs to indicate which bodies are editable. |
$('.SKEditableBody') |
.one('click', moveEditorToBody) |
.hover(function(){ |
$(this).addClass('SKEditableBodyHighlight'); |
}, function(){ |
$(this).removeClass('SKEditableBodyHighlight'); |
}); |
}); |
The problems are:
- In IE/Chrome, after an editable body is clicked, the user has to click again before the text insert caret and toolbar will show. Is there a way to make these appear as soon as the user clicks on the editable DIV.
- In Firefox, the text insert caret never shows, no matter how many times the user clicks. Sadly, this makes it unusable in Firefox, although if the user enters text it does go into the correct position in the RadEditor. How can I cause the text insert caret to appear in Firefox?
I hope you can help, as this would be a very efficient solution to the problem of having multiple editable areas on a single page.