Knockoutjs+Ckeditor需要帮助解决一些问题

Knockoutjs + Ckeditor Need help figuring something out

本文关键字:问题 解决 帮助 Knockoutjs+Ckeditor      更新时间:2023-09-26

我有这个代码需要与ckeditor:连接

基本上,我想做的是让它通过与已经存在的数据绑定连接

textare-autocomplete="off"class="form control"data bind="rev_ckeditor,value:app.models.userReview.body"id="editor"maxlength="50000"name="body"cols="50"rows="10"

上面的文本区域既有值数据绑定,也有ckeditor的数据dind。但是ckwditor出现了,但没有显示值的数据绑定,有什么问题吗?

代码:

(function($) {
'use strict'
app.viewModels.reviews = {
    /**
     * All reviews.
     *
     * @type ko.observable(Array)
     */
    sourceItems: ko.observableArray([]),
    /**
     * Sorting type and order.
     *
     * @type ko.observable(String)
     */
    currentSort: ko.observable(),
    /**
     * Holds average score of all critic reviews.
     *
     * @type ko.observable(String)
     */
    criticAverage: ko.observable(),
    /**
     * Holds count of all critic reviews.
     *
     * @type ko.observable(String)
     */
    criticCount: ko.observable(),
    /**
     * Holds average score of all user reviews.
     *
     * @type ko.observable(String)
     */
    userAverage: ko.observable(),
    /**
     * Holds count of all user reviews.
     *
     * @type ko.observable(String)
     */
    userCount: ko.observable(),
    /**
     * Whether to who user, critic or all reviews.
     *
     * @type ko.observable(String)
     */
    currentType: ko.observable(),
    /**
     * Send request to server to create a new
     * user review.
     *
     * @return void
     */
    create: function(form) {
        var self = this;
        var params = {
            data: ko.toJSON(app.models.userReview),
            success: function(response) {
                var exists = false;
                $.each(self.sourceItems(), function(i,v) {
                    //if user has already written a review for this game we'll just replace
                    //it with this one as that's what backend is doing as well
                    if (v.type == 'user' && v.user_id == parseInt(vars.userId)) {
                        self.sourceItems()[i] = ko.toJS(app.models.userReview);
                        self.sourceItems.notifySubscribers();
                        exists = true;
                        return false;
                    }
                });
                if ( ! exists) {
                    self.sourceItems.push(ko.toJS(app.models.userReview));
                }
                $('#review-modal').modal('hide');
                app.utils.noty(response, 'success');
            },
            /**
             * Append any validation errors returned to new review form.
             *
             * @param  jq
             * @return void
             */
            error: function(jq) {
                $('.alert').remove();
                app.utils.appendError(jq);
            },
            url: form.action,
        };
        app.utils.ajax(params);
    },
    /**
     * Handle user click on review edit button.
     *
     * @param  app.models.review review
     * @return void
     */
    edit: function(review) {
        app.models.userReview.id(review.id);
        app.models.userReview.title(review.title);
        app.models.userReview.body(review.body);
        app.models.userReview.score(review.score);
        app.models.userReview.story_rev(review.story_rev);
        app.models.userReview.animation_rev(review.animation_rev);
        app.models.userReview.sound_rev(review.sound_rev);
        app.models.userReview.characters_rev(review.characters_rev);
        app.models.userReview.enjoyment_rev(review.enjoyment_rev);
        $('#review-modal').modal('show');
    },
    /**
     * Handle user click on delete button.
     *
     * @param  Object review
     * @return void
     */
    delete: function(review) {
        var self = app.viewModels.reviews;
        app.utils.ajax({
            url: vars.urls.baseUrl+'/movies/'+vars.titleId+'/reviews/'+review.id,
            type: 'DELETE',
            data: ko.toJSON(vars.token),
            success: function() {
                self.sourceItems.remove(review);
            }
        })
    }
};
/**
 * Calculate average critic/user review score as well as review counts.
 *
 * @return void
 */
 app.viewModels.reviews.calculateMeta = ko.computed(function() {
     var self     = this, score = 0,
         crCount  = 0,    crAvg  = 0,
         uCount   = 0,    uAvg   = 0;
     $.each(self.sourceItems(), function(ind, val) {
         if (val.type == 'critic') {
             crCount++;
             crAvg += parseFloat(val.score);
         } else if (val.type == 'user') {
             uCount++;
             uAvg += parseFloat(val.score);
         }
     });
     //set average to flash if there's no reviews otherwise calculate an avarage
     crCount ? self.criticAverage(crAvg / crCount) : self.criticAverage('/');
     uCount ? self.userAverage(uAvg / uCount) : self.userAverage('/');
     self.userCount(uCount);
     self.criticCount(crCount);
 }, app.viewModels.reviews, {deferEvaluation: true});
/**
 * Filters critic reviews on platform dropdown change,
 * if no reviews found fires an ajax request to query
 * review data provider.
 *
 * @return array
 */
app.viewModels.reviews.filteredReviews = ko.computed(function() {
    var self = this, filtered;
    //filter by user or critic reviews if user select either
    if (self.currentType() === 'all') {
        filtered = self.sourceItems();
    } else {
        filtered = ko.utils.arrayFilter(self.sourceItems(), function(rev) {
            return rev.type === self.currentType();
        });
    }
    //split current sort by camelCase into type and order params
    var sort = self.currentSort().match(/([A-Z]?[^A-Z]*)/g).slice(0,-1);
    if (sort.length === 2) {
        filtered.sort(app.utils.sort[sort[0]](sort[1]));
    }
    return filtered ? filtered : [];
}, app.viewModels.reviews, {deferEvaluation: true});
/**
 * New review form model.
 *
 * @type Object
 */
app.models.userReview = {
    id: ko.observable(),
    author: app.username,
    title: ko.observable(),
    source: 'Test',
    body: ko.observable(),
    story_rev: ko.observable(),
    animation_rev: ko.observable(),
    characters_rev: ko.observable(),
    sound_rev: ko.observable(),
    enjoyment_rev: ko.observable(),
    score: ko.observable(),
    type: 'user',
    _token: vars.token,
    user_id: app.user_id,
};

/**
* Renders CKeditor on textarea.
*
* @type {Object}
*/
ko.bindingHandlers.rev_ckeditor = {
        init: function (element, valueAccessor, allBindingsAccessor, context, review) {
                var $element = $(element);
                var value = ko.utils.unwrapObservable(valueAccessor());
                $element.html(value);
                var editor = CKEDITOR.replace('editor');
                /**
                * Resize CKeditor according to textarea col and rows attributes.
                *
                * @return void
                */
                jQuery.fn.cke_resize = function() {
                    return this.each(function() {
                            var $this = $(this);
                            var rows = $this.attr('rows');
                            var height = rows * 20;
                            $this.next("div.cke").find(".cke_contents").css("height", height);
                    });
                };
                CKEDITOR.on('instanceReady', function(){ $element.cke_resize(); });
                //Update body observable on ckeditor blur event
                editor.on('blur', function (e) {
                       var obs = app.models.userReview.body(review.body);
                        if (ko.isWriteableObservable(obs)) {
                                obs(e.editor.getData());
                        }
                });
        }
};
})(jQuery);

