UpdatePanel and Maiking the CKEditor come back

May 4, 2010 at 9:43 PM

Good afternoon,

 

We are having a similar problem to the one described in this thread (http://syrinxckeditor.codeplex.com/Thread/View.aspx?ThreadId=71706), but ours was a bit trickier and so I thought it deserved its own thread.

 

We use the CKEditor and the Syrinx wrapper to add an editor to the page, but during a postback (partial postback using the UpdatePanel) we will sometimes make the CKEditor go away, replace it with a plain text box, and then on some future partial postback, we reshow the editor.   Once the editor is reshown, it has its text set to the correct value, but then displays an empty editor.

Here are the pertinent changes made in the wrapper code:

 public static void setupScripts(Page page)
        {
            //page.ClientScript.RegisterClientScriptInclude("Swaf.CkEditorMain", page.ResolveUrl(CkEditorJS));
            ScriptManager.RegisterClientScriptInclude(page, typeof(CkEditor), "Swaf.CkEditorMain", page.ResolveUrl(CkEditorJS));  //NRChange - using ScriptManager for partial postback support
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            setupScripts(Page);

            //NRChange - Added to handle partial postbacks
            ScriptManager.RegisterOnSubmitStatement(this, typeof(CkEditor), "CKEditorAjaxOnSubmit_" + ClientID, string.Format("try{{var e = CKEDITOR.instances.{0}; if (e != null)e.updateElement();}}catch(err){{}};", ClientID));
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.Write("<textarea id='{0}' name='{1}'></textarea>", ClientID, UniqueID);
            //writer.Write("<script type='text/javascript'>var t=\"{2}\";var e = CKEDITOR.instances.{0};if(e != null)CKEDITOR.remove(e);CKEDITOR.replace('{0}'{1}).setData(t);</script>",
            //    ClientID, buildConfigOptions(), getTextForRender());

            //NRChange - using ScriptManager for partial postback support
            ScriptManager.RegisterStartupScript(this, typeof(CkEditor), "startup" + ClientID, ""
                    + "var t=\"" + getTextForRender() + "\";"
                    + "var e = CKEDITOR.instances." + ClientID + ";"
                    + " if(e != null)CKEDITOR.remove(e); "
                    + "CKEDITOR.replace('" + ClientID + "'" + buildConfigOptions() + ").setData(t);"
                //+ "var newEditor = CKEDITOR.instances." + ClientID + ";"
                //+ "alert('text set to: ' + t);"
                //+ "alert('current text: ' + newEditor.getData());"
                    + "", true);
        }

 

If you uncomment the three lines in the RegisterStartupScript() you will see that the instance is set correctly and does have the correct text. 

 

We had been working under the impression that the ClientID being the same may affect it, but we did some testing with making sure it was uniuque each time, and that did not solve any problems.

 

I also set up a sample project that displays exactly the problem we are having in hopefully the simplest terms as possible.  You can find the zipped folder here:

 

http://www.netreach.com/ckeditor_concern/

 

 

Sep 16, 2010 at 4:30 PM

Hey all,

 

I just wanted to post the solution to the dilemma of adding the control back into the tree, once it has been removed on a partial post back.

With help of the thread and code from here http://cksource.com/forums/viewtopic.php?t=15882the problem has been solved.

Thank you Daniel Cohen Gindi danielgindi |at| gmail |dot| com

Here is the new PreRender and Render code

protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            setupScripts(Page);
            if (Visible)
            {
                //The following scripts were first written by Daniel Cohen Gindi danielgindi@gmail.com and posted to tghe 
                //  CKEditor forums for use as part of the ASP.Net control replacement for FCKEditorControl2.  See the thread at
                //  http://cksource.com/forums/viewtopic.php?t=15882  for full discussion

                var onSubmitScript = string.Format(
                             @"if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                        var e=document.getElementById('{0}'); 
                                        if(e) {{
                                            var i=CKEDITOR.instances.{0}; 
                                            e.value=i.getData();
                                            i.fire('destroy'); 
                                        }}
                                }};",
                             ClientID);
                ScriptManager.RegisterOnSubmitStatement(this, typeof(CkEditor), "CKEditorAjaxOnSubmit_" + ClientID, onSubmitScript);

                var startupScript = string.Format(
                            @"document.getElementById('{0}').dispose=function(){{
                                if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                    var e=document.getElementById('{0}');
                                    if(e) {{
                                        var i=CKEDITOR.instances.{0}; 
                                        CKEDITOR.remove(i);
                                    }}
                                }}
                            }};", ClientID);
                ScriptManager.RegisterStartupScript(
                    this,
                    typeof(CkEditor),
                    ClientID + @"_Dispose",
                    startupScript,
                    true);

                var instanceScript = string.Format(
                            @" if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{1}) {{CKEDITOR.instances.{1}.destroy();}}
                               var text = '{0}';
                               CKEDITOR.replace('{1}'{2}).setData(text);",
                               getTextForRender(),
                               ClientID,
                               buildConfigOptions());

                ScriptManager.RegisterStartupScript(this, typeof(CkEditor), "startup_" + ClientID, instanceScript, true);
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.Write("<textarea id='{0}' name='{1}'></textarea>", ClientID, UniqueID);          
        }
        

