views:

3584

answers:

8

I'm trying to do something that many people seem to have been able to do but which I am unable to implement any solution. The TinyMCE control works pretty well in an asp.net form until you enclose it with an UpdatePanel, which then breaks after postback. I have tried some fixes like the RegisterClientScriptBlock method, but am still unsuccessful, I still lose the tinyMCE control after postback.

Below is a full test project (VS 2008) provided with a Control outside UpdatePanel and one inside, with a button on each to generate postback. Also in the project I have a EditorTest control which include commented code of some calls I tried, in case it gives anyone any ideas.

CODE SAMPLE

Here are some sources for some solutions on the MCE forum :
AJAX
UpdatePanel

A: 

TinyMCE (as well as other WYSIWYG editors, FCKEditor etc) suffers from postback validation issues. By default any ASP.Net page on postback has its contents checked, and any unencoded HTML throws the postback validation error.

Now many people, including on those forums suggest disabling the postback validation, validaterequest="false" , but this makes you susceptible to scripting attacks, the best thing to do is bind a function to the async postback event that fires off just before async postback. This JavaScript function needs to HTML encode the TinyMCE data being posted back to the server, this will then pass the postback validation and you'll be OK.

I believe TinyMCE and other editors correctly do this on postbacks but not async postbacks hence the issue, in fact if you look at TinyMCE's source you can probably find their function that does this and simply add the event binding.

Hope this helps

MJJames
This has nothing to do with my problem where my postbacks are working, it's the tinyMCE layout that doesn't rebuild. Encoding the <> tag fix the validationRequest problem and I already did it. The code sample provided do not include such errors.
lucian.jp
A: 

There's quite a full answer at http://forums.asp.net/p/1131150/2154829.aspx a few answers down by 'steho706' using the MS AJAX javascript library to keep the TinyMCE frame around the textarea during partial postbacks.

Note that in situations where you're using TinyMCE for databinding purposes, this script works fine in IE, but not Firefox or Chrome - the value is not updated - but it is a definite start

Hmobius
A: 

You have to call the initializing method of the TinyMCE whenever the update panel is refreshed.

For this, you have either to call this method (tinyMCE.init) from a RegisterStartupScript method, or to create a page load javascript function in the head section of the page like this:

function pageLoad() {
   tinyMCE.init();
}

This function will be executed each time the update panel is refreshed.

Stefy
+2  A: 

Ok, your problem is two fold. Stefy supplied you with part of the answer, which is you have to initialize TinyMCE on the postback by registering startup script like so:

using System.Web.UI;

namespace TinyMCEProblemDemo
{
    public partial class EditorClean : UserControl
    {
        protected void Page_Load(object sender, System.EventArgs e)
        {                
              ScriptManager.RegisterStartupScript(this.Page, 
                  this.Page.GetType(), mce.ClientID, "callInt" + mce.ClientID + "();", true);
        }
    }
}

The second problem you have is with your implementation of a custom control. Designing custom controls is out of scope of this answer. Google can help you there.

You have multiple instances of your control on the page which can cause you issues with script, as it get rendered multiple times. This is how I modified your markup to solve your issue(notice dynamic naming of your script functions, custom controls should be self contained and mode: "exact" on the tinyMCE.init):

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="EditorClean.ascx.cs"
    Inherits="TinyMCEProblemDemo.EditorClean" %>
<script type="text/javascript" src="Editor/tiny_mce.js"></script>

<script type="text/javascript">
    function myCustomCleanup<%= mce.ClientID%>(type, value) {
        if (type == "insert_to_editor") {
            value = value.replace(/&lt;/gi, "<");
            value = value.replace(/&gt;/gi, ">");
        }
        return value;
    }
    function myCustomSaveContent<%= mce.ClientID%>(element_id, html, body) {
        html = html.replace(/</gi, "&lt;");
        html = html.replace(/>/gi, "&gt;");
        return html;
    }

    function callInt<%= mce.ClientID%>() {

        tinyMCE.init({
            mode: "exact",
            elements: "<%= mce.ClientID%>",
            theme: "advanced",
            skin: "o2k7",
            plugins: "inlinepopups,paste,safari",
            theme_advanced_buttons1: "fontselect,fontsizeselect,|,forecolor,backcolor,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,cut,copy,paste,pastetext,pasteword",
            theme_advanced_buttons2: "",
            theme_advanced_buttons3: "",
            theme_advanced_toolbar_location: "top",
            theme_advanced_toolbar_align: "left",
            cleanup_callback: "myCustomCleanup<%= mce.ClientID%>",
            save_callback: "myCustomSaveContent<%= mce.ClientID%>"
        });
    }
</script>
<textarea runat="server" id="mce" name="editor" cols="50" rows="15">Enter your text here...</textarea>
rick schott
Did my answer solve your problem?
rick schott
You cannot use the `mode` "exact", it doesn't work properly in a UpdatePanel. You can use `textareas` or a `class selector` instead. And for me the `save_callback` was pretty buggy, instead I used `RegisterOnSubmitStatement` to call `tinyMCE.triggerSave()`. It's working just fine for me.
BrunoLM
I have used mode exact in UpdatePanels without issue, everyone's requirements and implementation details are different.
rick schott
A: 

I did the following:

First I added the this Javascript to my page:

<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);

function endRequestHandler(sender,args)
{
    tinyMCE.idCounter=0;
    tinyMCE.execCommand('mceAddControl',false,'htmlContent');
}

function UpdateTextArea()
{ 
    tinyMCE.triggerSave(false,true);
}
</script>

Because I'm creating an ASP.NET and using and ASP.NET Button in my page, I had to add the following to the Page Load:

protected void Page_Load(object sender, EventArgs e)
{
    Button1.Attributes.Add("onclick", "UpdateTextArea()");
}
A: 

The correct way to make tinyMCE work in an updatepanel:

1) Create a handler for the OnClientClick of your "submit" button.

2) Run tinyMCE.execCommand("mceRemoveControl", false, '<%= txtMCE.ClientID %>'); in the handler, so as to remove the tinyMCE instance before the postback.

3) In your async postback, use the ScriptManager.RegisterStartupScript to run tinyMCE.execCommand("mceAddControl", true, '<%= txtMCE.ClientID %>');

Basically, all you need to do is use the mceRemoveControl command before the async postback and register a startup script to run the mceAddControl command after the async postback. Not too tough.

Kevin
+1  A: 

To execute the init everytime the UpdatePanel changes you need to register the script using ScriptManager:

// control is your UpdatePanel
ScriptManager.RegisterStartupScript(control, control.GetType(), control.UniqueID, "your_tinymce_initfunc();", true);

NOTE: You cannot use exact mode on your init function, you can use either textareas or a class selector, or else it won't work properly.

You also have to use

ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "", "tinyMCE.triggerSave();");

On a postback of a UpdatePanel the editor content isn't saved on the Textbox, because the default behavior is only for form.submit, so when you submit anything it will save the text before it posts.

On the code behind to get the value you will just need to access TextBox.Text property.

NOTE: If you are using the .NET GZipped you probably will have to drop it, I couldn't get it working, I had to remove this completely.

BrunoLM