我不熟悉CKEditor,所以我在这里可能错了,但许多所见即所得编辑器不会因为您更改了底层<textarea>中的数据而自行更新,而value绑定就是这样做的。我建议完全删除value绑定,让编辑器绑定到所有工作中。

现在,您的绑定似乎只处理编写编辑器对可观察对象的更改。我们还需要处理相反的方向,并将可观察到的更改写入编辑器。根据CKEditor文档,这是通过编辑器#setData:完成的

ko.bindingHandlers.rev_ckeditor = {
    init: function (element, valueAccessor, allBindingsAccessor, context, review) {
        var $element   = $(element),
            observable = valueAccessor();
        var editor = CKEDITOR.replace('editor');
        ko.computed(function() {
          editor.setData( observable() );
        }, { disposeWhenNodeIsRemoved: element });
        jQuery.fn.cke_resize = function () {
            return this.each(function () {
                var $this = $(this);
                var rows = $this.attr('rows');
                var height = rows * 20;
                $this.next("div.cke").find(".cke_contents").css("height", height);
            });
        };
        CKEDITOR.on('instanceReady', function () {
            $element.cke_resize();
        });
        editor.on('blur', function (e) {
            if (ko.isWriteableObservable(observable)) {
                observable(e.editor.getData());
            }
        });
    }
};

通常,会将对可观察到的更改写回绑定update处理程序中的编辑器。在这种情况下,在init处理程序中执行更方便,因为我们已经可以访问那里的编辑器实例。

如果您允许编辑器绑定访问可观察对象,那么一切都应该按预期工作:

<textarea data-bind="rev_ckeditor: app.models.userReview.body"></textarea>