blob: 0566ab84af3d555c9ac43dd1d1b4894717efb59b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function watchForTag(tagName, cb) {
if (!document.body)
return;
function findChildTags(queryNode) {
$Array.forEach(queryNode.querySelectorAll(tagName), function(node) {
cb(node);
});
}
// Query tags already in the document.
findChildTags(document.body);
// Observe the tags added later.
var documentObserver = new MutationObserver(function(mutations) {
$Array.forEach(mutations, function(mutation) {
$Array.forEach(mutation.addedNodes, function(addedNode) {
if (addedNode.nodeType == Node.ELEMENT_NODE) {
if (addedNode.tagName == tagName)
cb(addedNode);
findChildTags(addedNode);
}
});
});
});
documentObserver.observe(document, {subtree: true, childList: true});
}
// Expose a function to watch the |tagName| introduction via mutation observer.
//
// We employee mutation observer to watch on any introduction of |tagName|
// within document so that we may handle it accordingly (either creating it or
// reporting error due to lack of permission).
// Think carefully about when to call this. On one hand, mutation observer
// functions on document, so we need to make sure document is finished
// parsing. To satisfy this, document.readyState has to be "interactive" or
// after. On the other hand, we intend to do this as early as possible so that
// developer would have no chance to bring in any conflicted property. To meet
// this requirement, we choose "readystatechange" event of window and use
// capturing way.
function addTagWatcher(tagName, cb) {
var useCapture = true;
window.addEventListener('readystatechange', function listener(event) {
if (document.readyState == 'loading')
return;
watchForTag(tagName, cb);
window.removeEventListener(event.type, listener, useCapture);
}, useCapture);
}
exports.$set('addTagWatcher', addTagWatcher);