UpdatePanel - TinyMCE demo med nedladdningsbar zip-fil

TinyMCE är en skön HTML-Editor som har blivit väldigt populär. Den är oftast väldigt enkel att använda och har många konfigureringsmöjligheter.

Men att använda den tillsammans med Ajax och partial update är verkligen ingen lätt match. Jag lyckades tidigare i år, efter stor möda, men det var nog mest tur.

Skrev om det i bloggen, men den postningen blev inte så fullständig eller bra. Det var mest lite egna minnesanteckningar som jag fick till där. Jocke var inne och kollade på beskrivningen men fick inte till det. Så nu tänkte jag visa precis hur man kan göra med ett uppdaterad och fullständig kod.

Problemen

Problem 1. TinyMCE gör om textboxar till en Iframe, som My Portal Project förklarar. Detta leder till att det är svårt att ta emot värden (speciellt i Firefox). Waqas_badas visar hur man kan komma runt detta genom ett javascript på submit-knappen.

Problem 2. Vid Ajax-anrop ritas inte editorn upp igen. Här kan man anropa mceAddControl-kommandot, men det gäller att resetta id-räknaren innan man gör det, här är en som kommit på hur man gör.

Kodexempel

Nu tänkte jag låta koden förklara resten. Missa inte att ladda hem zip-filen längst ner som innehåller ett färdigt project som fungerar i IE7, FF2 och Opera.

Default.aspx

<%@ Page Language="C#" ValidateRequest="false" Trace="false" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>MS Ajax UpdatePanel - TinyMCE</title>
<script type="text/javascript">
function SaveMyPreciousValues()
{
tinyMCE.triggerSave(false,true);
TextBox1 = document.getElementById('TextBox1');
alert('Check value when posting: '+ TextBox1.value)
}
</script>
</head>
<body>

<form id="form1" runat="server">
<asp:ScriptManager ID="sm" EnablePartialRendering="true" runat="server">
</asp:ScriptManager>

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<p>
<asp:Label ID="Label1" runat="server" Text="Welcome to the MS Ajax UpdatePanel - TinyMCE Demo, Enjoy!"></asp:Label>
</p>
<asp:TextBox ID="TextBox1" Rows="10" Columns="50" TextMode="MultiLine" EnableViewState="false" Text="Write something here..." runat="server"></asp:TextBox>

<p>
<asp:Button ID="Button1" runat="server" OnClick="Button1_OnClick" OnClientClick="SaveMyPreciousValues();" Text="Hit me" />
</p>
</ContentTemplate>
</asp:UpdatePanel>

</form>
</body>
</html>

Default.cs.aspx

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
LoadTinyMCE();
}

private void LoadTinyMCE()
{

//Load tinyMCE
HtmlGenericControl Include = new HtmlGenericControl("script");
Include.Attributes.Add("type", "text/javascript");
Include.Attributes.Add("src", "js/tiny_mce/tiny_mce.js");
this.Page.Header.Controls.Add(Include);


//Config MCE
HtmlGenericControl Include2 = new HtmlGenericControl("script");
Include2.Attributes.Add("type", "text/javascript");
Include2.InnerHtml = "tinyMCE.init({mode : 'textareas' ,language : 'sv',entity_encoding : 'raw'});";
this.Page.Header.Controls.Add(Include2);

}

protected void Button1_OnClick(object sender, EventArgs e)
{

//Get the contect of the TextBox
string inputText = Request.Form["TextBox1"];

//Print all Form-values when testing
/*for (int i = 0; i<Request.Form.Count;i++ )
{
string itemName = Request.Form.AllKeys[i];
string itemValue = Request.Form.GetValues(i)[0];
Label1.Text = Label1.Text + "<br />" + itemName + ":" + itemValue;
}*/

Label1.Text = "Content posted from TextBox1: " + inputText;

//Register some javascript to redraw the editor.
//Very important to reset the id-counter to "0", or else strange things will happen..
ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "init", "tinyMCE.idCounter=0;tinyMCE.execCommand('mceAddControl', false, 'TextBox1');", true);
}
}

zip-icon UpdatePanelTinyMCE.zip (C#)

Uppdatering: Joakim har skrivit om exemplet till VB.NET, läs mer på hans blogg.

Comments

Hej! Tack för ett så snabbt svar :D Koden fungerar helt perfekt och bloggade lite kort om det: http://joakimk.blogspot.com/2007/07/tinymce-inside-of-aspnet-ajax.html
Har arbetat en dag nu med UpdatePanel och TinyMCE och kommit fram till att det kan bli lite tungt om man har många editorer som ska laddas om. Jag kommer troligtvis att kolla på att använda Web Services för den typen av CRUD forms.
Kul att det fungerade och trevligt att du gjorde om exemplet till VB. Ja du har rätt att det blir tungt med TinyMCE i UpdatePanels. Ibland ser det ut som hela sidan laddas om (istället för partial) bara för att editor hoppar till så. Det borde nog bli bättre om man använde en annan WYSIWYG-editor, men jag gillar TinyMCE i övrigt, så svårt att hitta en ersättare. Web Services i Ajax-funktioner låter intressant, har aldrig provat det själv. Men antar att man kan få snabbare uppdateringar då. Berätta gärna hur det har gått när du har provkört.
Nu har jag ändrat om sidan så att den använder webservices vilket tog bort de omladdningar som blev när jag använde UpdatePanel. Nakdelen med webservices är ett det blir lite mer kod. En stor fördel däremot är att man har mer kontroll när man helt styr flödet på klienten. Uppdaterade min blogg post lite med tips när man använder TinyMCE med web services.
Thanks for the help. The triggersave bit was exactly what I needed. The rest of the code didn't work for me though, probably because of MasterPages. Here's what I did, maybe it can help someone somewhere somehow sometime: In the MasterPage itself I added the usual: <script language="javascript" type="text/javascript" src="/tiny_mce/tiny_mce.js"></script> <script language="javascript" type="text/javascript"> tinyMCE.init({ mode : "textareas", theme : "simple", auto_reset_designmode : true }); </script> Now to convert the textareas on partial postback: <script language="javascript" type="text/javascript"> function TinyInit() { // Seems to be helluva important tinyMCE.idCounter = 0; // Get the webform (there can be only one in asp.net) var form = document.forms[0]; // Iterate all elements inside the webform for(var i = 0; i < form.elements.length; i++) { //If textarea, convert to TinyMCE if (form.elements[i].type == "textarea") tinyMCE.execCommand('mceAddControl', false, form.elements[i].id); } } </script> And to save the values before submitting: <script language="javascript" type="text/javascript"> function TinySave() { tinyMCE.triggerSave(false,true); } </script> In the Page_Load event of the MasterPage I add a javascript call to the TinyInit() function to on updatepanel init event: ScriptManager.RegisterClientScriptBlock(UpdatePanel1, this.GetType(), "init", "TinyInit();", true); Then all that is left to do is add: OnClientClick="TinySave()" to any button that might need the values of the textarea after postback (like a 'Save' button), or otherwise you wont see any of the changes you made inside the TinyMCE panel. The TinyInit() function just loops through all items on page and converts Textarea's into TinyMCE's. It's really mean and dirty, but I don't want to add each textarea clientid to the code manually, because the id's get real nasty when inside masterpages/panels/etc. If anyone has a better solution, please do tell. Regards, duncan
@Duncon clientid of the textarea can be used on master pages if it is declared runat=server e.g. tinyMce.updateContent('<%=txtpost.clientid %>'); Regards Rajesh
I have made an Ajax Control Extender to solve TinyMCE's problems with updatepanels. You can find it here http://weblog.e-agora.nl/cdevos/?p=4"> http://weblog.e-agora.nl/cdevos/?p=4
Hi CJ! Thanks for creating the TinyMCE Extender. I got noticed though the MS Forums about it a minute ago, so I've actually been writing a post about it meanwhile.
<a href="http://hi.baidu.com/zlgdgzl">baidu </a> <a href="http://zlgdgzl.blog.163.com/">163</a> <a href="http://blog.sina.com.cn/u/1423817594">sina</a> <a href="http://www.beijing-lv-guan.cn">beiing hotel</a>
'''
I have read all the comments above but none is useful for Tinymce to work with Ajax. Please give me a proper solution.
vibhu: The above code is working with the UpdatePanel. It is however not a great solution since the Iframe of TinyMCE is making the whole page flicker on update. I think the best way is to leave the html-editor outside of any Ajax-panels. I recommend to download the latest build from the TineMCE pages. There are now updated code with special components to use with Asp.Net.