Plugin till TinyMCE för att klistra in källkod

När jag postade mitt förra inlägg så märkte jag att källkoden kunde formateras bättre. HTML-editorn TinyMCE som vi använder till att redigera inläggen stoppar som default in <br /> på alla radbryt och omger stycken med paragrafer. Bra när man skriver brödtext, men onödigt när man vill posta källkod. Jag ville hellre att kodexemplena skulle vara förformatterade utan någon extra HTML-uppmärkning.

Eftersom jag har tagit bort breaks i det förra inlägget kommer här en bild på hur det såg ut innan.

Samtidigt ville jag prova med att fixa syntax-formattering där nyckelorden får färger för bättre läsbarhet. Ska skriva mer om hur jag gjorde själva syntax-uppmärkningen i ett senare blogginlägg, men kan nämna att jag gjort detta med javascript hos besökaren. Uppdatering: Nu har jag skrivit klart bloggposten om javascript-biblioteket syntaxhl som jag avänder till att visa formatteringen i själva blogginläggen.

Nu till TinyMCE-pluggen som märker upp kodstyckena i databasen. Det heter syntaxhl finns att ladda hem på GitHub och går att läsa mer om hos skaparen Richard Grundy. Vid redigering ser det ut så här:

http://codeodyssey.se/Images/Post/453/syntaxhl-plugin-for-tinymce.png

Som standard så omges koden med en textarea, något jag inte ville utan jag behövde en speciell uppmärkning för att fungera med den syntax-formatteraren jag valt. Hos Spencer Kellis hittade jag förklaring hur han hade gjort för att konfigurera TinyMCE med syntaxhl.

Först la jag syntaxhl i mappen plugin i TinyMCE. Sen modifierade jag syntax/js/dialog.js enligt följande för att få den uppmärkning jag efersträvade och inte textarea som den använder sig av som standard.

textarea_output = '<pre class="code">';
textarea_output += '<code class="' + f.syntaxhl_language.value + options + '">';
textarea_output +=  f.syntaxhl_code.value;
textarea_output += '</code></pre> ';

I databasen vill jag alltså att det ska sparas så här:

<pre class="code">
<code class="xhtml">
Testing the syntaxhl plugin for TinyMCE
</code>
</pre>

Så här ser mina inställningar nu:

<TinyMce:TextArea id="tbBody"
theme="advanced"
plugins="spellchecker,safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template,pagebreak,syntaxhl"
theme_advanced_buttons1="spellchecker,save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontsizeselect|,forecolor,backcolor"
theme_advanced_buttons2="cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,preview,pagebreak,syntaxhl"
theme_advanced_toolbar_location="bottom"
theme_advanced_toolbar_align="left"
theme_advanced_path_location="bottom"
theme_advanced_resizing="false"
extended_valid_elements="pre[class]"
pagebreak_separator="<!--more-->"
force_br_newlines="false"
convert_newlines_to_brs="false"
preformatted="true"
apply_source_formatting="false"
remove_linebreaks="false"
Value='<%# Bind("Body") %>'
Rows="20"
runat="server" />

Ändingar jag gjort sen min förra konfiguration är dessa:

  • Lagt till knappen för syntaxhl i plugin och i theme_advanced_button2.
  • Lagt till pre[class] i extended_valid_elements för att editorn ska godkänna attributet.
  • Satt force_br_newline och converty_newlines_to_brs till false.
  • Satt preformatted till true.

TinyMCE har många konfigurationmöjligheter så det finns säkert mer saker att tweaka för ännu bättre resultat. Kolla även Spenser Kellis visar upp hur han har gjort sina inställningar.

 

By Jesper Lind

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.

By Jesper Lind
1