Sep 21, 2010 at 2:35 PM

really nice, It works. thank you

Sep 22, 2010 at 11:33 AM
Edited Sep 22, 2010 at 11:50 AM

I added some code in order to add saving event enabled on server side...

        public event EventHandler<EventArgs> SaveClicked;




        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            var hf = new HiddenField
                         {
                             ID = "Save",
                             Value = "false"
                         };
            hf.ValueChanged += OnSaveClicked;
            Controls.Add(hf);
        }



        private void OnSaveClicked(object sender, EventArgs e)
        {
            var hf = (HiddenField) sender;
            bool saving;
            if(bool.TryParse(hf.Value, out saving) && saving
                && SaveClicked != null)
            {
                SaveClicked(this, EventArgs.Empty);
            }
            hf.Value = "false";
        }


        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            setupScripts(Page);
            if (Visible)
            {
                //The following scripts were first written by Daniel Cohen Gindi danielgindi@gmail.com and posted to tghe 
                //  CKEditor forums for use as part of the ASP.Net control replacement for FCKEditorControl2.  See the thread at
                //  http://cksource.com/forums/viewtopic.php?t=15882  for full discussion

                var onSubmitScript = string.Format(
                             @"if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                        var e=$get('{0}'); 
                                        if(e) {{
                                            var i=CKEDITOR.instances.{0}; 
                                            e.value=i.getData();
                                            i.fire('destroy'); 
                                        }}
                                }};",
                             ClientID);
                ScriptManager.RegisterOnSubmitStatement(this, typeof(CkEditor), "CKEditorAjaxOnSubmit_" + ClientID, onSubmitScript);

                var startupScript = string.Format(
                            @"$get('{0}').dispose=function(){{
                                if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                    var e=$get('{0}');
                                    if(e) {{
                                        var i=CKEDITOR.instances.{0}; 
                                        CKEDITOR.remove(i);
                                    }}
                                }}
                            }};", ClientID);
                ScriptManager.RegisterStartupScript(
                    this,
                    typeof(CkEditor),
                    ClientID + @"_Dispose",
                    startupScript,
                    true);

                var instanceScript = string.Format(
                    @" 
                    if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{1}) {{
                        CKEDITOR.instances.{1}.destroy();
                    }}
                    var text = '{0}';
                    CKEDITOR.replace('{1}'{2}).setData(text);
                    var e = CKEDITOR.instances.{1};
                    if(e){{
                        e.on('beforeCommandExec', function(evt) {{ 
                            if (evt.data.name=='save') {{
                                $get('{1}_Save').value='true';
                            }}
                        }});
                    }}
                    ",
                               getTextForRender(),
                               ClientID,
                               buildConfigOptions());

                ScriptManager.RegisterStartupScript(this, typeof(CkEditor), "startup_" + ClientID, instanceScript, true);
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);
            writer.Write("<textarea id='{0}' name='{1}'></textarea>", ClientID, UniqueID);
        }

        public event EventHandler<EventArgs> SaveClicked;


        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            var hf = new HiddenField
                         {
                             ID = "Save",
                             Value = "false"
                         };
            hf.ValueChanged += OnSaveClicked;
            Controls.Add(hf);
        }



        private void OnSaveClicked(object sender, EventArgs e)
        {
            var hf = (HiddenField) sender;
            bool saving;
            if(bool.TryParse(hf.Value, out saving) && saving
                && SaveClicked != null)
            {
                SaveClicked(this, EventArgs.Empty);
            }
            hf.Value = "false";
        }


        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            setupScripts(Page);
            if (Visible)
            {
                //The following scripts were first written by Daniel Cohen Gindi danielgindi@gmail.com and posted to tghe 
                //  CKEditor forums for use as part of the ASP.Net control replacement for FCKEditorControl2.  See the thread at
                //  http://cksource.com/forums/viewtopic.php?t=15882  for full discussion

                var onSubmitScript = string.Format(
                             @"if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                        var e=$get('{0}'); 
                                        if(e) {{
                                            var i=CKEDITOR.instances.{0}; 
                                            e.value=i.getData();
                                            i.fire('destroy'); 
                                        }}
                                }};",
                             ClientID);
                ScriptManager.RegisterOnSubmitStatement(this, typeof(CkEditor), "CKEditorAjaxOnSubmit_" + ClientID, onSubmitScript);

                var startupScript = string.Format(
                            @"$get('{0}').dispose=function(){{
                                if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{0}) {{
                                    var e=$get('{0}');
                                    if(e) {{
                                        var i=CKEDITOR.instances.{0}; 
                                        CKEDITOR.remove(i);
                                    }}
                                }}
                            }};", ClientID);
                ScriptManager.RegisterStartupScript(
                    this,
                    typeof(CkEditor),
                    ClientID + @"_Dispose",
                    startupScript,
                    true);

                var instanceScript = string.Format(
                    @" 
                    if (CKEDITOR && CKEDITOR.instances && CKEDITOR.instances.{1}) {{
                        CKEDITOR.instances.{1}.destroy();
                    }}
                    var text = '{0}';
                    CKEDITOR.replace('{1}'{2}).setData(text);
                    var e = CKEDITOR.instances.{1};
                    if(e){{
                        e.on('beforeCommandExec', function(evt) {{ 
                            if (evt.data.name=='save') {{
                                $get('{1}_Save').value='true';
                            }}
                        }});
                    }}
                    ",
                               getTextForRender(),
                               ClientID,
                               buildConfigOptions());

                ScriptManager.RegisterStartupScript(this, typeof(CkEditor), "startup_" + ClientID, instanceScript, true);
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);
            writer.Write("<textarea id='{0}' name='{1}'></textarea>", ClientID, UniqueID);
        }

