MDo*_*MDo 16 asp.net-mvc ckeditor singlepage knockout.js
我有一个涉及KnockoutJS和CKEditor的情况.
基本上我们的网站是"单页"应用程序风格的一部分,目前它只涉及2个页面,但可能会随着时间的推移而扩展,目前它只是一个"列表"页面和一个"管理"页面,用于名单.
管理页面本身需要某种富文本编辑器,我们已经将CKEditor用于公司范围的解决方案.
因为这两个页面是"单页"样式,显然CKEditor无法注册管理元素,因为它们不在页面加载上 - 足够简单的问题需要修复.因此,作为一个示例,我在一个非常有用的点击事件上附加了CKEditor.接下来的问题是,然后设置的Knockout observable没有得到更新,因为CKEditor实际上并没有修改它附加的textarea,它会创建你实际编辑的所有div/html元素.
经过一段时间的谷歌搜索后,我找到了一个用TinyMCE做这个的例子 - http://jsfiddle.net/rniemeyer/GwkRQ/所以我想我可以为CKEditor调整类似的东西.
目前我非常接近有一个可行的解决方案,我已经使用这种技术初始化和更新正确的observable(我将在底部发布代码),甚至正确地回发到服务器 - 太棒了.
我目前遇到的问题是"单页"应用程序部分和CKEditor的重新初始化.
基本上你可以点击列表进行管理然后保存(返回到列表页面)然后当你去另一个'管理'时CKEditor被初始化但是它没有任何值,我已经检查了更新代码(下面)和'value'肯定有正确的值,但它没有被推送到CKEditor本身.
也许是对CKEditor的流程/初始化过程缺乏了解或者缺乏对挖掘绑定的理解,或者可能是我们单页应用程序设置的框架存在问题 - 我不确定.
这是代码:
//Test one for ckeditor
ko.bindingHandlers.ckeditor = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var options = allBindingsAccessor().ckeditorOptions || {};
        var modelValue = valueAccessor();
        $(element).ckeditor();
        var editor = $(element).ckeditorGet();
        //handle edits made in the editor
        editor.on('blur', function (e) {
            var self = this;
            if (ko.isWriteableObservable(self)) {
                self($(e.listenerData).val());
            }
        }, modelValue, element);
        //handle destroying an editor (based on what jQuery plugin does)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            var existingEditor = CKEDITOR.instances[element.name];
            existingEditor.destroy(true);
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, context) {
        //handle programmatic updates to the observable
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).html(value);
    }
};
Run Code Online (Sandbox Code Playgroud)
所以在HTML中它是一个相当标准的淘汰'data-bind:ckeditor',它在ViewModel初始化时为它应用绑定.
我把调试器放了; 在代码中查看流程,看起来当我第一次加载它时调用init,然后更新,当我第二次进入它时,它会触及ko.utils.domNodeDisposal来处理元素.
我试过没有破坏它,CKEditor然后抱怨已经存在该名称的东西.我已经尝试过不破坏它并检查它是否存在并初始化它是否存在 - 这是第一次工作但第二次我们没有CKEditor.
我认为只有一件我想念的东西会让它发挥作用,但我已经筋疲力尽了.
有没有人知道如何整合这3件可以帮助我的东西?
是否有任何淘汰赛专家可以帮助我?
任何帮助将非常感激.
MD
MDo*_*MDo 11
对于任何感兴趣的人,我对它进
它只是一个基本的执行顺序,我只需要在初始化之前将值设置为textarea html.
注意,这使用jquery适配器扩展来对元素执行.ckeditor().
可能还有一种更好的方法来做"模糊"部分.
此扩展目前也不适用于选项,但相比之下应该非常简单.
ko.bindingHandlers.ckeditor = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        var options = allBindingsAccessor().ckeditorOptions || {};
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).html(value);
        $(element).ckeditor();
        var editor = $(element).ckeditorGet();
        //handle edits made in the editor
        editor.on('blur', function (e) {
            var self = this;
            if (ko.isWriteableObservable(self)) {
                self($(e.listenerData).val());
            }
        }, modelValue, element);
    }
};
Run Code Online (Sandbox Code Playgroud)
        我已经使用了一段时间了,并且再次运行.on("模糊")方法的几个问题.也就是说,当人们点击富文本并输入文本然后直接滚动到我的表单上的"保存"按钮时,observable的更新速度不够快.有很多方法可以处理延误,但我想要更正式的东西.我挖到了CKEditor文档,发现了这个gem: focusManager
