Выясните, по какому номеру строки элемент в домене встречается в Javascript? - PullRequest
18 голосов
/ 11 января 2010

Хотя я никогда не слышал об этом, но возможно ли извлечь узел из DOM с помощью JS, а затем выяснить, в какой строке файла находится этот узел?

Я открыт для всего, плагинов / надстроек для альтернативных браузеров и т. Д. Это не обязательно должно быть кросс-браузерным, скажем.

Я бы предположил, что это каким-то образом возможно, учитывая, что некоторые отладчики JS способны находить номер строки в теге сценария, но я не совсем уверен.

Ответы [ 4 ]

7 голосов
/ 12 января 2010

Хорошо, прости меня за то, как это велико. Я подумал, что это очень интересный вопрос, но, поиграв с ним, я быстро понял, что innerHTML и его аналог довольно ненадежны в отношении сохранения пробелов, комментариев и т. Д. Имея это в виду, я вернулся к созданию полной копии источник, чтобы я мог быть абсолютно уверен, что я получил полный источник. Затем я использовал jquery и несколько (относительно небольших) регулярных выражений, чтобы найти местоположение каждого узла. Кажется, это работает хорошо, хотя я уверен, что пропустил некоторые крайние случаи. И да, да, регулярные выражения и две проблемы, бла-бла-бла.

Редактировать: В качестве упражнения по созданию плагинов jquery я изменил свой код так, чтобы он функционировал достаточно хорошо, в качестве отдельного плагина с примером , аналогичным HTML, найденный ниже (который я оставлю здесь для потомков). Я попытался сделать код немного более устойчивым (например, теперь обрабатывать теги внутри строк в кавычках, например onclick), но самая большая остающаяся ошибка - это то, что он не может объяснить любые изменения на странице, такие как добавление элементов. Возможно, мне понадобится использовать iframe вместо вызова ajax для обработки этого случая.

<code><html>
    <head id="node0">
    <!-- first comment -->
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
        <style id="node1">
/*          div { border: 1px solid black; } */
            pre { border: 1px solid black; }
        </style>
    <!-- second comment -->
        <script>
            $(function() {

                // fetch and display source
                var source;
                $.ajax({
                    url: location.href,
                    type: 'get',
                    dataType: 'text',
                    success: function(data) {
                        source = data;


                        var lines = data.split(/\r?\n/);
                        var html = $.map(lines, function(line, i) {
                            return ['<span id="line_number_', i, '"><strong>', i, ':</strong> ', line.replace(/</g, '&lt;').replace(/>/g, '&gt;'), '</span>'].join('');
                        }).join('\n');

                        // now sanitize the raw html so you don't get false hits in code or comments
                        var inside = false;
                        var tag = '';
                        var closing = {
                            xmp: '<\\/\\s*xmp\\s*>',
                            script: '<\\/\\s*script\\s*>',
                            '!--': '-->'
                        };
                        var clean_source = $.map(lines, function(line) {
                            if (inside && line.match(closing[tag])) {
                                var re = new RegExp('.*(' + closing[tag] + ')', 'i');
                                line = line.replace(re, "$1");
                                inside = false;
                            } else if (inside) {
                                line = '';
                            }

                            if (line.match(/<(script|!--)/)) {
                                tag = RegExp.$1;
                                line = line.replace(/<(script|xmp|!--)[^>]*.*(<(\/(script|xmp)|--)?>)/i, "<$1>$2");
                                var re = new RegExp(closing[tag], 'i');
                                inside = ! (re).test(line);
                            }
                            return line;
                        });

                        // nodes we're looking for
                        var nodes = $.map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(num) { return $('#node' + num) });

                        // now find each desired node in both the DOM and the source
                        var line_numbers = $.map(nodes, function(node) {
                            var tag = node.attr('tagName');
                            var tags = $(tag);
                            var index = tags.index(node) + 1;

                            var count = 0;
                            for (var i = 0; i < clean_source.length; i++) {
                                var re = new RegExp('<' + tag, 'gi');
                                var matches = clean_source[i].match(re);
                                if (matches && matches.length) {
                                    count += matches.length;
                                    if (count >= index) {
                                        console.debug(node, tag, index, count, i);
                                        return i;
                                    }
                                }
                            }


                            return count;
                        });

                        // saved till end to avoid affecting source html
                        $('#source_pretty').html(html);
                        $('#source_raw').text(source);
                        $('#source_clean').text(clean_source.join('\n'));

                        $.each(line_numbers, function() { $('#line_number_' + this).css('background-color', 'orange'); });
                    },
                });

                var false_matches = [
                    "<div>",
                    "<div>",
                    "</div>",
                    "</div>"
                ].join('');

            });
        </script>
    </head>
    <!-- third comment -->
    <body id="node2">
        <div>
            <pre id="source_pretty">
            
            
            
// <xmp> is deprecated, you should put it in <code> instead
<! - четвертый комментарий ->
<! - пятый комментарий ->
1 голос
/ 11 января 2010

Как то так?

var wholeDocument = document.getElementsByTagName('html')[0]
var findNode = document.getElementById('whatever')
var documentUpToFindNode = wholeDocument.substr(0, wholeDocument.indexOf(findNode.outerHTML))
var nlsUpToFindNode = documentUpToFindNode.match(/\n/g).length
1 голос
/ 11 января 2010

Это можно сделать. Начните с получения наивысшего узла в документе следующим образом:

var htmlNode = document.getElementsByTagName('html')[0];
var node = htmlNode;
while (node.previousSibling !== null) {
    node = node.previousSibling;
}
var firstNode = node;

(этот код был протестирован и получил как узел doctype, так и комментарии над узлом html)

Затем вы перебираете все узлы (как родные, так и дочерние). В IE вы будете видеть только элементы и комментарии (не текстовые узлы), поэтому лучше использовать FF или chrome или что-то еще (вы сказали, что это не обязательно будет кросс-браузер).

Когда вы доберетесь до каждого текстового узла , проанализируйте его, чтобы найти возврат каретки.

0 голосов
/ 12 января 2010

Вы можете попробовать: -

 - start at the 'whatever' node, 
 - traverse to each previous node back to the doc begining while concatenating the html of each node, 
 - then count the new lines in your collected HTML.

Опубликуйте код, как только вы его взяли, потому что это хороший вопрос:)

...