如何在将 ckeditor 数据绑定为 knockout observable 时更新它?
How to update ckeditor data when binding it as knockout observable?
我正在尝试将 ckeditor 作为 knockout.js 可观察对象使用,但我 运行 遇到了一些麻烦。
首先,这是我的代码:
ko.bindingHandlers.CKEDITOR = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var ckEditorValue = valueAccessor();
var id = $(element).attr('id');
var options = allBindings().EditorOptions;
var instance = CKEDITOR.replace(id, {
on: {
change: function () {
// This moves the caret to the start of the editor on each key pressed
ckEditorValue(instance.getData());
}
}
});
// instance.setData(ckEditorValue());
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var id = $(element).attr('id');
var ckEditorValue = valueAccessor();
CKEDITOR.instances[id].setData(ckEditorValue());
}
};
我在使用这段代码时遇到的问题是,在我按下的每个键上,change
事件正在触发,插入符号移动到编辑器的顶部开始位置。
我尝试调用 blur
事件而不是 change
事件,但是当我单击保存按钮时它不会触发,它仅在我单击空白位置或移动到另一个控件时触发。
我怎样才能使我的可观察对象保持更新?
我有 a similar issue with a different editor,并通过删除 update
处理程序并将其替换为手动订阅来解决它。这样,您可以引入一些共享状态 'skip this update, that was me':
ko.bindingHandlers.CKEDITOR = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var ckEditorValue = valueAccessor();
var id = $(element).attr('id');
var options = allBindings().EditorOptions;
var ignoreChanges = false;
var instance = CKEDITOR.replace(id, {
on: {
change: function() {
ignoreChanges = true;
ckEditorValue(instance.getData());
ignoreChanges = false;
}
}
});
ckEditorValue.subscribe(function(newValue) {
if (!ignoreChanges) {
instance.setData(newValue);
}
});
}
};
这是 CKEditor v4.6.2 (12 Jan 2017) 的扩展 KO 绑定。
我想使用 'update' 的预期行为
这将确保可观察值在 'blur' 事件上更新。
这花了一些时间来微调,所以我希望这对某人有用。
/**
* Custom KO binding for jQuery CKEditor plugin v4.2.6
* {@link http://docs.ckeditor.com/#!/guide/dev_jquery Original Reference}
* Usage: <div data-bind="ckeditor: { [ CKEditor init options should be placed here.] }, value: $data.value"></div>
*/
ko.bindingHandlers.ckeditor = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = valueAccessor();
var binding = ko.utils.unwrapObservable(allBindingsAccessor()).value;
options = ko.utils.extend(ko.bindingHandlers.ckeditor.options, options);
// Set an ID if the element doesn't already have one assigned
var elemId = $(element).attr('id');
if(typeof elemId === "undefined") {
elemId = 'ck_' + Math.random().toString(36).substring(7);
$(element).attr('id', elemId);
}
var ckeditorId = $(element).attr("id");
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
var ckInst = eval( "CKEDITOR.instances." + ckeditorId );
if ( ckInst ) ckInst.destroy();
});
$(element).ckeditor( options );
// wire up the source button click event to copy the value
CKEDITOR.instances[ckeditorId].on('afterCommandExec', handleAfterCommandExec);
function handleAfterCommandExec(event) {
var commandName = event.data.name;
// For 'source' commmand
if (commandName == 'source')
//console.log("source button pressed!");
binding( $(element).val() );
}
// wire up the blur event to ensure our observable is properly updated
CKEDITOR.instances[ckeditorId].focusManager.blur = function () {
var ckInst = eval( "CKEDITOR.instances." + ckeditorId );
//console.log('blur!');
//console.log( $(element).val() );
binding( $(element).val() );
};
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.unwrap(allBindingsAccessor.get('value'));
// only update the code when there are differences
if ( value !== $(element).val() ) {
$(element).val(value);
}
},
options: {
toolbar: [
{ name: 'styles', items: [ 'Styles', 'Format' ] },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source' ] },
{ name: 'clipboard', groups: [ 'undo' ], items: [ 'Undo', 'Redo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ], items: [ 'Scayt' ] },
{ name: 'tools', items: [ 'Maximize' ] },
{ name: 'others', items: [ '-' ] },
{ name: 'about', items: [ 'About' ] },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule', 'SpecialChar' ] }
]
}
};
我知道我回答这个问题有点晚了,但我已经为此苦苦挣扎了一段时间,我的问题是我需要用户在框中输入或通过按钮添加模板,所有我找到的解决方案解决了其中一个问题,但没有同时解决这两个问题。
下面的 fiddle 解决了在框中键入(将光标保持在正确的位置并且不重置到位置 0)以及单击按钮以触发 KO 函数以更新编辑器中的数据.
这是实现此目的的自定义绑定
var TOOLBAR_CONFIG = [{
name: 'document',
items: ['Source', '-', 'Save', 'NewPage', 'DocProps', 'Preview', 'Print', '-', 'Templates']
}, {
name: 'clipboard',
items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']
}, {
name: 'editing',
items: ['Find', 'Replace', '-', 'SelectAll', '-', 'SpellChecker', 'Scayt']
}, {
name: 'forms',
items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton',
'HiddenField'
]
},
'/', {
name: 'basicstyles',
items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']
}, {
name: 'paragraph',
items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv',
'-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'
]
}, {
name: 'links',
items: ['Link', 'Unlink', 'Anchor']
}, {
name: 'insert',
items: ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']
},
'/', {
name: 'styles',
items: ['Styles', 'Format', 'Font', 'FontSize']
}, {
name: 'colors',
items: ['TextColor', 'BGColor']
}, {
name: 'tools',
items: ['Maximize', 'ShowBlocks', '-', 'About']
}
];
ko.bindingHandlers.ckeditor = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var ignoreChanges = false;
var options = ko.utils.extend({
toolbar: TOOLBAR_CONFIG,
removePlugins: 'elementspath'
}, allBindings.get('ckeditorOptions') || {});
var modelValue = valueAccessor();
var editor = CKEDITOR.replace(element, options);
editor.on('change', function() {
ignoreChanges = true;
modelValue(editor.getData());
ignoreChanges = false;
});
modelValue.subscribe(function(newValue) {
var editor = new CKEDITOR.dom.element(element).getEditor();
if (!(ignoreChanges))
editor.setData(newValue);
});
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (editor) {
CKEDITOR.remove(editor);
};
});
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var editor = new CKEDITOR.dom.element(element).getEditor();
console.log(ko.unwrap(valueAccessor()));
editor.setData(ko.unwrap(valueAccessor()), null, true);
}
};
工作示例
我正在尝试将 ckeditor 作为 knockout.js 可观察对象使用,但我 运行 遇到了一些麻烦。 首先,这是我的代码:
ko.bindingHandlers.CKEDITOR = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var ckEditorValue = valueAccessor();
var id = $(element).attr('id');
var options = allBindings().EditorOptions;
var instance = CKEDITOR.replace(id, {
on: {
change: function () {
// This moves the caret to the start of the editor on each key pressed
ckEditorValue(instance.getData());
}
}
});
// instance.setData(ckEditorValue());
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var id = $(element).attr('id');
var ckEditorValue = valueAccessor();
CKEDITOR.instances[id].setData(ckEditorValue());
}
};
我在使用这段代码时遇到的问题是,在我按下的每个键上,change
事件正在触发,插入符号移动到编辑器的顶部开始位置。
我尝试调用 blur
事件而不是 change
事件,但是当我单击保存按钮时它不会触发,它仅在我单击空白位置或移动到另一个控件时触发。
我怎样才能使我的可观察对象保持更新?
我有 a similar issue with a different editor,并通过删除 update
处理程序并将其替换为手动订阅来解决它。这样,您可以引入一些共享状态 'skip this update, that was me':
ko.bindingHandlers.CKEDITOR = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var ckEditorValue = valueAccessor();
var id = $(element).attr('id');
var options = allBindings().EditorOptions;
var ignoreChanges = false;
var instance = CKEDITOR.replace(id, {
on: {
change: function() {
ignoreChanges = true;
ckEditorValue(instance.getData());
ignoreChanges = false;
}
}
});
ckEditorValue.subscribe(function(newValue) {
if (!ignoreChanges) {
instance.setData(newValue);
}
});
}
};
这是 CKEditor v4.6.2 (12 Jan 2017) 的扩展 KO 绑定。 我想使用 'update' 的预期行为 这将确保可观察值在 'blur' 事件上更新。
这花了一些时间来微调,所以我希望这对某人有用。
/**
* Custom KO binding for jQuery CKEditor plugin v4.2.6
* {@link http://docs.ckeditor.com/#!/guide/dev_jquery Original Reference}
* Usage: <div data-bind="ckeditor: { [ CKEditor init options should be placed here.] }, value: $data.value"></div>
*/
ko.bindingHandlers.ckeditor = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = valueAccessor();
var binding = ko.utils.unwrapObservable(allBindingsAccessor()).value;
options = ko.utils.extend(ko.bindingHandlers.ckeditor.options, options);
// Set an ID if the element doesn't already have one assigned
var elemId = $(element).attr('id');
if(typeof elemId === "undefined") {
elemId = 'ck_' + Math.random().toString(36).substring(7);
$(element).attr('id', elemId);
}
var ckeditorId = $(element).attr("id");
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
var ckInst = eval( "CKEDITOR.instances." + ckeditorId );
if ( ckInst ) ckInst.destroy();
});
$(element).ckeditor( options );
// wire up the source button click event to copy the value
CKEDITOR.instances[ckeditorId].on('afterCommandExec', handleAfterCommandExec);
function handleAfterCommandExec(event) {
var commandName = event.data.name;
// For 'source' commmand
if (commandName == 'source')
//console.log("source button pressed!");
binding( $(element).val() );
}
// wire up the blur event to ensure our observable is properly updated
CKEDITOR.instances[ckeditorId].focusManager.blur = function () {
var ckInst = eval( "CKEDITOR.instances." + ckeditorId );
//console.log('blur!');
//console.log( $(element).val() );
binding( $(element).val() );
};
},
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.unwrap(allBindingsAccessor.get('value'));
// only update the code when there are differences
if ( value !== $(element).val() ) {
$(element).val(value);
}
},
options: {
toolbar: [
{ name: 'styles', items: [ 'Styles', 'Format' ] },
{ name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source' ] },
{ name: 'clipboard', groups: [ 'undo' ], items: [ 'Undo', 'Redo' ] },
{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ], items: [ 'Scayt' ] },
{ name: 'tools', items: [ 'Maximize' ] },
{ name: 'others', items: [ '-' ] },
{ name: 'about', items: [ 'About' ] },
'/',
{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] },
{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote' ] },
{ name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule', 'SpecialChar' ] }
]
}
};
我知道我回答这个问题有点晚了,但我已经为此苦苦挣扎了一段时间,我的问题是我需要用户在框中输入或通过按钮添加模板,所有我找到的解决方案解决了其中一个问题,但没有同时解决这两个问题。
下面的 fiddle 解决了在框中键入(将光标保持在正确的位置并且不重置到位置 0)以及单击按钮以触发 KO 函数以更新编辑器中的数据.
这是实现此目的的自定义绑定
var TOOLBAR_CONFIG = [{
name: 'document',
items: ['Source', '-', 'Save', 'NewPage', 'DocProps', 'Preview', 'Print', '-', 'Templates']
}, {
name: 'clipboard',
items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']
}, {
name: 'editing',
items: ['Find', 'Replace', '-', 'SelectAll', '-', 'SpellChecker', 'Scayt']
}, {
name: 'forms',
items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton',
'HiddenField'
]
},
'/', {
name: 'basicstyles',
items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']
}, {
name: 'paragraph',
items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv',
'-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'
]
}, {
name: 'links',
items: ['Link', 'Unlink', 'Anchor']
}, {
name: 'insert',
items: ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']
},
'/', {
name: 'styles',
items: ['Styles', 'Format', 'Font', 'FontSize']
}, {
name: 'colors',
items: ['TextColor', 'BGColor']
}, {
name: 'tools',
items: ['Maximize', 'ShowBlocks', '-', 'About']
}
];
ko.bindingHandlers.ckeditor = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var ignoreChanges = false;
var options = ko.utils.extend({
toolbar: TOOLBAR_CONFIG,
removePlugins: 'elementspath'
}, allBindings.get('ckeditorOptions') || {});
var modelValue = valueAccessor();
var editor = CKEDITOR.replace(element, options);
editor.on('change', function() {
ignoreChanges = true;
modelValue(editor.getData());
ignoreChanges = false;
});
modelValue.subscribe(function(newValue) {
var editor = new CKEDITOR.dom.element(element).getEditor();
if (!(ignoreChanges))
editor.setData(newValue);
});
//handle disposal (if KO removes by the template binding)
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (editor) {
CKEDITOR.remove(editor);
};
});
},
update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var editor = new CKEDITOR.dom.element(element).getEditor();
console.log(ko.unwrap(valueAccessor()));
editor.setData(ko.unwrap(valueAccessor()), null, true);
}
};
工作示例