Javascript: удаляются пробельные символы в Chrome (но не в Firefox) - PullRequest
1 голос
/ 02 июня 2010

Почему нижеприведенное ниже устраняет пробелы вокруг сопоставленного текста ключевого слова при его замене на якорную ссылку? Обратите внимание, что эта ошибка возникает только в Chrome, а не в Firefox.

Для полного контекста файл находится по адресу: http://seox.org/lbp/lb-core.js

Для просмотра кода в действии (пока не найдено ни одной ошибки), демонстрационная страница находится по адресу http://seox.org/test.html. Копирование / вставка первого абзаца в текстовый редактор (например, Dreamweaver или Gmail с включенным текстовым редактором) на) раскроет проблему со словами, сгруппированными вместе. Вставить его в простой текстовый редактор не удастся.

// Find page text (not in links) -> doxdesk.com
function findPlainTextExceptInLinks(element, substring, callback) {
    for (var childi= element.childNodes.length; childi-->0;) {
        var child= element.childNodes[childi];
        if (child.nodeType===1) {
            if (child.tagName.toLowerCase()!=='a')
                findPlainTextExceptInLinks(child, substring, callback);
        } else if (child.nodeType===3) {
            var index= child.data.length;
            while (true) {
                index= child.data.lastIndexOf(substring, index);
                if (index===-1 || limit.indexOf(substring.toLowerCase()) !== -1)
                    break;
                // don't match an alphanumeric char
                var dontMatch =/\w/;
                if(child.nodeValue.charAt(index - 1).match(dontMatch) || child.nodeValue.charAt(index+keyword.length).match(dontMatch))
                    break;
                // alert(child.nodeValue.charAt(index+keyword.length + 1));
                callback.call(window, child, index)
            }
        }
    }
}

// Linkup function, call with various type cases (below)
function linkup(node, index) {

    node.splitText(index+keyword.length);
    var a= document.createElement('a');
    a.href= linkUrl;
    a.appendChild(node.splitText(index));
    node.parentNode.insertBefore(a, node.nextSibling);
    limit.push(keyword.toLowerCase()); // Add the keyword to memory
    urlMemory.push(linkUrl); // Add the url to memory
}

// lower case (already applied)
findPlainTextExceptInLinks(lbp.vrs.holder, keyword, linkup);

Заранее спасибо за помощь. Я почти готов запустить сценарий и с удовольствием оставлю вам комментарии за вашу помощь.

Ответы [ 2 ]

2 голосов
/ 02 июня 2010

Это не имеет ничего общего с функциональностью связывания; это происходит со скопированными ссылками, которые уже есть на странице, и с содержимым credit, даже если вызов processSel() закомментирован.

Кажется, это странная ошибка в функции расширенного копирования текста Chrome. Содержание в holder в порядке; если вы клонируете содержимое выбранного диапазона и в конце предупреждаете его innerHTML, пробелы явно присутствуют. Но пробелы непосредственно перед, сразу после и на внутренних границах любого встроенного элемента (не только ссылки!) Не отображаются в расширенном тексте.

Даже если вы добавите новые текстовые узлы в DOM, содержащие пробелы рядом со ссылкой, Chrome проглотит их. Я смог заставить его выглядеть правильно, вставив неразрывные пробелы:

var links= lbp.vrs.holder.getElementsByTagName('a');
for (var i= links.length; i-->0;) {
    links[i].parentNode.insertBefore(document.createTextNode('\xA0 '), links[i]);
    links[i].parentNode.insertBefore(document.createTextNode(' \xA0), links[i].nextSibling);
}

но это довольно уродливо, должно быть ненужным и не исправляет другие встроенные элементы. Bad Chrome!

var keyword = links[i].innerHTML.toLowerCase();

Неразумно полагаться на innerHTML для получения текста от элемента, поскольку браузер может экранировать или не экранировать символы в нем. В частности, &, но нет никаких гарантий относительно того, какие символы выводит свойство innerHTML браузера.

Поскольку вы, похоже, уже используете jQuery, возьмите содержимое с помощью text().

var isDomain = new RegExp(document.domain, 'g');
if (isDomain.test(linkUrl)) { ...

Это будет сбой каждый второй раз, потому что g регулярные выражения запоминают свое предыдущее состояние (lastIndex): при использовании с такими методами, как test, вы должны продолжать вызывать несколько раз, пока они не вернут соответствия .

Кажется, вам здесь не нужно g (несколько совпадений) ... но и здесь вам не нужно регулярное выражение, так как простая строка indexOf будет более надежной. (В регулярном выражении каждый . в домене будет соответствовать любому символу в ссылке.)

Более того, используйте свойства декомпозиции URL на Location, чтобы выполнить прямое сравнение имен хостов, а не грубое сопоставление строк по всему URL:

if (location.hostname===links[i].hostname) { ...

1039 *

// don't match an alphanumeric char
var dontMatch =/\w/;
if(child.nodeValue.charAt(index - 1).match(dontMatch) || child.nodeValue.charAt(index+keyword.length).match(dontMatch))
    break;

Если вы хотите сопоставлять слова на границах слов и без учета регистра, я думаю, вам лучше использовать регулярное выражение, а не простое сопоставление подстрок. Это также спасло бы от четырех вызовов на findText для каждого ключевого слова, как сейчас. Вы можете получить внутренний бит (в if (child.nodeType==3) { ...) функции в этого ответа и использовать его вместо текущего совпадения строки.

Раздражающая вещь при создании регулярных выражений из строки - это добавление загрузки обратной косой черты к пунктуации, поэтому вам понадобится функция для этого:

// Backslash-escape string for literal use in a RegExp
//
function RegExp_escape(s) {
    return s.replace(/([/\\^$*+?.()|[\]{}])/g, '\\$1')
};

var keywordre= new RegExp('\\b'+RegExp_escape(keyword)+'\\b', 'gi');

Вы можете даже сделать все замены ключевых слов за один раз для повышения эффективности:

var keywords= [];
var hrefs= [];
for (var i=0; i<links.length; i++) {
    ...
    var text= $(links[i]).text();
    keywords.push('(\\b'+RegExp_escape(text)+'\\b)');
    hrefs.push[text]= links[i].href;
}
var keywordre= new RegExp(keywords.join('|'), 'gi');

, а затем для каждого совпадения в linkup проверьте, какая группа совпадений имеет ненулевую длину, и укажите ссылку с hrefs[ того же номера.

0 голосов
/ 02 июня 2010

Я хотел бы помочь вам больше, но трудно угадать, не имея возможности его протестировать, но я полагаю, что вы можете обойти это, добавив символы пробела вокруг ваших ссылок, например. &nbsp;.

Кстати, эта ваша функция, которая добавляет полезные ссылки при копировании, действительно интересна.

...