I have been working on a formatting toolbar for a textarea, much like the toolbar for writing questions on this very site (with the bold, italic, underline buttons). The only difference is that I need the buttons to make the text actually bold not just add a bold tag. What I need is similar to the Instructables.com rich comment editor, or the newgrounds.com comment editor, or google d开发者_C百科ocs. Does anyone have a clue how I can make some text in a textarea show up bold, italic, or underlined but keep the rest of it?
There are lots of implementations of javascript WYSIWYG eitors. FCKEditor (now CKEditor) was one of the first. TinyMCE was popular for a long time. I've recently used TinyEditor.
There's also nicedit, 10 editors listed and compared here, not to mention the answers previously provided here on SO to the question of what's available.
An they don't have to produce HTML - there are also editors producing Wiki markup
Why reinvent the wheel?
I found how to create own Rich Text Editor just like this :
(function ($) {
if (typeof $.fn.rte === "undefined") {
var defaults = {
content_css_url: "rte.css",
media_url: "images",
dot_net_button_class: null,
max_height: 350
};
$.fn.rte = function (options) {
$.fn.rte.html = function (iframe) {
return iframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
};
var opts = $.extend(defaults, options);
return this.each(function () {
var textarea = $(this);
var iframe;
var myID = textarea.attr("id");
var settings = $.meta ? $.extend({}, opts, textarea.data()) : opts;
var sel = {
cmdBtnSelector: "." + settings.dot_net_button_class
};
function enableDesignMode() {
var content = textarea.val();
if ($.trim(content) == '') {
content = '<br />';
}
if (iframe) {
textarea.hide();
$(iframe).contents().find("body").html(content);
$(iframe).show();
$("#toolbar-" + myID).remove();
textarea.before(toolbar());
return true;
}
iframe = document.createElement("iframe");
iframe.frameBorder = 0;
iframe.frameMargin = 0;
iframe.framePadding = 0;
iframe.height = 200;
if (textarea.attr('class')) iframe.className = textarea.attr('class');
if (textarea.attr('id')) iframe.id = myID;
if (textarea.attr('name')) iframe.title = textarea.attr('name');
textarea.after(iframe);
var css = "";
if (settings.content_css_url) {
css = "<link type='text/css' rel='stylesheet' href='" + settings.content_css_url + "' />";
}
var doc = "<html><head>" + css + "</head><body class='frameBody'>" + content + "</body></html>";
tryEnableDesignMode(doc, function () {
$("#toolbar-" + myID).remove();
textarea.before(toolbar());
textarea.hide();
});
}
function tryEnableDesignMode(doc, callback) {
if (!iframe) {
return false;
}
try {
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(doc);
iframe.contentWindow.document.close();
} catch (error) {
console.log(error)
}
if (document.contentEditable) {
iframe.contentWindow.document.designMode = "On";
callback();
return true;
} else if (document.designMode != null) {
try {
iframe.contentWindow.document.designMode = "on";
callback();
return true;
} catch (error) {
console.log(error)
}
}
setTimeout(function () {
tryEnableDesignMode(doc, callback)
}, 250);
return false;
}
function disableDesignMode(submit) {
var content = $(iframe).contents().find("body").html();
if ($(iframe).is(":visible")) {
textarea.val(content);
}
if (submit !== true) {
textarea.show();
$(iframe).hide();
}
}
function toolbar() {
var tb = $("<div class='rte-toolbar' id='toolbar-" + myID + "'><div>\
<p>\
<select>\
<option value=''>Block style</option>\
<option value='p'>Paragraph</option>\
<option value='h3'>Title</option>\
</select>\
</p>\
<p>\
<a href='#' class='bold'><img src='" + settings.media_url + "text_bold.png' alt='bold' title='Bold' /></a>\
<a href='#' class='italic'><img src='" + settings.media_url + "text_italic.png' alt='italic' title='Italicize' /></a>\
</p>\
<p>\
<a href='#' class='unorderedlist'><img src='" + settings.media_url + "text_list_bullets.png' alt='unordered list' title='Unordered List' /></a>\
<a href='#' class='link'><img src='" + settings.media_url + "link.png' alt='link' title='Hyperlink' /></a>\
<a href='#' class='image'><img src='" + settings.media_url + "image.png' alt='image' title='Image' /></a>\
<a href='#' class='disable'><img src='" + settings.media_url + "code.png' alt='close rte' title='View Code' /></a>\
</p></div></div>");
$('select', tb).change(function () {
var index = this.selectedIndex;
if (index != 0) {
var selected = this.options[index].value;
formatText("formatblock", '<' + selected + '>');
}
});
$('.bold', tb).click(function () {
formatText('bold');
return false;
});
$('.italic', tb).click(function () {
formatText('italic');
return false;
});
$('.unorderedlist', tb).click(function () {
formatText('insertunorderedlist');
return false;
});
$('.link', tb).click(function () {
var p = prompt("URL:");
if (p) formatText('CreateLink', p);
return false;
});
$('.image', tb).click(function () {
var p = prompt("image URL:");
if (p) formatText('InsertImage', p);
return false;
});
$('.disable', tb).click(function () {
disableDesignMode();
var edm = $('<a href="#">Enable design mode</a>');
tb.empty().append(edm);
edm.click(function (e) {
e.preventDefault();
enableDesignMode();
$(this).remove();
});
return false;
});
if (settings.dot_net_button_class != null) {
var cmdBtn = $(iframe).parents('form').find(sel.cmdBtnSelector);
cmdBtn.click(function () {
disableDesignMode(true);
});
} else {
$(iframe).parents('form').submit(function () {
disableDesignMode(true);
});
}
var iframeDoc = $(iframe.contentWindow.document);
var select = $('select', tb)[0];
iframeDoc.mouseup(function () {
setSelectedType(getSelectionElement(), select);
return true;
});
iframeDoc.keyup(function () {
setSelectedType(getSelectionElement(), select);
var body = $('body', iframeDoc);
if (body.scrollTop() > 0) {
var iframe_height = parseInt(iframe.style['height']);
if (isNaN(iframe_height)) {
iframe_height = 0;
}
var h = Math.min(opts.max_height, iframe_height + body.scrollTop()) + 'px';
iframe.style['height'] = h;
}
return true;
});
return tb;
}
function formatText(command, option) {
iframe.contentWindow.focus();
try {
iframe.contentWindow.document.execCommand(command, false, option);
} catch (e) {
console.log(e)
}
iframe.contentWindow.focus();
}
function setSelectedType(node, select) {
while (node.parentNode) {
var nName = node.nodeName.toLowerCase();
for (var i = 0; i < select.options.length; i++) {
if (nName == select.options[i].value) {
select.selectedIndex = i;
return true;
}
}
node = node.parentNode;
}
select.selectedIndex = 0;
return true;
}
function getSelectionElement() {
if (iframe.contentWindow.document.selection) {
selection = iframe.contentWindow.document.selection;
range = selection.createRange();
try {
node = range.parentElement();
} catch (e) {
return false;
}
} else {
try {
selection = iframe.contentWindow.getSelection();
range = selection.getRangeAt(0);
} catch (e) {
return false;
}
node = range.commonAncestorContainer;
}
return node;
}
enableDesignMode();
});
};
}
})(jQuery);
The contentEditable
DOM attribute is used make the document or a section of it editable. This doesn't work with a <textarea>
; more often an <iframe>
is created and the document inside of it used as an editor.
Mark Pilgrim has an article explaining it on the blog of the Web Hypertext Application Technology Working Group. It includes an example page showing some of the features in use.
精彩评论