製作 CKEdiotr 的 Server Control

  • 2943
  • 0
  • 2009-12-28

製作 CKEdiotr 的 Server Control

點部落(dotblogs) 的標籤: , ,

今天把 CKEditor 做成 Server Control,雖然有點畫蛇添足,因為要用使用CKEditor並不麻煩,做完後感覺好像載入的反應有慢一點點耶……會是我的錯覺嗎?

先來看看要怎樣才能再 ASP.NET 中使用 CKEditor ,我的 Sample 是直接使用 textarea 標籤,也可以使用C# <asp:TextBox> 將 TextMode設定成 MultiLine。

  1. 到 CKEditor 官方網站下載 CKEditor
  2. 使用建立一個網站
  3. 將下載下來的 CKEditor 壓縮檔,解壓縮到網站目錄
  4. 修改 Default.aspx 內容,增加下面二項內容:
    Head區段加入 
    <script type="text/javascript" src="/ckeditor/ckeditor.js"></script> 
    Form1裡面加入一個Textarea

        <textarea id="editor1" name="editor1" rows="10" cols="80"></textarea>
        <script type="text/javascript">
            var editor = (typeof CKEDITOR == 'undefined' ? null : CKEDITOR.replace('editor1'));
        </script>

    Default.aspx 完整內容如下:
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebDemo.Default" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
        <script type="text/javascript" src="/ckeditor/ckeditor.js"></script>
        <script type="text/javascript" src="/ckfinder/ckfinder.js"></script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
        
        <textarea id="editor1" name="editor1" rows="10" cols="80"></textarea>    
        
        <script type="text/javascript">        
            var editor = (typeof CKEDITOR == 'undefined' ? null : CKEDITOR.replace('editor1'));
        </script>
        
        </div>
        </form>
    </body>
    </html>
  5. 執行後即可看到 textarea 套用 CKEditor 了

