2

So I am having a nightmare trying to run ckeditor in wpf webbrowser control. Custom built ckeditor that our company is using for their websites, throws an error that points to nowhere.. line 0, yet it works everywhere else, including IE. Basic package, semi loads, but throws undefined error and stay greyed out in loading phase. This is with latest ck editor 4.7. I've tried using version 3.6 with which nothing happens at all, ckeditor throws no error, but doesnt load either ( works fine outside of wpf browser).

Here is some basic html code that I inject into the wpfbrowser.

            WebBrowser webBrowser = dependencyObject as WebBrowser;
        if (webBrowser != null)
        { 
            var html = "<head>" +

                       "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />" +
                       "<meta charset=\"UTF-8\">" +

                      // $"<script type=\"text/javascript\" src=\"{ResourceDir}MathJax\\MathJax.js?config=MML_HTMLorMML,default\"></script>" +
                       $"<script type=\"text/javascript\" src=\"{ResourceDir}ckeditor\\ckeditor.js\"></script>" +
                       $"<script type=\"text/javascript\" src=\"{ResourceDir}JavaScript\\essay.js\"></script>" +
                       // $"<link rel=\"stylesheet\" type=\"text/css\" href=\"{ResourceDir}\\CSS\\main.css\">" +

                       "</head>" +

                       "<body>" +
                       "         <form>\r\n" +
                       "            <textarea name=\"editor\" id=\"editor\" rows=\"10\" cols=\"80\">\r\n" +
                                    $"Hello World!" + /*{e.NewValue}*/
                       "            </textarea>\r\n" +
                       "        </form>"+
                       " <button onclick=\"ReplaceEditor()\">Click me</button> " +
                       "</body>";

            webBrowser.NavigateToString(html);

Other javascript such as MathJax and so on works just fine, please ignore the way I build HTML, its not relevant now.

This is essay.js content

function ReplaceEditor() {
CKEDITOR.replace('editor');
}
window.onerror = function (message, url, lineNumber) {
    window.external.GetErrors(message, url, lineNumber);
}

catching errors doesnt help much as it returns same line 0 char 0 that webbrowser throws for all errors . Any help appreciated, from what I've read it should be working as people made it work before.

Aistis Taraskevicius
  • 781
  • 2
  • 10
  • 31
  • Been there. See if [this](https://stackoverflow.com/a/18333982/1768303) helps. – noseratio Aug 07 '17 at 20:21
  • Sadly issue still persists, also those registry tweaks, broke my other workarounds for horrible wpf webbrowser, thus had to undo them, and would prefer not writing anything to registry as app will be externally used. – Aistis Taraskevicius Aug 08 '17 at 08:41
  • I was able to to use CKEditor 4.5.x with such host worry-free. Note it writes to HKCU, so no admin rights are required. Can't tell about later CKEditor versions though. – noseratio Aug 08 '17 at 10:52
  • I've just tried with 4.5.11( only 4.5 available) and when I manually load editor this time, textarea disappears and ckeditor doesnt appear, ther are no errors, but it doesn't work. Also seems registry changes requires application to restart to take effect.As browses has a funny way of loading. Any chance you have source code or examples how you've done this, maybe I am making a small mistake somewhere along the road. – Aistis Taraskevicius Aug 08 '17 at 15:38
  • I can't share that code, but I can give some hints, like you should make sure the editor host page that you load into WebBrowser is treated as an HTML5 page, so make sure it has this: ` ... ` – noseratio Aug 08 '17 at 19:46
  • then make sure you intialize CKEditor properly on that page, e.g., `$(document).ready(function () { CKEDITOR.domReady(function () { CKEDITOR.replace("editorDivElement", { docType: ' ', on: { instanceReady: function (evt) { var editor = evt.editor; alert("CKEditor ready"); } } }); }); });` – noseratio Aug 08 '17 at 19:52
  • I have these things, btw CKEditor does not require jquery does it, I could not find anything stating it does. Also I am currently initializing it with button click just to ensure everything loaded properly. I'm not sure what could else be wrong :/ – Aistis Taraskevicius Aug 10 '17 at 10:22
  • I've used your function to initialize ckeditor, added jquery too, used your host and still it doesnt work... if you can make a simple application that just runs ckeditor via browser I'll be super happy to accept your answer. – Aistis Taraskevicius Aug 10 '17 at 12:01

1 Answers1

2

I guess I know what's wrong, you're using NavigateToString, which produces an about:blank page. This is not going to work with CKEditor, same as a file://-based editor host page. You need a real http/https-based page, which can be as simple as referencing CKEditor from their CDN (a very reliable Amazon-hosted one):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>CKEditor</title>
        <script src="https://cdn.ckeditor.com/4.7.1/standard/ckeditor.js"></script>
    </head>
    <body>
        <textarea name="editor1"></textarea>
        <script>
            CKEDITOR.replace( 'editor1' );
        </script>
    </body>
</html>

Below is simple example loading CKEditor Standard Editor Example into a WPF WebBrowser control, it works without any issues for me.

If you can't have your own dedicated online page to host CKEditor, you might need to run an in-app single-page web server to serve it via http://localhost. There're many examples out there on how to do it (e.g. this one).

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;

namespace WpfWebEditor
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        WebBrowser _webBrowser;

        static MainWindow()
        {
            var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
            SetBrowserFeatureControlKey("FEATURE_BROWSER_EMULATION", fileName, GetBrowserEmulationMode());
        }

        public MainWindow()
        {
            InitializeComponent();
            this.Loaded += MainWindow_Loaded;

            _webBrowser = new WebBrowser();
            this.Content = _webBrowser;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            _webBrowser.Navigate("https://nightly.ckeditor.com/standard/samples/");
        }

        private static void SetBrowserFeatureControlKey(string feature, string appName, uint value)
        {
            using (var key = Registry.CurrentUser.CreateSubKey(
                String.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature),
                RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);
            }
        }

        private static UInt32 GetBrowserEmulationMode()
        {
            int browserVersion = 7;
            using (var ieKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer",
                RegistryKeyPermissionCheck.ReadSubTree,
                System.Security.AccessControl.RegistryRights.QueryValues))
            {
                var version = ieKey.GetValue("svcVersion");
                if (null == version)
                {
                    version = ieKey.GetValue("Version");
                    if (null == version)
                        throw new ApplicationException("Microsoft Internet Explorer is required!");
                }
                int.TryParse(version.ToString().Split('.')[0], out browserVersion);
            }

            UInt32 mode = 11000; // Internet Explorer 11. Webpages containing standards-based !DOCTYPE directives are displayed in IE11 Standards mode. Default value for Internet Explorer 11.
            switch (browserVersion)
            {
                case 7:
                    mode = 7000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE7 Standards mode. Default value for applications hosting the WebBrowser Control.
                    break;
                case 8:
                    mode = 8000; // Webpages containing standards-based !DOCTYPE directives are displayed in IE8 mode. Default value for Internet Explorer 8
                    break;
                case 9:
                    mode = 9000; // Internet Explorer 9. Webpages containing standards-based !DOCTYPE directives are displayed in IE9 mode. Default value for Internet Explorer 9.
                    break;
                case 10:
                    mode = 10000; // Internet Explorer 10. Webpages containing standards-based !DOCTYPE directives are displayed in IE10 mode. Default value for Internet Explorer 10.
                    break;
                default:
                    // use IE11 mode by default
                    break;
            }

            return mode;
        }
    }
}
noseratio
  • 59,932
  • 34
  • 208
  • 486
  • 1
    Cheers, this actually works, though it does not require setting any browser features ( though I can see how this might be helpful. Does not require hosting local http pages. Same can be achieved by creating new URI to local html page and navigating to it. I am contemplating if I should write up an answer, or accept yours as without your post I would never thought of that. – Aistis Taraskevicius Aug 11 '17 at 09:17
  • @AistisTaraskevicius, glad it helped. I'm surprised to know it works against a `file://`-based with page too. I don't think it did a few CKE iterations ago, I'm sure we tried that. Anyhow, feel free to post a detailed answer, so others can benefit from it. – noseratio Aug 11 '17 at 11:17