如何避免从内容可编辑的< p>中删除键入的文本.在jQuery中 [英] How to avoid removing typed text from contenteditable <p> in jQuery

查看:74
本文介绍了如何避免从内容可编辑的< p>中删除键入的文本.在jQuery中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用jQuery UI拖动组件将<span>添加到可编辑的内容<p>.

I'm using jQuery UI draggable component to add <span> to content editable <p>.

预期的输出是,段落<p>应该是可编辑的,并且可拖动组件应该能够拖放到段落,并且<p>的内容也应该是可编辑的.我的代码有问题.当我在<p>内键入内容并单击外部<p>时.从段落中删除的键入的单词.

The expected output was, paragraph <p> should be editable and the draggable component should able to drag and drop to paragraph and also the content of the <p> should able to be editable. I have problems with my code. When I type something inside <p> and click the outside <p>. typed words removing from the paragraph.

我的代码如下:

$(function() {
  function textWrapper(str, sp, btn) {
    if (sp == undefined) {
      sp = [0, 0];
    }
    var txt = "";
    if (btn) {
      txt = "<span class='w b'>" + str + "</span>";
    } else {
      txt = "<span class='w'>" + str + "</span>";
    }

    if (sp[0]) {
      txt = "&nbsp;" + txt;
    }

    if (sp[1]) {
      txt = txt + "&nbsp;";
    }

    return txt;
  }

  function chunkWords(p) {
    var words = p.split(" ");
    words[0] = textWrapper(words[0], [0, 1]);
    var i;
    for (i = 1; i < words.length; i++) {
      var re = /\[.+\]/;
      if (re.test(words[i])) {
        var b = makeTextBox(words[i].slice(1, -1));
        words[i] = "&nbsp;" + b.prop("outerHTML") + "&nbsp;";
      } else {
        if (words[0].indexOf(".")) {
          words[i] = textWrapper(words[i], [1, 0]);
        } else {
          words[i] = textWrapper(words[i], [1, 1]);
        }
      }
    }
    return words.join("");
  }

  function unChunkWords(tObj) {
    var words = [];
    $(".w", tObj).each(function(i, el) {
      console.log($(el).text(), $(el).attr("class"));
      if ($(el).hasClass("b")) {
        words.push("[" + $(el).text().trim() + "]");
      } else {
        words.push($(el).text().trim());
      }
    });
    return words.join(" ");
  }

  function makeBtn(tObj) {
    var btn = $("<span>", {
      class: "ui-icon ui-icon-close"
    }).appendTo(tObj);
  }

  function makeTextBox(txt) {
    var sp = $("<span>", {
      class: "w b"
    }).html(txt);
    makeBtn(sp);
    return sp;
  }

  function makeDropText(obj) {
    return obj.droppable({
      drop: function(e, ui) {
        var txt = ui.draggable.text();
        var newSpan = textWrapper(txt, [1, 0], 1);
        $(this).after(newSpan);
        makeBtn($(this).next("span.w"));
        makeDropText($(this).next("span.w"));
        $("span.w.ui-state-highlight").removeClass("ui-state-highlight");
      },
      over: function(e, ui) {
        $(this).add($(this).next("span.w")).addClass("ui-state-highlight");
      },
      out: function() {
        $(this).add($(this).next("span.w")).removeClass("ui-state-highlight");
      }
    });
  }

  $("p.given").html(chunkWords($("p.given").text()));

  $("p.given").on("click", ".b > .ui-icon", function() {
    $(this).parent().remove();
  });

  $("p.given").blur(function() {
    var w = unChunkWords($(this));
    console.log(w);
    $(this).html(chunkWords(w));
    makeDropText($("p.given span.w"));
  });

  $("span.given").draggable({
    helper: "clone",
    revert: "invalid"
  });

  makeDropText($("p.given span.w"));
});

p.given {
  display: flex;
  flex-wrap: wrap;
}

p.given span.w span.ui-icon {
  cursor: pointer;
}

div.blanks {
  display: inline-block;
  min-width: 50px;
  border-bottom: 2px solid #000000;
  color: #000000;
}

div.blanks.ui-droppable-active {
  min-height: 20px;
}

span.answers>b {
  border-bottom: 2px solid #000000;
}

span.given {
  margin: 5px;
}

