• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5function watchForTag(tagName, cb) {
6  if (!document.body)
7    return;
8
9  function findChildTags(queryNode) {
10    $Array.forEach(queryNode.querySelectorAll(tagName), function(node) {
11      cb(node);
12    });
13  }
14  // Query tags already in the document.
15  findChildTags(document.body);
16
17  // Observe the tags added later.
18  var documentObserver = new MutationObserver(function(mutations) {
19    $Array.forEach(mutations, function(mutation) {
20      $Array.forEach(mutation.addedNodes, function(addedNode) {
21        if (addedNode.nodeType == Node.ELEMENT_NODE) {
22          if (addedNode.tagName == tagName)
23            cb(addedNode);
24          findChildTags(addedNode);
25        }
26      });
27    });
28  });
29  documentObserver.observe(document, {subtree: true, childList: true});
30}
31
32// Expose a function to watch the |tagName| introduction via mutation observer.
33//
34// We employee mutation observer to watch on any introduction of |tagName|
35// within document so that we may handle it accordingly (either creating it or
36// reporting error due to lack of permission).
37// Think carefully about when to call this. On one hand, mutation observer
38// functions on document, so we need to make sure document is finished
39// parsing. To satisfy this, document.readyState has to be "interactive" or
40// after. On the other hand, we intend to do this as early as possible so that
41// developer would have no chance to bring in any conflicted property. To meet
42// this requirement, we choose "readystatechange" event of window and use
43// capturing way.
44function addTagWatcher(tagName, cb) {
45  var useCapture = true;
46  window.addEventListener('readystatechange', function listener(event) {
47    if (document.readyState == 'loading')
48      return;
49
50    watchForTag(tagName, cb);
51    window.removeEventListener(event.type, listener, useCapture);
52  }, useCapture);
53}
54
55exports.addTagWatcher = addTagWatcher;
56