所以最基本的方式就是引用 ckeditor.js,加入一個 Textarea ,然後在網頁載入完成時將 textarea 套上 CKEditor 的功能。
因為看起來不難搞定,所以就來動手做個Server Control 吧!

  1. 首先建立一個伺服器控制項專案
    newPrj_05
  2. 更改一下 ServerControl1.cs 檔案名稱,換成「Editor.cs」
     saveas
  3. 加入參考以下組件
    System.Drawing
    System.Design
  4. Editor.cs 檔案內容換成下面程式
    using System;
    using System.ComponentModel;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Drawing;
    using System.Drawing.Design;
    
    namespace CKEditor
    {
        
        [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")] 
        [ParseChildren(true,"Text")]
        [DefaultProperty("Text")]
        [ToolboxData("<{0}:Editor runat=server></{0}:Editor>")]
        public class Editor : WebControl,IPostBackDataHandler
        {
    
            #region Properties

    [Bindable(true)]
    [Category("Appearance")]
    [DefaultValue("")]
    [Localizable(true)]
    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public string Text
    {
    get
    {
    String s = (String)ViewState["Text"];
    string value=((s == null) ? "[" + this.ID + "]" : s);
    return HttpUtility.HtmlDecode(value);
    }

    set
    {
    ViewState["Text"] = HttpUtility.HtmlEncode(value);
    }
    }


    [Bindable(true),
    Category("Appearance"),
    Description("CKEditor ScriptPath."),
    DefaultValue("~/ckeditor/cdeditor.js"),
    Localizable(false)]
    [Editor("System.Web.UI.Design.UrlEditor", typeof(UITypeEditor)), UrlProperty]
    public string CKEditorScriptPath
    {
    get
    {
    object o = ViewState["CKEditorScriptPath"];

    if (o == null)
    o = System.Configuration.ConfigurationSettings.AppSettings["CKEditor:CKEditorScriptPath"];

    return (o == null ? "~/ckeditor/ckeditor.js" : (string)o);
    }
    set { ViewState["CKEditorScriptPath"] = value; }
    }

    [Category("Appearence")]
    [DefaultValue("10")]
    public int Rows
    {
    get { object o = ViewState["Rows"]; return (o == null ? (int)10 : (int)o); }
    set { ViewState["Rows"] = value; }
    }

    [Category("Appearence")]
    [DefaultValue("80")]
    public int Cols
    {
    get { object o = ViewState["Cols"]; return (o == null ? (int)80 : (int)o); }
    set { ViewState["Cols"] = value; }
    }

    [DefaultValue("")]
    public string ClassName
    {
    get { return ViewState["ClassName"] as string; }
    set { ViewState["ClassName"] = value; }
    }

    [TypeConverter(typeof(WebColorConverter))]
    [DefaultValue("#CCCCCC")]
    public Color UIColor
    {
    get { object o = ViewState["UIColor"]; return (o == null ? Color.LightGray : (Color)o); }
    set { ViewState["UIColor"] = value; }
    }

    [Category("CKEdiotr")]
    [DefaultValue("")]
    public string ToolBar
    {
    get { object o = ViewState["ToolBar"]; return (o == null ? "" : (string)o); }
    set { ViewState["ToolBar"] = value; }
    }

    //[DefaultValue("v2")]
    //public SkinType Skin
    //{
    // get { object o = ViewState["Skin"]; return (o == null ? SkinType.v2 : (SkinType)o); }
    // set { ViewState["Skin"] = value; }
    //}

    [Category("CKEdiotr")]
    [DefaultValue(false)]
    public bool Disabled
    {
    get { object o = ViewState["Disabled"]; return (o == null ? false : (bool)o); }
    set { ViewState["Disabled"] = value; }
    }

    [Category("CKFinder")]
    [DefaultValue(false)]
    public bool CKFinderEnable
    {
    get { object o = ViewState["CKFinderEnable"]; return (o == null ? false : (bool)o); }
    set { ViewState["CKFinderEnable"] = value; }
    }

    [Bindable(true)]
    [Category("CKFinder")]
    [DefaultValue("~/ckfinder/ckfinder.js")]
    [Editor("System.Web.UI.Design.UrlEditor", typeof(UITypeEditor)), UrlProperty]

    public string CKFinderScriptPath
    {
    get
    {
    object o = ViewState["CKFinderScriptPath"];

    if (o == null)
    o = System.Configuration.ConfigurationSettings.AppSettings["CKFinder:ScriptPath"];

    return (o == null ? "~/ckfinder/ckfinder.js" : (string)o);
    }
    set { ViewState["CKFinderScriptPath"] = value; }
    }



    private string GetFolderName(string urlPath)
    {
    return urlPath.Substring(0,urlPath.LastIndexOf('/'));
    }


    public string CreateHtml()
    {

    System.Text.StringBuilder initScript = new StringBuilder();
    initScript.AppendLine("<script type=\"text/javascript\">");
    initScript.AppendLine("//<![CDATA[");
    initScript.AppendLine("var editor" + this.UniqueID + " = CKEDITOR.replace( '" + this.UniqueID + "',");
    initScript.AppendLine("{");
    //initScript.AppendLine("skin : '" + this.Skin.ToString() + "'");//v2, office2003 , kama
    initScript.AppendLine("uiColor: '" + ColorTranslator.ToHtml(this.UIColor) + "'");
    initScript.AppendLine(",enterMode : Number( 2)");
    initScript.AppendLine(",shiftEnterMode : Number( 1)");
    if (this.ToolBar.Length > 0)
    {
    initScript.AppendLine(",toolbar_TadToolbar :" + this.ToolBar);
    }
    initScript.AppendLine("}");
    initScript.AppendLine(");");
    if (this.CKFinderEnable)
    {
    initScript.AppendLine("CKFinder.SetupCKEditor(editor" + this.UniqueID + ", '" + this.Page.ResolveUrl(GetFolderName((this.CKFinderScriptPath))) + "');");
    }

    initScript.AppendLine("//]]>");
    initScript.AppendLine("</script>");

    return initScript.ToString();
    }

    #endregion

    protected override void OnPreRender(EventArgs e)
    {


    ClientScriptManager cs = this.Page.ClientScript;

    if (!cs.IsClientScriptBlockRegistered(typeof(Page), "ckeditorScript"))
    {
    cs.RegisterClientScriptBlock(typeof(Page), "ckeditorScript",
    "<script type='text/javascript' src='" + this.Page.ResolveUrl(this.CKEditorScriptPath) + "'></script>");
    }
    if (!cs.IsClientScriptBlockRegistered(typeof(Page), "ckfinderScript"))
    {
    cs.RegisterClientScriptBlock(typeof(Page), "ckfinderScript",
    "<script type='text/javascript' src='" + this.Page.ResolveUrl(this.CKFinderScriptPath) + "'></script>");
    }

    base.OnPreRender(e);
    }

    protected override void Render(HtmlTextWriter writer)
    {
    string _ClassName = this.ClassName;

    if (_ClassName != null && _ClassName.Length > 0)
    _ClassName = " class=\"" + _ClassName + "\"";

    //base.Render(writer);
    writer.Write(string.Format("<textarea id='{0}' name='{0}'{1} >{2}</textarea>", this.UniqueID, _ClassName ,this.Text));

    writer.Write(this.CreateHtml());

    }


    #region For postback

    public event EventHandler TextChanged;


    public virtual bool LoadPostData(string postDataKey,
    System.Collections.Specialized.NameValueCollection postCollection)
    {

    String presentValue = Text;
    String postedValue = postCollection[postDataKey];

    if (presentValue == null || !presentValue.Equals(postedValue))
    {
    //base.ValidateEvent(postDataKey);
    Text = postedValue;
    return true;
    }

    return false;
    }


    public virtual void RaisePostDataChangedEvent()
    {
    OnTextChanged(EventArgs.Empty);
    }


    protected virtual void OnTextChanged(EventArgs e)
    {
    if (TextChanged != null)
    TextChanged(this, e);
    }

    #endregion
    }
    }
     
  5. 在網站中,將這個專案加入參考,或是將專案編譯成 Dll 檔之後,將 CKEditor.dll 加入參考,就能在工具箱看到Editor控制項了!
    toolbox
  6. 使用時只要拖拉到網頁中,能使用了!

 

這個Server control 自己有些屬性已經加上去了,skin 屬性我是建立一個 enum skintype{v2,office2003,kama},應該要依skin目錄中的名稱列出選項,但是我沒想到設計階段要如何製作,所以先註解,如果有需要的人可以再花點時間加上ToolBar或是其它設定項目。

 

2009/12/27 補充:

在OnPreRender加入以下程式碼,可以不用將表單驗證關閉,我只有使用 IE 和 Firefox,所以不保證其它瀏覽器正常喔!

if (!cs.IsOnSubmitStatementRegistered(typeof(Page), "HtmlEncodeDecodeScript")) { /*ie 傳回contentWindow.document,firefox 傳回 contentDocument*/ string script = @" function htmlEncode(str) { var div = document.createElement('div'); var text = document.createTextNode(str); div.appendChild(text); return div.innerHTML; } var w = document.getElementById('cke_contents_"+ this.UniqueID + @"').firstChild; if (w.nodeName == 'TEXTAREA') { w.value=htmlEncode(w.value); } else{ var d=(w.contentDocument == undefined?w.childNodes[1].contentWindow.document:w.contentDocument); d.body.innerHTML=htmlEncode(d.body.innerHTML); } "; cs.RegisterOnSubmitStatement(typeof(Page), "HtmlEncodeDecodeScript",script); }


2009/12/28 補充:

今天使用時發現上面的作法當文子框輸入含有單引號會出錯

範例程式下載

-------
一點一滴堆砌著夢想的執行者