这是内置功能,可处理焦点和模糊的所有实例,并允许您将真正的模糊事件连接到控件.
这是我的richHandler for rich text
ko.bindingHandlers.richText = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
       var txtBoxID = $(element).attr("id");
       var instance = CKEDITOR.instances[txtBoxID];
       var options = allBindingsAccessor().richTextOptions || {};
       options.toolbar_Full = [
            ['Source', '-', 'Format', 'Font', 'FontSize', 'TextColor', 'BGColor', '-', 'Bold', 'Italic', 'Underline', 'SpellChecker'],
            ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'],
            ['Link', 'Unlink', 'Image', 'Table']
       ];
       //handle disposal (if KO removes by the template binding)
       ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
          if (CKEDITOR.instances[txtBoxID]) { CKEDITOR.remove(CKEDITOR.instances[txtBoxID]); };
       });
       $(element).ckeditor(options);
       //wire up the blur event to ensure our observable is properly updated
       CKEDITOR.instances[txtBoxID].focusManager.blur = function () {
          var observable = valueAccessor();
          observable($(element).val());
       };
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
       var val = ko.utils.unwrapObservable(valueAccessor());
       $(element).val(val);
    }
}
Run Code Online (Sandbox Code Playgroud)
        在其他答案中完成的工作是我的解决方案:
change事件处理更改(按键更新但不仅仅是这样)getData()所以你不会得到像"魔术线"和类似的东西不需要的HTML码:
ko.bindingHandlers.ckeditor = {
    init: function(element, valueAccessor, allBindingsAccessor, context) {
        var options = allBindingsAccessor().ckeditorOptions || {};
        var modelValue = valueAccessor();
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).html(value);
        $(element).ckeditor();
        var editor = $(element).ckeditorGet();
        //handle edits made in the editor
        editor.on('change', function(e) {
            var self = this;
            if (ko.isWriteableObservable(self)) {
                self($(e.listenerData).val());
            }
        }, modelValue, element);
        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            if (editor) {
                CKEDITOR.remove(editor);
            };
        });
    },
    update: function(element, valueAccessor, allBindingsAccessor, context) {
        // handle programmatic updates to the observable
        var newValue = ko.utils.unwrapObservable(valueAccessor());
        if ($(element).ckeditorGet().getData() != newValue)
            $(element).ckeditorGet().setData(newValue)
    }
};
Run Code Online (Sandbox Code Playgroud)
我使用的标记(注意afterkeydown):
<textarea 
    id="editor1" 
    data-bind="ckeditor: text, valueUpdate: 'afterkeydown'"
></textarea>
Run Code Online (Sandbox Code Playgroud)
更新:根据评论中的要求,这是一个最小的工作小提琴.
第一篇帖子让我知道我做错了什么
在我的项目中,我提供了关于是否存在未保存更改的视觉反馈,因此需要更新可观察的更改keyup.并在click单击工具栏按钮时.这也与我valueUpdate:['afterkeydown','propertychange','input']在我的data-bind属性中使用一致.
另外,为了性能,我使用了回调方法参数.ckeditor(callback,options)而不是.on(eventName,handler).
这是我提出的自定义绑定:
ko.bindingHandlers.ckeditor = {
    init: function (element, valueAccessor, allBindingsAccessor, context) {
        // get observable
        var modelValue = valueAccessor();;
        $(element).ckeditor(function(textarea) {
            // <span> element that contains the CKEditor markup
            var $ckeContainer = $(this.container.$);
            // <body> element within the iframe (<html> is contentEditable)
            var $editorBody =
                    $ckeContainer.find('iframe').contents().find('body');
            // sets the initial value
            $editorBody.html( modelValue() );
            // handle edits made in the editor - by typing
            $editorBody.keyup(function() {
                modelValue( $(this).html() );
            });
            // handle edits made in the editor - by clicking in the toolbar
            $ckeContainer.find('table.cke_editor').click(function() {
                modelValue( $editorBody.html() );
            });
        });
        // when ko disposes of <textarea>, destory the ckeditor instance
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            $(element).ckeditorGet().destroy(true);
        });
    },
    update: function (element, valueAccessor, allBindingsAccessor, context) {
        // handle programmatic updates to the observable
        var newValue = ko.utils.unwrapObservable(valueAccessor());
        var $ckeContainer = $(element).ckeditorGet().container;
        if( $ckeContainer ) {
            // <span> element that contains the CKEditor markup
            $ckeContainer = $($ckeContainer.$);
            // <body> element within the iframe (<html> is contentEditable)
            var $editorBody =
                    $ckeContainer.find('iframe').contents().find('body');
            // if new value != existing value, replace it in the editor
            if( $editorBody.html() != newValue )
                $editorBody.html( newValue );
        }
    }
};
Run Code Online (Sandbox Code Playgroud)
理由:
我知道,我也许应该使用.getData()和.setData(html)替代发现的这个相当哈克的方式<body>与<table class="cke_editor">该范围内iframe的内容.
原因是,对于update:以下情况:
if( $(element).ckeditorGet().getData() != newValue )
    $(element).ckeditorGet().setData( newValue )
Run Code Online (Sandbox Code Playgroud)
由于CKEditor所做的HTML格式化,最初是真的.因此,即使不是,也会通知用户有关脏记录的信息.对我来说非常具体,所以我想你应该知道,万一你想知道为什么.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           6834 次  |  
        
|   最近记录:  |