Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Utilizzare editor JavaScript con ASP.NET: TinyMCE

Integrare TinyMCE, editor JavaScript semplice e potente per fare inserire contenuti agli utenti
Integrare TinyMCE, editor JavaScript semplice e potente per fare inserire contenuti agli utenti
Link copiato negli appunti

Nei progetti Web, specie quando vogliamo consentire all'utente di inserire testi e immagini, si rivelano molto utili i cosiddetti editor JavaScript. Questi editor sostituiscono la classica casella di testo fornendo funzioni come la formattazione e allineamento del testo, inserimento di immagini, tabelle ed elenchi puntati.

Figura 1. Casella TinyMCE
Casella dell'editor TinyMCE

Questa finestra è stata ottenuta utilizzando TinyMCE, uno degli editor JavaScript più diffusi, a cui si appoggiano anche applicazioni commerciali. Si tratta di un prodotto gratuito, rilasciato con licenza LGPL. È compatibile con la quasi totalità dei browser esistenti e, essendo realizzato interamente in JavaScript, può essere integrato in siti di qualunque tipo: HTML statico, PHP, ASP, ASP.NET, JSF. In particolare, nel corso di questo articolo mostreremo come integrare TinyMCE all'interno dei propri siti Web realizzati con ASP.NET

Installazione e primo utilizzo

