Create a bindable content-editable div with CSS styling and observe mutations for updating an observable property.
by whelkaholism
HTML
<div data-bind="contenteditable: Text"></div>
<hr/>
<xmp data-bind="text: Text"></xmp>
CSS
.cfaf-content-editable {
padding: 1em;
border: 1px dotted #909090;
border-radius: 0.5em;
outline: none;
}
.cfaf-content-editable:focus {
border-color: #000000;
}
JavaScript
(function()
{
ko.bindingHandlers.contenteditable = {
init:
function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
{
var obs = f_valueaccessor();
el.classList.add('cfaf-content-editable');
el.setAttribute('contenteditable', true);
// Callback function to execute when mutations are observed
const callback = function(mutations, observer)
{
obs.__contenteditable_updating = true;
try
{
obs(el.innerHTML);
}
finally
{
delete obs.__contenteditable_updating;
}
}
const observer = new MutationObserver(callback);
observer.observe(el, { characterData: true, childList: true, subtree: true });
ko.utils.domNodeDisposal.addDisposeCallback(el, function() { observer.disconnect(); });
},
update: function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
{
var obs = f_valueaccessor();
!obs.__contenteditable_updating && (el.innerHTML = ko.unwrap(f_valueaccessor()));
},
};
})();
var model = new function()
{
this.Text = ko.observable('XXX');
}
ko.applyBindings(model);