简体   繁体   English

将文本/ HTML插入所见即所得编辑器

[英]Insert Text/HTML into WYSIWYG Editor

I'm trying to add very specific functionality into a text editor. 我正在尝试将非常特定的功能添加到文本编辑器中。 My users have no need for any actual text formatting or styling, but the interface is greatly improved by being able to place HTML elements into the text editor. 我的用户不需要任何实际的文本格式或样式,但是可以将HTML元素放入文本编辑器中,从而大大改善了界面。

I started by using jQuery Text Editor on top of the textarea in my form. 我首先在表单的文本区域顶部使用jQuery Text Editor I stripped out all of the formatting buttons from the header, so it's basically just a textarea that renders html. 我从标题中剥离了所有格式按钮,因此,基本上,这只是呈现html的文本区域。 My users will be typing or pasting multiple lines of text just like a text editor. 我的用户将像文本编辑器一样输入或粘贴多行文本。 The tricky part for me comes from inserting HTML into that textarea. 对我而言,棘手的部分来自将HTML插入该文本区域。 I have events elsewhere on the page that, when clicked, try to add a button at the current cursor location within the jqte textarea. 我在页面上的其他地方有事件,单击这些事件时,尝试在jqte文本区域内的当前光标位置添加一个按钮。

I found a jQuery snippet to help me locate the caret position. 我找到了一个jQuery代码段来帮助我定位插入符号的位置。 Pulling the caret position out of the div lets me insert the first button at the correct location. 将插入符号的位置拉出div,可以将第一个按钮插入正确的位置。 To maintain my button elements, I have to extract the text field's html(), but I don't know how to get the location of my character within the html, only within the text. 为了维护我的按钮元素,我必须提取文本字段的html(),但是我不知道如何仅在文本中获取字符在html中的位置。 How can I achieve this functionality? 如何实现此功能?

I created a jsFiddle to demonstrate what I'm doing. 我创建了一个jsFiddle来演示我在做什么。 Adding the first button works fine, but once I add the second button, grabbing the substring of html from the text field's text makes the whole thing fall apart. 添加第一个按钮可以正常工作,但是一旦添加第二个按钮,就可以从文本字段的文本中获取html的子字符串,这会使整个过程分崩离析。

Any help is appreciated, thanks! 任何帮助表示赞赏,谢谢!

I didn't realize you can't link to jsFiddle without code, so here's my HTML, CSS, and JS: 我不知道没有代码就无法链接到jsFiddle,所以这是我的HTML,CSS和JS:

HTML 的HTML

<div class='buttons'>
    <button>Item A</button>
    <button>Item B</button>
</div>
<textarea id='text'></textarea>

<div class='btn-group hidden cloneable'>
    <button type='button' class='btn btn-default dropdown-toggle' data-toggle='dropdown'>
        <span class='name'></span> <span class='caret'></span>
    </button>
    <ul class='dropdown-menu' role='menu'>
        <li><a href='#'>Function 1</a></li>
        <li class='divider'></li>
        <li><a href='#'>Function 2</a></li>
    </ul>
</div>

CSS 的CSS

.jqte_editor{
    height: 300px;
}

JS JS

$('#text').jqte({
    b: false,
    center: false,
    color: false,
    fsize: false,
    format: false,
    i: false,
    link: false,
    left: false,
    ol: false,
    remove: false,
    right: false,
    rule: false,
    source: false,
    sub: false,
    strike: false,
    sup: false,
    u: false,
    ul: false,
    unlink: false,
    indent: false,
    outdent: false
});

var $jqte = $('div.jqte_editor');

$('.buttons').on('click', 'button', function(e){
    e.preventDefault();
    insertHtmlAtCaret($(this).text());
});

function insertHtmlAtCaret(text){
    var position = getCaretCharacterOffsetWithin($jqte.get(0));
    var front = $jqte.html().substring(0, position);
    var back = $jqte.html().substring(position, $jqte.text().length); 

    var $group = $('div.cloneable').clone();
    $group.find('span.name').text(text);
    $group.removeClass('hidden cloneable');
    $jqte.html(front).append($group).append(back);
}

function getCaretCharacterOffsetWithin(element){
    var caretOffset = 0;
    var doc = element.ownerDocument || element.document;
    var win = doc.defaultView || doc.parentWindow;
    var sel;
    if (typeof win.getSelection != "undefined") {
        var range = win.getSelection().getRangeAt(0);
        var preCaretRange = range.cloneRange();
        preCaretRange.selectNodeContents(element);
        preCaretRange.setEnd(range.endContainer, range.endOffset);
        caretOffset = preCaretRange.toString().length;
    } else if ( (sel = doc.selection) && sel.type != "Control") {
        var textRange = sel.createRange();
        var preCaretTextRange = doc.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToEnd", textRange);
        caretOffset = preCaretTextRange.text.length;
    }
    return caretOffset;
}

Took a little time but found a JS example that included enough for me to get the functionality I was looking for. 花了一些时间,但是找到了一个JS示例,其中包含的内容足以让我获得想要的功能。 Having no prior knowledge of Ranges, that appeared to be the main portion of the solution: 没有Ranges的先验知识,这似乎是解决方案的主要部分:

function insertButtonAtCaret(name) {
    var node = document.createElement('div');
    node.innerHTML = $('div.cloneable').html();

    $(node).addClass('btn-group');
    $(node).find('span.name').text(name);

    var selection = document.getSelection();
    selection.getRangeAt(0).insertNode(node);
    selection.removeAllRanges();
}

There are still some small issues with the entire solution in general (the button names are in the text area and can be changed), but this is definitely enough for me to work with for now. 总体而言,整个解决方案仍然存在一些小问题(按钮名称在文本区域中,可以更改),但是对于我现在来说,这绝对足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM