Невозможно добавить ‹img› в ‹span› в скрипте содержимого расширения Chrome

Я пытаюсь добавить элемент <img> в <span> в сценарии содержимого моего расширения Chrome. Однако кажется, что добавление имеет эффект только тогда, когда я добавляю в body из document, как описано в content-script.js. Чтобы воспроизвести это, щелкните следующую ссылку и откройте инструменты разработчика:

http://kart.finn.no/?mapType=norge&tab=soek_i_annonser&searchKey=search_id_realestate_lettings&mapTitle=Kart+over+bolig+til+leie+&ztr=1&

Найдите <img>, у которого id равно seenIcon. Он будет определен при добавлении в body, но undefined во всех остальных случаях.

manifest.json

{
    "manifest_version": 2,

    "name": "Finn.no Property Blacklist",
    "description": "Hides finn.no property search results that you've marked as \"seen\".",
    "version": "1.0",

    "permissions": [
        "activeTab",
        "http://kart.finn.no/*",
        "storage"
    ],
    "content_scripts": [
        {
            "matches": ["http://kart.finn.no/*"],
            "js": ["content-script.js"]
        }
    ],
    "web_accessible_resources": [
        "*.png"
    ]
}

content-script.js

console.log("content script!")

function getIconSpanIfExists() {
    var spanClassName = "imagePoi";
    var matchingElements = document.getElementsByClassName(spanClassName);
    if (matchingElements.length > 1) {
        console.error(failureMessage("wasn't expecting more than one element with class name " + spanClassName));
        return null;
    }

    if (matchingElements.length === 0) {
        return null;
    }

    return matchingElements[0].parentNode;
}

function htmlReady() {
    return getIconSpanIfExists();
}

function addIcons() {
    var iconSpan = getIconSpanIfExists();

    // Append into body - works.
//    var icon = document.createElement("img");
//    icon.id = "seenIcon";
//    icon.src = chrome.extension.getURL("seen.png");
//    document.body.appendChild(icon);
//    console.log("appended " + icon.id + " into body");

    // Append into span - doesn't work, even though it says childNodes.length is 2.
    var icon = document.createElement("img");
    icon.id = "seenIcon";
    icon.src = chrome.extension.getURL("seen.png");
    icon.style.left = "200px";
    icon.style.top = "200px";
    iconSpan.appendChild(icon);
    console.log("appended " + icon.id + " into span with class imagePoi" + " new children: " + iconSpan.childNodes.length);

    // Modify innerHTML of span - doesn't work, even though innerHTML has the icon.
//    iconSpan.innerHTML += "\n<img id=\"seenIcon\""
//        + "src=\"" + chrome.extension.getURL("seen.png") + "\""
//        + "style=\"left: 200px; top: 200px;\">";
//    console.log(iconSpan.parentNode.id, iconSpan.innerHTML);
}

function init() {
    console.log("initialising content script");

    if (!htmlReady()) {
        console.log("not all HTML is loaded yet; waiting");

        var timer = setInterval(waitForHtml, 200);

        function waitForHtml() {
            console.log("waiting for required HTML elements...");
            if (htmlReady()) {
                clearInterval(timer);
                console.log("... found them!");
                addIcons();
            }
        }

        return;
    }
}

if (document.readyState === "complete") {
    console.log("document is complete")
    init();
} else {
    console.log("document is not yet ready; adding listener")
    window.addEventListener("load", init, false);
}

seen.png

увиденный.png

Почему изменения не отражаются в DOM?


person Mitch    schedule 25.07.2015    source источник


Ответы (1)


Узел пересоздается сайтом, поэтому нужно немного подождать после его первого появления и только потом добавлять новое изображение.

Я протестировал его с помощью простого пользовательского скрипта с MutationObserver, который добавляет новый значок каждый раз, когда .imagePoi добавляется в документ, включая первые два появления и последующие при увеличении/уменьшении масштаба.

setMutationHandler(document, '.imagePoi', function(observer, node) {
  node.parentNode.insertAdjacentHTML('beforeend',
    '<img src="http://www.dna-bioscience.co.uk/images/check-mark.gif">');
});

function setMutationHandler(baseNode, selector, cb) {
  var ob = new MutationObserver(function(mutations) {
    for (var i=0, ml=mutations.length, m; (i<ml) && (m=mutations[i]); i++)
      for (var j=0, nodes=m.addedNodes, nl=nodes.length, n; (j<nl) && (n=nodes[j]); j++)
        if (n.nodeType == 1) 
          if (n = n.matches(selector) ? n : n.querySelector(selector))
            if (!cb(ob, n))
              return;
  });
  ob.observe(baseNode, {subtree:true, childList:true});
}

Вы можете упростить обработчик, используя тот факт, что запись мутации .imagePoi target имеет finnPoiLayer в своем списке классов. Но он может сломаться при незначительном изменении макета сайта.

person wOxxOm    schedule 25.07.2015
comment
Первоначально я использовал MutationObserver и в итоге получил несколько цепочек функций, которые очень похожи на функцию setMutationHandler() выше, поэтому я переключился на простой таймер в соответствии с этот совет. Я не знал, что вы можете наблюдать, как вложенные дочерние элементы добавляются с помощью MutationObserver... Я вижу, что аргумент subtree мог бы быть весьма полезным, чтобы избежать этих цепочек. :) - person Mitch; 26.07.2015
comment
Я попробовал это, но <img> по-прежнему не создается для меня по моей исходной ссылке. Я добавил пару console.log() в обратном вызове load и перед вызовом insertAdjacentHTML(), но ничего не было напечатано. Я также дал <img> id, но не смог найти его после загрузки страницы. - person Mitch; 26.07.2015
comment
Ваш код работает с проверкой if (document.readyState === "complete"), спасибо! Возможно, стоит добавить это к вашему ответу на случай, если у кого-то еще возникнет такая же проблема. - person Mitch; 26.07.2015
comment
Кстати, а почему вы его отключаете в первый раз? Разве не достаточно оставить его подключенным? - person Mitch; 26.07.2015
comment
Я отключаю его, чтобы пропустить работу в первый раз, но, видимо, в этом нет необходимости. - person wOxxOm; 26.07.2015