Dal sito ufficiale di TinyMCE è possibile scaricare il modulo principale, che costituisce l'editor Web vero e proprio, nonché di una serie di pacchetti aggiuntivi tra cui i language pack, per localizzare l'interfaccia utente nella lingua desiderata (l'italiano è pienamente supportato) e il .NET Compressor, un modulo che permette di comprimere i file JavaScript dell'editor prima di inviarli al client, in modo da risparmiare banda e, quindi, tempo di esecuzione.

Estratto l'archivio, troviamo la cartella tinymce e, al suo interno, due sottodirectory:

  • examples, contenente una serie di esempi di utilizzo dell'editor in pagine HTML statiche
  • jscripts, con i file JavaScript che realizzano tutte le funzionalità di TinyMCE

Il nostro obiettivo è integrare l'editor in un sito realizzato con ASP.NET. Apriamo dunque Visual Studio (oppure Visual Web Developer), creiamo una nuova Web Application in C#, chiamandola ProvaTinyMCE e copiamo l'intera cartella tinymce nella root del sito.

Figura 2. Struttura delle cartelle
Struttura delle cartelle

Fatto questo, "prepariamo" la pagina Default.aspx ad ospitare l'editor: tutto quello che dobbiamo fare è inserire un controllo HTML <textarea>:

<form id="form1" runat="server">
<div>
  <textarea id="txtTesto" runat="server" cols="50" rows="12"></textarea>
</div>
</form>

Aggiungiamo poi, nel tag <head>, il riferimento al file principale di TinyMCE e il codice JavaScript necessario per inizializzare il controllo:

<script type="text/javascript" 
           src="/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>

<script type="text/javascript">
tinyMCE.init(
{
  mode: "exact", 
  elements: "txtTesto", 
  theme: "advanced",
  skin: "o2k7",

  plugins: "safari,style,layer,table,advhr,advimage,advlink,emotions,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,xhtmlxtras,template",
  
  theme_advanced_buttons1: "newdocument,|,preview,print,|,cut,copy,paste,pastetext,pasteword,|,search,replace,|,undo,redo,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,visualchars,|,fullscreen,|,template,|,code",
  theme_advanced_buttons2: "styleselect,formatselect,fontselect,fontsizeselect,|,bullist,numlist,|,outdent,indent,blockquote,|,forecolor,backcolor",
  theme_advanced_buttons3: "link,unlink,anchor,image,cleanup,|,insertdate,inserttime,|,tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,media,advhr",
  
  theme_advanced_toolbar_location: "top",
  theme_advanced_toolbar_align: "left"
});
</script>

Il nucleo è rappresentato dal metodo tinyMCE.init: specificando in esso gli opportuni parametri, è possibile personalizzare nei minimi dettagli l'interfaccia e il comportamento dell'editor. Quelle mostrate nello script di esempio rappresentano solo una parte delle numerose opzioni disponibili. Per conoscerle tutte si può consultare il Wiki di TinyMCE.

Iniziamo osservando l'attributo mode:

  • mode: "exact", indica a TinyMCE di "trasformare" in editor solo l'oggetto con l'id specificato nel seguente parametro elements (in questo caso utilizziamo txtTesto, che è l'id della nostra textarea). In altre parole, lo script cerca nella pagina un oggetto con l'id indicato, quindi ne modifica lo stile e vi aggiunge le barre degli strumenti e tutte le funzionalità richieste (che analizzeremo in dettaglio tra breve)
  • mode: "textareas", ogni casella di testo (indipendentemente dal valore della proprietà elements) sarebbe stata trasformata in un editor Web

Scorrendo la lista degli attributi, arriviamo a plugins, in assoluto il più importante: esso contiene la lista delle funzionalità di cui si vuole dotare l'editor. Ognuna di esse, infatti, è implementata da uno specifico script JavaScript: con questo parametro è possibile indicare esattamente quali si vogliono utilizzare, in modo da alleggerire la pagina dell'editor, caricando solo gli script necessari. Ad esempio, nello script sopra riportato, tra i plugin è presente anche searchreplace, necessario per attivare la funzionalità Trova e Sostituisci.

Subito dopo, troviamo tre righe con gli attributi theme_advanced_buttonsX: con queste opzioni è possibile indicare quali pulsanti mostrare nelle barre degli strumenti e in quale posizione. Quelli mostrati nell'esempio sono i più comuni (il wiki ne contiene la lista completa).

Ricordiamo, infine, l'attributo content_css (non presente nell'esempio), con cui si può applicare al controllo lo stesso foglio di stile utilizzato nel sito, in modo da renderlo coerente con il resto della grafica dell'applicazione Web.

Premendo F5 su Visual Studio, mandiamo in esecuzione il sito e ci troviamo di fronte ad un editor del tutto simile a quello mostrato all'inizio dell'articolo, già funzionante. Possiamo provare a variare l'allineamento del testo, inserire immagini, cambiare il carattere: in tutte queste operazioni, l'editor si comporterà proprio come ci aspettiamo.

Salvataggio e apertura di documenti

Dopo aver creato la finestra dell'editor, dobbiamo aggiungere la possibilità di salvare e caricare i documenti creati. Per il salvataggio, TinyMCE utilizza il formato HTML: tutto quello che viene scritto nella casella di testo, gli oggetti e le formattazioni applicate sono realizzate tramite tag HTML. Ad esempio, un testo centrato e in grassetto è rappresentato dal seguente codice HTML:

<p style="text-align: center;"><strong>Prova di testo</strong></p>

Tenendo a mente questo, tutto ciò che appare nell'editor si "riflette" nella proprietà Value della <textarea>: in altre parole, tale proprietà rappresenta esattamente il testo visualizzato. Di conseguenza, per recuperare quanto digitato, è sufficiente accedere alla succitata proprietà, ad esempio in seguito alla pressione di un pulsante.

Analogamente, per caricare un documento, si deve assegnare l'HTML che lo rappresenta alla proprietà Value della <textarea>: TinyMCE si preoccuperà di tradurre automaticamente i tag per riprodurre a video la formattazione originale.

A questo punto, è necessario considerare un potenziale problema, derivante dal fatto che il contenuto della casella di testo contiene anche tag HTML. ASP.NET, per impostazione predefinita, genera un'eccezione di tipo HttpRequestValidationException quando si effettua il PostBack di una <textarea> (o TextBox) al cui interno sono presenti tag di markup, perché lo interpreta come un possibile tentativo di attacco tramite script.

Per risolvere il problema, è possibile disabilitare questo controllo inserendo la direttiva ValidateRequest="false" nel tag <%@ Page %> della pagina che contiene il nostro editor.

Questa pratica, tuttavia, è altamente sconsigliata perché, di fatto, disabilita tutti i controlli effettuati da ASP.NET sui dati inseriti nelle Web Form.

saveCallback e loadCallback

La soluzione corretta consiste nell'aggiungere un paio di parametri all'inizializzazione di TinyMCE, con cui si indica il codice da eseguire quando si salva e quando si carica un testo HTML all'interno dell'editor:

function saveCallback(element_id, html, body)
{
  html = html.replace(/</gi, "<");
  html = html.replace(/>/gi, ">");
  return html;
}

function loadCallback(type, value)
{
  if (type == "insert_to_editor")
  {
    value = value.replace(/</gi, "<");
    value = value.replace(/>/gi, ">");
  }
  return value;
}

tinyMCE.init(
{
    //...
    save_callback: "saveCallback",
    cleanup_callback: "loadCallback"
});

La routine saveCallback trasforma tutti i caratteri meggiore e minore (< e >) presenti nella casella di testo nelle rispettive entities (< e >). D'altra parte, loadCallback esegue l'operazione opposta, ripristinando i caratteri al posto delle entità. In tal modo, quando si esegue il PostBack della pagina, non essendo più presente codice considerato pericoloso, non si otterrà alcuna eccezione.

A questo punto, possiamo aggiungere alla nostra pagina di prova una TextBox e due pulsanti, rispettivamente per salvare il contenuto del controllo oppure per caricarlo dal file specificato:

<asp:TextBox ID="txtNomeFile" runat="server"></asp:TextBox>
<asp:Button ID="btnSalva" runat="server" Text="Salva" OnClick="btnSalva_Click" />
<asp:Button ID="btnCarica" runat="server" Text="Carica" OnClick="btnCarica_Click" />

Quindi, nel Code Behind della pagina, definiamo le due routine sopra indicate (per semplicità, omettiamo il controllo degli eventuali errori):

protected void btnSalva_Click(object sender, EventArgs e)
{
  using (StreamWriter sw = new StreamWriter(Path.Combine(Server.MapPath("~"), txtNomeFile.Text)))
  {
    sw.Write(HttpUtility.HtmlDecode(txtTesto.Value));
  }
}

protected void btnCarica_Click(object sender, EventArgs e)
{
  txtTesto.Value = File.ReadAllText(Path.Combine(Server.MapPath("~"), txtNomeFile.Text));
}

Notiamo che, nel metodo btnSalva_Click, utilizziamo la funzione HttpUtility.HtmlDecode per ritrasformare i codici < e > nei corrispondenti simboli < e > prima di effettuare il salvataggio vero e proprio: in tal modo, nel file viene salvato un testo HTML pronto per essere visualizzato, ad esempio all'interno di un controllo Literal. Il caricamento, invece, come accennato prima consiste semplicemente nel leggere il file ed assegnare il suo contenuto alla proprietà Value della textarea.

Figura 3. Esempio in cui i file sono letti e scritti nella root del sito
esempio in cui i file sono letti e scritti nella root del sito

Migliorare l'uso di TinyMCE

Con gli strumenti presentati finora siamo in grado di integrare un editor di testi avanzato in un sito ASP.NET. Ci sono però altri aspetti che meritano di essere menzionati.

Anzitutto notiamo che l'interfaccia dell'editor è in inglese. Se vogliamo utilizzare lingue diverse, è necessario scaricare il language pack corrispondente, quindi estrarre il file ZIP nella cartella tinymce/jscripts/tiny_mce. Fatto questo, possiamo indicare la lingua desiderata nella solita istruzione di inizializzazione. Ad esempio, per ottenere l'editor in lingua italiana, il codice da aggiungere è:

tinyMCE.init({
    //...
    language: "it"
});

Altra funzione degna di nota è il .NET Compressor, già citato all'inizio di questo articolo. Questo modulo comprime tutti i file JavaScript che compongono l'editor in un singolo archivio ZIP, riducendo notevolmente il numero di richieste al Web server e la quantità di dati trasferiti, permettendo così di caricare tutti i controlli più velocemente.

Per attivarlo, si deve scaricare il pacchetto Compressor .NET dalla pagina di download di TinyMCE, e copiare i file tiny_mce_gzip.aspx e tiny_mce_gzip.js nella posizione tinymcejscriptstiny_mce.

Nell'archivio ZIP troviamo inoltre il file binICSharpCode.SharpZipLib.dll, ovvero la libreria SharpZipLib, anch'essa gratuita, necessaria per gestire la compressione/decompressione dell'editor; tale file va copiato nella cartella bin della Web Application. La versione dell'assembly inclusa nel Compressor .NET non è però l'ultima disponibile, quindi di consiglia di scaricare manualmente la più recente.

A questo punto, nella pagina .aspx contenente l'editor, si deve sostituire il riferimento allo script principale di TinyMCE con quello appena copiato. In altre parole, l'istruzione:

<script type="text/javascript" src="/tinymce/jscripts/tiny_mce/tiny_mce.js"></script>

Diventa:

<script type="text/javascript" src="/tinymce/jscripts/tiny_mce/tiny_mce_gzip.js"></script>

Infine, sotto tale istruzione si deve aggiungere un altro script di inizializzazione, simile a quello visto in precedenza, ma stavolta relativo al compressore:

<script type="text/javascript">
tinyMCE_GZ.init(
{
  plugins: "safari,style,layer,table,advhr,advimage,advlink,emotions,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,xhtmlxtras,template",
  themes: 'advanced',
  languages: 'it',
  disk_cache: true,
  debug: false
});
</script>

Il resto del codice JavaScript non deve essere modificato. È importante che l'attributo plugins di tinyMCE_GZ.init contenga gli stessi valori presenti nell'omonimo elemento dell'istruzione tinyMCE.init, dal momento che questa lista indica quali sono gli script Java da comprimere.

Se non sono stati commessi errori, premendo F5 otterremo il nostro editor Web: nulla è cambiato dal punto di vista dell'utente finale; tuttavia, se proviamo a visualizzare la cartella tinymcejscriptstiny_mce, noteremo che essa contiene un file di nome tiny_mce_XXX.gz (dove XXX è un codice esadecimale), contenente la versione compressa degli script necessari al funzionamento di TinyMCE.

Attenzione alle Master Page

Abbiamo detto che TinyMCE, quando impostato con l'opzione mode: "exact", utilizza l'id dell'oggetto indicato in elements per applicare ad esso lo stile dell'editor. Tuttavia, se il controllo è inserito in una pagina che ha una Master Page, il suo id viene automaticamente modificato da ASP.NET con l'aggiunta del riferimento alla pagina master.

In questo caso, quindi, lo script di inizializzazione di TinyMCE non è in grado di trovare l'oggetto a cui applicare lo stile. In una situazione del genere, invece del semplice id si deve utilizzare il ClientID del controllo, come nel codice seguente:

tinyMCE.init(
{
  mode: "exact",
  elements: "<%= txtTesto.ClientID %>",
  //...
});

Validare l'input

Poiché il controllo utilizzato per l'editor è un oggetto standard di ASP.NET (ovvero, nel nostro caso, una textarea), ad esso è possibile associare eventuali altri controlli, come si farebbe con un qualunque altro oggetto: ad esempio, si può inserire un RequiredFieldValidator per assicurarsi che sia stato digitato del testo nella casella prima di avviare il salvataggio:

<textarea id="txtTesto" runat="server" cols="50" rows="12"></textarea>
<asp:RequiredFieldValidator ID="rfvTesto" runat="server" 
                            ErrorMessage="Digitare il testo" 
                            ControlToValidate="txtTesto">
</asp:RequiredFieldValidator>

Avendo aggiunto questo controllo, si deve modificare la dichiarazione del pulsante btnSalva perché il salvataggio sia in grado di gestire correttamente la presenza del validatore: dobbiamo aggiungere l'esecuzione di un particolare metodo JavaScript alla pressione del pulsante, utilizzando l'attributo OnClientClick. Inoltre, conviene impostare la proprietà CausesValidation del pulsante btnCarica su false, perché quando si carica un documento esistente, non dobbiamo verificare che la casella di testo sia vuota:

<asp:Button ID="btnSalva" runat="server" Text="Salva" OnClick="btnSalva_Click"  
            OnClientClick="tinyMCE.triggerSave(false,true);" />

<asp:Button ID="btnCarica" runat="server" Text="Carica" OnClick="btnCarica_Click"
            CausesValidation="false" />

Diritti e permessi

Infine, una nota relativa alla pubblicazione di siti Web contenenti TinyMCE. Affinché il salvataggio dei documenti avvenga correttamente, è necessario assegnare all'account Web definito nel Web server il diritto di scrittura nella cartella in cui si vogliono memorizzare i dati.

Analogamente, se si utilizza il .NET Compressor, si deve garantire il diritto di scrittura anche nella cartella tinymcejscriptstiny_mce, perché in essa viene salvata la versione compressa degli script JavaScript.

Ti consigliamo anche