在没有插入多余标签的情况下关闭<ul>标签</ul>

时间:2013-01-23 16:30:25

标签: javascript jquery contenteditable

在一个令人满意的人中使用无序(或有序)列表让我很头疼。

每当我想通过按 ENTER 两次结束编辑列表时,浏览器将关闭<ul />,但会插入<p />(Firefox)或<div /> (Chrome)标记包含<br />
Example here

我的目标是避免多余的<p /><div />,而只关闭<ul />
我尝试修改Tim Down's解决方案,这会阻止浏览器在按 ENTER 时插入<p /><div />,而是插入一个干净的<br />标记。
Example here

不幸但是,在使用该解决方案时,<ul />永远不会被浏览器关闭,因为只有<br />标记插入 in <li />项目。

所以我的问题是:

如何在最后一个空<ul />按Enter键时插入节点或粘贴html来主动关闭<li />

更新: 如果问题很明显:我正在寻找一种方法来关闭<ul />而不插入{{1} }或<p />代码,只需插入好的旧<div />

3 个答案:

答案 0 :(得分:6)

与您的尝试类似,我们会在用户按下Enter键时修改contenteditable:Demo

if (window.getSelection) { // w3c
    $('div').keypress(function (e) {
        var sel, node, children, br, range;
        if (e.which == 13) {
            sel = window.getSelection();
            node = $(sel.anchorNode);
            children = $(sel.anchorNode.childNodes);

            // if nothing is selected and the caret is in an empty <li>
            // (the browser seems to insert a <br> before we get called)
            if (sel.isCollapsed && node.is('li') && (!children.length ||
                    (children.length == 1 && children.first().is('br')))) {
                e.preventDefault();

                // if the empty <li> is in the middle of the list,
                // move the following <li>'s to a new list
                if (!node.is(':last-child')) {
                    node.parent().clone(false)
                        .empty()
                        .insertAfter(node.parent())
                        .append(node.nextAll());
                }

                // insert <br> after list
                br = $('<br>').insertAfter(node.parent());

                // move caret to after <br>
                range = document.createRange();
                range.setStartAfter(br.get(0));
                range.setEndAfter(br.get(0));
                sel.removeAllRanges();
                sel.addRange(range);

                // remove <li>
                node.remove();
            }
        }
    });

} else if (document.selection) { // internet explorer
    $('div').keypress(function (e) {
        var range, node, children;
        if (e.which == 13) {
            range = document.selection.createRange();
            node = $(range.parentElement());
            children = $(range.parentElement().childNodes);

            // if nothing is selected and the caret is in an empty <li>
            // (the browser seems to insert a <br> before we get called)
            if (!range.htmlText.length && node.is('li') && (!children.length ||
                    (children.length == 1 && children.first().is('br')))) {
                e.preventDefault();

                // if the empty <li> is in the middle of the list,
                // move the following <li>'s to a new list
                if (!node.is(':last-child')) {
                    node.parent().clone(false)
                        .empty()
                        .insertAfter(node.parent())
                        .append(node.nextAll());
                }

                // insert <br> after list
                br = $('<br>').insertAfter(node.parent());

                // move caret to after <br>
                range = document.body.createTextRange();
                range.moveToElementText(br.get(0));
                range.collapse(false);
                range.select();

                // remove <li>
                node.remove();
            }
        }
    });
}

请注意,这不会处理用户在按Enter之前选择了某些内容的情况。如果你想处理这种情况,你需要弄清楚用户是否选择了<li>的全部内容(这似乎不是一项简单的任务),如果是,请删除内容和对待它就像用户在空<li>中按Enter键一样。

答案 1 :(得分:1)

我理解你的问题,但不清楚为什么存在这样的要求。澄清这方面可能会有所帮助。

无论如何,这是一个想法。为什么不替换或删除空的<div><p>标记。

$(document).ready(function(){
    $("div").keyup(function(evt) { 
        $("div, p").filter( function() {
                $this = $(this);
            return !($.trim($(this).text()).length);
        }).replaceWith('<br />');
    });
});

工作示例: http://jsfiddle.net/4xyR2/9/

我注意到的一个问题是contenteditable如何使用上述解决方案影响游标。我认为Chrome和Firefox需要<div><p>,以便他们可以跟踪<div>中光标的位置。这来自我在测试时的观察,而不是对浏览器如何解释contenteditable的深刻理解。

Chrome(24.0.1312.52米)似乎不喜欢替换。我在测试它时会看到奇怪的光标位置,但它有效。 Firefox(17.0.1)很好地处理了替换。

答案 2 :(得分:0)

没有Javascript,我能够锻炼的最好的是

HTML:

<div contenteditable="true">
  <div>asdfasdf</div>
</div>

LESS:

div[contenteditable=true] {
  outline: none;

  &>p,
  &>div {
      margin: 0 0 0 30px;
      display: list-item;
  }
}

bin http://jsbin.com/idekix/6/edit

但这里有一些缺点,

  1. Win8上的第一个也是非常大的FireFox 18.0.1,而不是将divp标记作为新行插入,使用类似double br的内容,

  2. 当您删除所有内容并启动类型并点击输入时,第二个发生了,不同的浏览器行为非常不同,Chrome将第一行插入contenteditable容器的正文文本节点,然后放入每个新行进入div,Opera 12.12可以更好地处理它,它永远不会允许删除最后div个节点,IE9-10开始跳转并在你再次开始使用p标签而不是{{1} (这甚至不是这样的灾难,只是不一致),但FireFox还没有尝试改变它的div行为。还尝试使用IE10调试模式检查IE7-8,它与Opera相同,但它不是真正的浏览器。

  3. 它允许你插入空节点的第三个,说到Opera做的好工作,在Opera http://jsbin.com/uxesez/1/edit中看到这个bin,标记在这里更接近原始,并且它没有允许您插入空br

  4. 据说,所有测试都在Windows 8 64位平台上完成,Chrome 24.0.1312.56 m,FireFox 18.0.1,Opera 12.12和IE10通过IE调试栏模拟旧IE。承认在其他平台/版本上,事情可能会有所不同。

    总结以上所有内容,li具有非常好的浏览器支持范围http://caniuse.com/contenteditable,但是每个浏览器都有自己的实现,这是另一个独立的问题。因此,如果没有crossbrowser JavaScrpt麻烦你就无法使用它。另外,我的个人意见contenteditable核心思想更适合像contenteditable的轻量级替换,当它用作浏览器中几乎每个富文本编辑器的元素时。

    来自Mozilla来源https://developer.mozilla.org/en-US/docs/HTML/Content_Editable

    的UPD
      

    在HTML5中,任何元素都可以编辑。这个功能很久以前就已经推出了,但现在已经被WHATWG(html当前规范)标准化了。使用一些JavaScript事件处理程序,您可以将网页转换为完整且快速的富文本编辑器

    下一步是我的拙见。在你的情况下,非常方便,正如我的意见,将使用真正的可编辑字段。我在这个bin http://jsbin.com/ojiyok/7/edit中做的非常多的原型版本仍然有待改进,但看起来它比真正的iframe具有更可预测的行为,而且在这里您可以根据自己的需要更改UI浏览器一下子。