我正在为Summernote所使用的所见即所得编辑器(版本0.8.1)开发一个插件,以便将iframe元素插入到代码中。
通过使用提供的示例,我成功地在菜单中添加了插件按钮,并打开了一个对话框,在其中可以输入URL和标题。将iframe标签添加到源中并不是问题,但这不是我想要的。
我想要在代码中插入一个占位符,其标记类似于(或类似于):
现在,Summernote允许我编辑span的内容,但我希望能够插入一个占位符,它不能在编辑器中修改。
我该如何在编辑器中插入一个具有以下特点的占位符:
- 它作为单一块进行编辑(可以通过单个删除删除) - 单击时,我可以打开类似于链接或图像弹出窗口的弹出窗口以调整大小 - 内部内容不可编辑
以下是我到目前为止所拥有的:
通过使用提供的示例,我成功地在菜单中添加了插件按钮,并打开了一个对话框,在其中可以输入URL和标题。将iframe标签添加到源中并不是问题,但这不是我想要的。
我想要在代码中插入一个占位符,其标记类似于(或类似于):
<div class="ext-iframe-subst" data-src="http://www.test.example" data-title="iframe title"><span>iframe URL: http://www.test.example</span></div>
现在,Summernote允许我编辑span的内容,但我希望能够插入一个占位符,它不能在编辑器中修改。
我该如何在编辑器中插入一个具有以下特点的占位符:
- 它作为单一块进行编辑(可以通过单个删除删除) - 单击时,我可以打开类似于链接或图像弹出窗口的弹出窗口以调整大小 - 内部内容不可编辑
以下是我到目前为止所拥有的:
// Extends plugins for adding iframes.
// - plugin is external module for customizing.
$.extend($.summernote.plugins, {
/**
* @param {Object} context - context object has status of editor.
*/
'iframe': function (context) {
var self = this;
// ui has renders to build ui elements.
// - you can create a button with `ui.button`
var ui = $.summernote.ui;
var $editor = context.layoutInfo.editor;
var options = context.options;
var lang = options.langInfo;
// add context menu button
context.memo('button.iframe', function () {
return ui.button({
contents: '<i class="fa fa-newspaper-o"/>',
tooltip: lang.iframe.iframe,
click: context.createInvokeHandler('iframe.show')
}).render();
});
// This events will be attached when editor is initialized.
this.events = {
// This will be called after modules are initialized.
'summernote.init': function (we, e) {
console.log('IFRAME initialized', we, e);
},
// This will be called when user releases a key on editable.
'summernote.keyup': function (we, e) {
console.log('IFRAME keyup', we, e);
}
};
// This method will be called when editor is initialized by $('..').summernote();
// You can create elements for plugin
this.initialize = function () {
var $container = options.dialogsInBody ? $(document.body) : $editor;
var body = '<div class="form-group row-fluid">' +
'<label>' + lang.iframe.url + '</label>' +
'<input class="ext-iframe-url form-control" type="text" />' +
'<label>' + lang.iframe.title + '</label>' +
'<input class="ext-iframe-title form-control" type="text" />' +
'<label>' + lang.iframe.alt + '</label>' +
'<textarea class="ext-iframe-alt form-control" placeholder="' + lang.iframe.alttext + '" rows=""10""></textarea>' +
'</div>';
var footer = '<button href="#" class="btn btn-primary ext-iframe-btn disabled" disabled>' + lang.iframe.insert + '</button>';
this.$dialog = ui.dialog({
title: lang.iframe.insert,
fade: options.dialogsFade,
body: body,
footer: footer
}).render().appendTo($container);
};
// This methods will be called when editor is destroyed by $('..').summernote('destroy');
// You should remove elements on `initialize`.
this.destroy = function () {
this.$dialog.remove();
this.$dialog = null;
};
this.bindEnterKey = function ($input, $btn) {
$input.on('keypress', function (event) {
if (event.keyCode === 13) { //key.code.ENTER) {
$btn.trigger('click');
}
});
};
this.createIframeNode = function (data) {
var $iframeSubst = $('<div class="ext-iframe-subst"><span>' + lang.iframe.iframe + '</span></div>');
$iframeSubst.attr("data-src", data.url).attr("data-title", data.title);
return $iframeSubst[0];
};
this.show = function () {
var text = context.invoke('editor.getSelectedText');
context.invoke('editor.saveRange');
console.log("iframe.getInfo: " + text);
this
.showIframeDialog(text)
.then(function (data) {
// [workaround] hide dialog before restore range for IE range focus
ui.hideDialog(self.$dialog);
context.invoke('editor.restoreRange');
// build node
var $node = self.createIframeNode(data);
if ($node) {
// insert iframe node
context.invoke('editor.insertNode', $node);
}
})
.fail(function () {
context.invoke('editor.restoreRange');
});
};
this.showIframeDialog = function (text) {
return $.Deferred(function (deferred) {
var $iframeUrl = self.$dialog.find('.ext-iframe-url');
var $iframeTitle = self.$dialog.find('.ext-iframe-title');
var $iframeBtn = self.$dialog.find('.ext-iframe-btn');
ui.onDialogShown(self.$dialog, function () {
context.triggerEvent('dialog.shown');
$iframeUrl.val(text).on('input', function () {
ui.toggleBtn($iframeBtn, $iframeUrl.val());
}).trigger('focus');
$iframeBtn.click(function (event) {
event.preventDefault();
deferred.resolve({ url: $iframeUrl.val(), title: $iframeTitle.val() });
});
self.bindEnterKey($iframeUrl, $iframeBtn);
});
ui.onDialogHidden(self.$dialog, function () {
$iframeUrl.off('input');
$iframeBtn.off('click');
if (deferred.state() === 'pending') {
deferred.reject();
}
});
ui.showDialog(self.$dialog);
});
};
}
});
// add localization texts
$.extend($.summernote.lang['en-US'], {
iframe: {
iframe: 'iframe',
url: 'iframe URL',
title: 'title',
insert: 'insert iframe',
alt: 'Text alternative',
alttext: 'you should provide a text alternative for the content in this iframe.',
test: 'Test'
}
});