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:
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/