AJAX Extender for TinyMCE. Including fix for UpdatePanels.
The information in this article is no longer valid. Please go to the new version found at http://weblogs.asp.net/cjdevos/archive/2008/06/19/ajax-extender-for-tinymce-continued.aspx. The current downloads are removed.
A while ago I was looking for a usable editor in one of the web applications I am working on. There are quite a few alternatives but I ended up picking TinyMCE.
TinyMCE is a very easy to use editor. Both for users and developers. It's great to write 1 small line of code to have textareas turned automatically into usable editors!
Using TinyMCE would be like:
1: <script type=”text/javascript” src=”/tinymce/jscripts/tiny_mce/tiny_mce.js”></script>
2: <script type=”text/javascript”>tinyMCE.init({mode : ‘textareas’, theme : ’simple’});</script>
However – this control actually turned into a small nightmare when textareas lived INSIDE an UpdatePanel.
Some of the problems:
1. After an asynchronous postback the editor was gone.
2. Values were not submitted to the server.
When searching the web for these issues, you’d find several links which would help you out a bit. Some of the solutions where:
a. before the postback is made the following statement must be issued: tinyMCE.saveTrigger(false, true);
b. issue an mceAddControl after the postback is finished.
c. Issue an mceRemoveControl before the postback starts.
d. Reset the idCounter to 0.
Only part d. was absolutely incorrect. It can lead to strange behaviors with textareas both inside and outside an updatepanel.
For my solution I took part of the input given by steho706 (http://forums.asp.net/members/steho706.aspx) in the discussion at http://forums.asp.net/p/1131150/2154829.aspx. He actually nailed the problem by mentioning the mceRemoveControl statement with the right event.
For me, however, the solution had one drawback. Textareas which were not inside an UpdatePanel refreshed as well…
And to nail this particular issue I decided to write an AJAX Control Extension, which you can find attached to this article.
The control will be usable by writing the following code:
1: <asp:TextBox ID=”TextBox1″ runat=”server” Width=”100%” Height=”200″ TextMode=”MultiLine” />
2: <cc:TinyMCETextBoxExtender TargetControlID=”txtTextBox1” ID=”TinyMCETextBoxExtender1″ runat=”server” />
For completeness sake here are excerpts of the code as well:
From the Behavior
1: this.registerPartialUpdateEvents();
2: this._pageLoadingHandler = Function.createDelegate(this, this._pageLoading);
3: this._pageRequestManager.add_pageLoading(this._pageLoadingHandler);
4:
5: var element = this.get_element();
6: if (tinyMCE.getInstanceById(element.id) == null || tinyMCE.getInstanceById(element.id) == “undefined”)
7: tinyMCE.execCommand(‘mceAddControl’,false,element.id);
8:
9:
10:
11: ...
12:
13: _pageLoading : function(sender, args) {
14: if (this._postBackPending) {
15: this._postBackPending = false;
16:
17: var element = this.get_element();
18: var panels = args.get_panelsUpdating();
19: for (var i = 0; i < panels.length; i++) {
20: var el=element;
21: while(el!=null)
22: {
23: if(el==panels[i]) break;
24: el = el.parentNode;
25: }
26: if(el!=null)
27: {
28: if (tinyMCE.getInstanceById(element.id) != null && tinyMCE.getInstanceById(element.id) != “undefined”)
29: {
30: tinyMCE.execCommand(‘mceFocus’, false, element.id);
31: tinyMCE.execCommand(‘mceRemoveControl’,false,element.id);
32: }
33: break;
34: }
35: }
36: }
37:
1: [Designer(typeof(TinyMCETextBoxDesigner))]
2: [ClientScriptResource(“TinyMCETextBox.TinyMCETextBoxBehavior”, “TinyMCETextBox.TinyMCETextBoxBehavior.js”)]
3: [TargetControlType(typeof(TextBox))]
4: public class TinyMCETextBoxExtender : ExtenderControlBase
5: {
6: protected override void OnLoad(EventArgs e)
7: {
8: // ** load scripts
9: if (Page.Items[“tinymce”] == null)
10: {
11: HtmlGenericControl Include = new HtmlGenericControl(“script”);
12: Include.Attributes.Add(“type”, “text/javascript”);
13: Include.Attributes.Add(“src”, Page.ResolveUrl(“~/tinymce/jscripts/tiny_mce/tiny_mce.js”));
14: this.Page.Header.Controls.Add(Include);
15:
16: //Config MCE
17: HtmlGenericControl Include2 = new HtmlGenericControl(“script”);
18: Include2.Attributes.Add(“type”, “text/javascript”);
19: Include2.InnerHtml = “tinyMCE.init({mode : ’specific_textareas’, theme : ’simple’});”;
20: this.Page.Header.Controls.Add(Include2);
21:
22: Page.Items[“tinymce”] = true;
23:
24: if (!Page.ClientScript.IsOnSubmitStatementRegistered(this.GetType(), “tinymcetriggersave”))
25: {
26: Page.ClientScript.RegisterOnSubmitStatement(this.GetType(), “tinymcetriggersave”, “tinyMCE.triggerSave(false,true);”);
27: }
28: }
29: base.OnLoad(e);
30: }
31: }