<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="row">
  <p class="given" contenteditable="true">Lorem Ipsum is simply dummy text of the printing and typesetting industry. [Lorem] Ipsum has been the industry's standard dummy text ever since the 1500s, Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</div>

<div class="divider"></div>
<div class="section">
  <section>
    <div class="card blue-grey ">
      <div class="card-content white-text">
        <div class="row">
          <div class="col s12">
            <span class="given btn-flat white-text red lighten-1" rel="1">the Santee, thDakota</span>
            <span class="given btn-flat white-text red lighten-1" rel="2">America</span>
            <span class="given btn-flat white-text red lighten-1" rel="3">Qatar</span>
            <span class="given btn-flat white-text red lighten-1" rel="4">Philippines</span>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

问题间歇出现.

推荐答案

有时用户输入的文本再次被删除,其原因在函数unChunkWords中:

Sometimes the user-entered text is removed again, and the cause is in the function unChunkWords:

此函数仅对 elements (具有类"w")进行迭代,但不对可能在这些元素之间出现的纯文本节点进行迭代.而且,在内容可编辑的元素中,用户确实可以在元素之间 区域中键入文本.因此,unChunkWords中的此循环将永远不会访问此类文本,在返回的数组中将其省略.

This function iterates only over elements (with class "w"), but it does not iterate over the plain text nodes that may occur in-between those elements. And in a content-editable element, the user can indeed type text in areas between elements. And so this loop in unChunkWords will never visit such text, omitting it in the array it returns.

您可以通过将光标放在单词的末尾,空格之前,然后按向右箭头键来强制执行此操作.要么将光标移动到下一个单词的开头,要么不明显移动(它刚刚移出了它所在的span).无论哪种方式,您的光标现在都位于分隔两个单词的文本节点中.键入一些内容,然后单击其他位置. ...异常发生.

You can force it to happen by putting the cursor at the end of a word, before a space, then press the right arrow key. Either this moves the cursor to the start of the next word, or it does not move visibly (it just moved out of the span it was in). Either way, your cursor is now in the text node that separates the two words. Type something and click somewhere else. ... the anomaly happens.

有很多方法可以规避这一点.其中之一是使用jQuery contents()方法,该方法还收集文本节点.更改以下代码:

There are many ways to circumvent this. One of them is to use the jQuery contents() method, which also collects text nodes. Change the following code:

$(".w", tObj).each(function(i, el) {
  if ($(el).hasClass("b")) {
    words.push("[" + $(el).text().trim() + "]");
  } else {
    words.push($(el).text().trim());
  }
});

...对此:

$(tObj).contents().each(function (i, el) {
  if (el.nodeType !== 3 && !$(el).is(".w")) return; // Only regard ".w" or text nodes
  if ($(el).hasClass("b")) {
    words.push("[" + $(el).text().trim() + "]");
  } else {
    words.push($(el).text().trim());
  }
});

现在,即使您在作为内容可编辑元素的直接子元素的文本节点中键入文本,也不会从words中忽略输入的文本.

Now the text you enter will not be omitted from words, even when you type it in text nodes that are direct children of the content-editable element.

您的代码正在使用.join(" ")添加空格,而没有验证p元素的内容中的文本片段是否确实由空格分隔.因此,我只需要获取所有内容(包括空格)并将其连接起来即可.这样,您将获得与p元素中完全一样的单词分隔.

Your code is adding spaces with .join(" ") without verifying that the text fragments are really separated by white space in the content of the p element. So, I would just grab all content, including spacing and just concatenate that. That way you will have the word separations exactly as they are in the p element.

那么您的功能将是:

  function unChunkWords(tObj) {
    var words = "";
    $(tObj).contents().each(function (i, el) {
      if ($(el).hasClass("b")) {
        words += "[" + $(el).text() + "]";
      } else {
        words += $(el).text();
      }
    });
    return words.replace(/\s+/g, " ").trim();
  }

免责声明:我只研究了这个 specific 问题,指出了为什么您会有这种 specific 行为,以及如何解决它.这并不意味着现在您的代码可以在所有预期的功能中正常工作,而这超出了问题的范围.

Disclaimer: I have only looked at this particular problem, pointing out why you have this particular behaviour, and how to fix it. This does not mean that now your code will work correctly in all its intended functionality, which would go beyond the scope of the question.

这篇关于如何避免从内容可编辑的&lt; p&gt;中删除键入的文本.在jQuery中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