代码之家  ›  专栏  ›  技术社区  ›  Roy Prins

查找未被A标记包围并被A标记环绕的事件

  •  2
  • Roy Prins  · 技术社区  · 12 年前

    我正在努力充分利用HTML 定义列表 ,用作带有工具提示的词汇表。请参阅 this fiddle 用于预期结果(在底部)。

    如果文章中的部分文本与定义列表中的术语匹配,则会显示具有匹配定义的工具提示气泡。这是通过一个环绕的a标签完成的。到现在为止,一直都还不错。

    现在的问题是如何解析文章,以便在词汇表中可以找到的所有部分都会自动被A标记包围。例如,这些术语可以是:

    • 社会团体
    • 群体行为
    • 研究

    解析必须是“贪婪的”,所以它首先解析最长的定义。

    var arr = []; /* Array of terms, sorted by length */
    $('#glossary dt').each( function() { arr.push($(this).text()); });
    arr.sort(function(a,b) { return b.length - a.length; });
    

    接下来,它必须用A标记包围#article.html中第一个数组项的出现,除非它们已经在A标记中。此外,这应该是不区分大小写的。

    /* don't know how to approach this */
    

    最后移动到下一个数组项并重复。

    /* ok, i can figure the loop out myself */
    

    我的问题是检查某个字符串是否已经在a标记中,以及在文本的一部分周围放置a标记。应避免替换,以保持大小写相同。检查JSfiddle以获得预期结果。


    编辑:在下面plalx解决方案的基础上,我得出了以下代码:

    /*
    This script matches text strings in an article with terms in a defintion list (DL);
    the DL acts as a glossary. The text strings are wrapped in '<span>' tags,
    with the 'title' attribute containing the definition. This allows for easy custom tooltips.
    
    - This script is 'greedy' the longest terms are matched first;
    - This script preserves capitalization and escapes HTML in the definitions
     */
    var $article = $('#container-inhoud');
    var $terms = $('#glossary dt');
    //clone to avoid multiple DOM reflows
    var $clone = $article.clone();
    
    //create a regex that matches all glossary terms (not case-sensitive), sorted by length
    var rx = new RegExp('\\b(' + $terms.map(function () {
                return $(this).text();
            }).get().sort(function (term1, term2) {
                        return term2.length - term1.length;
                    }).join('|') + ')\\b', 'ig');
    
    
    var entityMap = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': '&quot;',
        "'": '&#39;',
        "/": '&#x2F;'
    };
    
    function escapeHtml(string) {
        return String(string).replace(/[&<>"'\/]/g, function (s) {
            return entityMap[s];
        });
    }
    
    //wrap any text string that corresponds with a definition term in a 'span' tag
    //the title contains the connected definition.
    function replacer(match){
            var definition = $terms.filter(function() {
                return $(this).text().toLowerCase() == match.toLowerCase();
            }).next('dd').text();
            definition = escapeHtml(definition);
            return '<span class="tooltip" title="' + definition + '">' + match + '</span>';
    }
    
    //call the replace function for every regex match
    $clone.html($clone.html().replace(rx , replacer));
    
    //unwrap the terms in the glossary section (to avoid tooltips within the glossary itself)
    //only needed if the #glossary is within the #article container, otherwise delete the next line.
    $clone.find('#glossary .tooltip').contents().unwrap();
    
    $article.replaceWith($clone);
    

    以下代码显示工具提示。

    /*
     This script displays a tooltip for every 'span' with class 'tooltip'.
     The 'title' attribute will be displayed as the tooltip.
     The tooltip is displayed directly above and in line with the left side of the element.
     Any offsetting is done by manipulation the 'left' and 'top' attributes in the CSS.
     */
    $("span.tooltip").hover(
            function () {
                var bubble = $("#bubble");
                bubble.text($(this).attr('title'));
                var ypos = $(this).offset().top - bubble.height();
                var xpos = $(this).offset().left;
                bubble.css({"left":xpos+"px","top":ypos+"px"});
                bubble.show();
            },
            function () {
                $("#bubble").hide();
            }
    );
    

    我习惯于使用CSS来格式化工具提示气泡:

    #bubble{
                -webkit-border-radius: 4px;
                -moz-border-radius: 4px;
                border-radius: 4px;
                border: 1px solid #888;
                color: #ee6c31;
                background-color: rgba(255, 255, 255, 0.85);
                position:absolute;
                z-index:200;
                padding:5px 8px;
                margin: -15px 5px 5px -10px;
                display:none;
            }
    
    2 回复  |  直到 12 年前
        1
  •  2
  •   plalx    12 年前

    我为你精心设计了一个小解决方案。我想这就是你想要的:

    HTML示例:

    <div id="glossary">
        <dt>test</dt>
        <dt>Testing</dt>
        <dt>something</dt>
        <dt>some other thing</dt>
        <dt>long test</dt>
    </div>
    
    <div id="article">
        this is a test, to see if Testing will correctly be wrapped by something, or some other thing.
        This <a data-glossary-term href="#test">test</a> should not be wrapped again however, <span>something</span> should!
        Very long test should also be wrapped first.
    </div>
    

    JS:

    $(function () {
        var $article = $('#article'),
            //clone to avoid multiple DOM reflows
            $clone = $article.clone(),
            //create a regex that matches all glossary terms (not case-sensitive)
            rx = new RegExp('\\b(' + $('#glossary dt').map(function () {
                return $(this).text();
            }).get().sort(function (term1, term2) {
                return term2.length - term1.length;
            }).join('|') + ')\\b', 'ig');
    
        //unwrap previously wrapped glossary terms to avoid issues
        //this would not be needed if your initial markup doesn't have terms wrapped already
        $clone.find('[data-glossary-term]').each(function () {
            $(this).replaceWith(this.childNodes);
        });
    
        //wrap terms in the 'a' tag
        $clone.html($clone.html().replace(rx, '<a data-glossary-term="$1" href="#$1">$1</a>'));
    
        $article.replaceWith($clone);
    });
    
        2
  •  0
  •   yuvi    12 年前

    不要将dt文本收集到数组中,而是收集dom项本身,然后创建一个类似这样的函数:

    function add_tags(td) {
        var dd = td.next(),
            q = td.text()
            txt = dd.text().replace(q, '<a href="#">'+q+'</a>');
    
        dd.html(txt);
    };
    

    然后循环。你可能想添加一些检查功能,看看你的单词周围是否已经有了a标签,但这是一个很好的开始