I have a situation involving KnockoutJS and the jwysiwyg plugin (https://github.com/jwysiwyg/jwysiwyg ). I'm using the custom binding seen below. However, whenever the user updates the text onto a second line, updating the content via the binding causes the cursor to reset to the very beginning of the editor. So whenever a user pauses typing for more than 1 second after an update, they're forced to click back to where they were before to continue.

    ko.bindingHandlers.wysiwyg = {
        init: function (element, valueAccessor, allBindingsAccessor) {
        var options = allBindingsAccessor().wysiwygOptions || {};
        var value = ko.utils.unwrapObservable(valueAccessor());
        var $e = $(element);
        $.extend(true, {
            initialContent : value
        }, options);

        $e.wysiwyg(options);

        //handle the field changing
        function detectFn() {
            var observable = valueAccessor();
            var newvalue = $e.wysiwyg("getContent");
            observable(newvalue);
        }

        var current = $e.wysiwyg('document');
        var timer;
        current.bind({    
            keyup: function(){
                clearTimeout(timer);
                timer = setTimeout(detectFn, 1000);
            }
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $e.wysiwyg('destroy');
        });
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).wysiwyg("setContent", value);
        ko.bindingHandlers.value.update(element, valueAccessor);
    }
};

(The binding is then used by this)

<textarea data-bind="wysiwyg: yourViewModelValue"></textarea>

How can I get the caret position to restore the cursor once the update is complete? Or what other solutions are there to force the cursor not to move when updating?

EDIT: A jsfiddle to demonstrate the issue. http://jsfiddle.net/797ZL/ Notice what happens when you type on a second line or beyond, then pause for a second, causing the cursor to reset.

有帮助吗?

解决方案

Here is what you are seeing:

  1. The user types some text into the WYSIWYG editor
  2. The user stops typing and the timeout hits after 1 second, triggering detectFn
  3. detectFn grabs the new value from the WYSIWYG editor and updates your observable
  4. Your observable, being updated, triggers the update method on your custom binder
  5. The update method on the custom binder gets the value from the observable, and sets it on the WYSIWYG editor
  6. The WYSIWYG editor, having a new value set to it, moves the cursor to the top line

You can fix this by stopping things in the middle of step 5, and only updating the value in the WYSIWYG editor if it is different from the value in the observable - that is, if the observable was updated from somewhere outside of the WYSIWYG editor.

Change your update method to this:

update: function (element, valueAccessor) {
    var newValue = ko.utils.unwrapObservable(valueAccessor());
    var oldValue = $(element).wysiwyg("getContent");
    if (newValue !== oldValue) {
        $(element).wysiwyg("setContent", newValue);
    }
    // ko.bindingHandlers.value.update(element, valueAccessor);
}

I commented out the last line of that method... it seems extraneous and I'm not really sure why it's there.

Also, these lines of code don't seem to be doing anything either:

$.extend(true, {
    initialContent : value
}, options);

I think what you are trying to do is add the initialContent property to the options object. That can be done in this way:

$.extend(options, {initialContent: value});

However, even that is not needed, because the update method is called after the init method, and the value from the observable is loaded into the WYSIWYG editor at that time.

Here is a fiddle with the updated code: http://jsfiddle.net/tlarson/797ZL/2/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top