blic event EventHandler<EventArgs> SaveClicked;
Sep 22, 2010 at 9:15 PM

I grabbed the lastest version of the wrapper control.

In CkEditor.cs I replaced the OnPreRender and Render events with the code from this thread. 

When trying to build the project so I can use the new .DLL, I get the following error:

The name 'ScriptManager' does not exist in the current context

I have not altered any other code in any manner.  Am I missing any other steps?  If so, can someone post a step-by-step walk through so people are coming in fresh to this problem can easily solve it?

Thanks!

Sep 23, 2010 at 6:43 AM

It seems you need to install Ajax Control Toolkit. (3dll are necessary to make it run: AjaxControlToolkit.dll, System.web.Extension.dll and System.Web.Extensions.Design.dll).

When installing the toolkit, you should have a project template which prepare for you a clean project with ajax enabled (project templates are the kind of projects which are available from file>new project)

Anyway, if you know nothing about asp.net ajax framework (ajax control toolkit), I am not sure this code is for you...

Sep 23, 2010 at 1:54 PM

It appears I only needed to add the System.web.Extension.dll to the SyrinxCkEditor project.  After I did that the code would then compile and I could use the .dll in my project.  I am using AJAX, but of course that reference is in my project that actually uses AJAX.

So if your coming in late to this discussion like I was (I arrived here from various forums with various info over various timespans) and just want this to work.  Do the following:

1) grab the source code from this site

2) add the above code to CkEditor.cs

3) add the System.web.Extension.dll to your project if need be

4) build in VS and use the new .dll in your project

 

Thanks to those who got this to work.  Much appreciated.