【问题标题】:How can I possibly accomplish this Javascript highlighting technique?我怎样才能完成这种 Javascript 突出显示技术?
【发布时间】:2012-03-30 09:01:57
【问题描述】:
<div id="content" contenteditable="false" style="margin:-0.2em 1em; font-family:New Century Schoolbook; font-size:20; color:black; line-height:170%">
        <span style="margin-left:1.7em">Jenny was cute!</span>
        <span style="margin-left:1.7em">She looked happy with the instructor.</span>
        <span style="margin-left:1.7em">Can we meet her again?</span><br>
        <span style="margin-left:18em">Sakura</span>
    </div>

这是我为满足客户需求而创建的一些 HTML。每个句子之间的左边距是为了让我可以在每个句子之间插入一个单独的图像(当图像在 HTML 中时,用户选择变得非常奇怪)。用户需要能够选择、突出显示和添加备忘录到 iBook 应用程序中的部分。但是,与 iBook 应用不同的是,它需要使用格式化文本。所以它需要是可选择的、可编辑的,并且在同一个视图中支持粗体、斜体和下划线。这是我提出的 Javascript(HTML 和 Javascript 的结果不符合标准,但我不在乎,因为这不是网页,我受够了):

function addHighlight(className, id)
{
    var html = '';
    var sel = window.getSelection().getRangeAt(0);
    var container = document.createElement('JimSpan');
    container.id = id;
    container.className = className;
    container.appendChild(sel.extractContents());

    var arrElements = document.getElementsByTagName('span');
    for(i = 0; i < arrElements.length-1; i++)
    {
        if(!arrElements[i].innerText.match(/\S/))
        {
            arrElements[i].parentNode.removeChild(arrElements[i]);
        }
    }

    sel.insertNode(container); 

    return 'js: ADDED HIGHLIGHT';
}

我必须使用“JimSpan”而不是“Span”的原因是用户还需要能够在页面不显示时删除注释,这意味着我必须使用正则表达式手动编辑它。由于有很多跨度,我不知道我的实际何时结束。这很有效,但有一个例外。如果用户选择一个元素的全部和另一个元素的一部分,结果是这样的:

<div id="content" contenteditable="false" style="margin:-0.2em 1em; font-family:New Century Schoolbook; font-size:20; color:black; line-height:170%">
    <jimspan id="memo0" class="pinkHilite"><span style="margin-left:1.7em">Jenny was cute!</span>
    <span style="margin-left:1.7em">She</span></jimspan><span style="margin-left:1.7em"> looked happy with the instructor.</span>
    <span style="margin-left:1.7em">Can we meet her again?</span><br>
    <span style="margin-left:18em">Sakura</span>
</div>

正如您在中间看到的那样,拆分导致句子 She looks happy with the coach 被拆分为两个跨度,每个跨度都有左边距,而我留下了一个巨大的句子中间的空隙。我将接受以下任何一项:

1) 一种让我生成以下(技术上无效,但显示良好)HTML 的方法(如果有办法,我不介意用正则表达式编辑当前范围):

<div id="content" contenteditable="false" style="margin:-0.2em 1em; font-family:New Century Schoolbook; font-size:20; color:black; line-height:170%">
    <jimspan id="memo0" id="pinkHilite"><span style="margin-left:1.7em">Jenny was cute!</span>
    <span style="margin-left:1.7em">She</jimspan> looked happy with the instructor.</span>
    <span style="margin-left:1.7em">Can we meet her again?</span><br>
    <span style="margin-left:18em">Sakura</span>
</div>

2) 一种强制用户选择仅包含 1 个跨度内部的方法(选择必须更改,而不仅仅是受影响的突出显示区域)。

请帮助拯救我的理智 -__-;

【问题讨论】:

  • 试过document.execCommand("HiliteColor", false, "pink")?还是您需要更多地控制高亮样式而不仅仅是背景颜色?
  • 是的,这不会削减它。这是不一致的。有时它添加一个跨度,有时它只是将一个类添加到当前 DOM 样式元素( 变为 等)。另外,我使用的是图像,而不是颜色。最后但并非最不重要的一点是,我需要能够拥有一个与用户编写的备忘录区域相对应的区域,并且 execCommand 有时会将该区域拆分为多个跨度。
  • 我需要能够删除突出显示,以便它返回到应用突出显示之前的状态,并且这种不一致程度不会发生。

标签: javascript uiwebview


【解决方案1】:

选项 2 是最简单的解决方案,并且可以使用 RangeSelection 对象完全实现(排除 IE UIWebView 无关紧要,但对于想要在浏览器中执行类似操作的人来说可能)。下面将选择限制为包含用户开始选择点的元素(注意:为了说明起见,它仅适用于基于鼠标的选择):

现场演示:http://jsfiddle.net/U4smu/

代码:

function isOrIsDescendantOf(node, ancestor) {
    while (node) {
        if (node === ancestor) {
            return true;
        }
        node = node.parentNode;
    }
}

function selectionIsBackwards(sel) {
    var range = document.createRange();
    range.setStart(sel.anchorNode, sel.anchorOffset);
    range.setEnd(sel.focusNode, sel.focusOffset);
    var backwards = range.collapsed;
    range.detach();
    return backwards;
}    

document.onmouseup = function() {
    var sel = window.getSelection();
    var containerEl = sel.anchorNode;
    if (containerEl ) {
        if (containerEl .nodeType == 3) {
            containerEl = containerEl.parentNode;
        }

        if (!isOrIsDescendantOf(sel.focusNode, containerEl)) {
            var backwards = selectionIsBackwards(sel);
            var range = document.createRange();
            if (backwards) {
                range.setStart(containerEl, 0);
                range.setEnd(sel.anchorNode, sel.anchorOffset);
            } else {
                range.setStart(sel.anchorNode, sel.anchorOffset);
                range.setEnd(containerEl, containerEl.childNodes.length);
            }
            sel.removeAllRanges();
            sel.addRange(range);
        }
    }
};

【讨论】:

  • 非常感谢!正如您的个人资料所示,您确实是 Javascript 专家;)。我是 Javascript 灵长类动物 >_
  • @borrrden:这也是我在 JavaScript 中的专业领域 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多