Mutation Observers to use in Extensions

2,550 views
Skip to first unread message

Ernest Delgado

unread,
Feb 16, 2012, 3:48:04 PM2/16/12
to Chromium-extensions
Many extensions are currently using Mutation Events to trigger some
action in the extension when a change in the page DOM occurs. Mutation
Events has been deprecated in the DOM spec and will be going away at
some point.

Mutation Observers are faster, safer & fully implemented in Chrome
(Mutation Events were never fully implemented). Mutation Observers are
available in Chrome Beta and are on track to make it to Chrome 18.

Thanks to Rafael Weinstein, we've open-sourced a JS Library that most
use cases will want to use: code.google.com/p/mutation-summary (also
contains more info about Mutation Observers)

If you are currently using Mutation Events and have any question about
it feel free to drop a question here, although we encourage to use our
StackOverflow channel instead: http://stackoverflow.com/questions/tagged/google-chrome-extension

Mohamed Mansour

unread,
Feb 17, 2012, 10:30:48 AM2/17/12
to Ernest Delgado, Chromium-extensions
Hi Ernest,

Would that allow me to rewrite this with Mutation Events?

or even this?

I am using DOMNodeInserted events to listen if a new Element was created.

Kind regards,
Mohamed Mansour




--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To post to this group, send email to chromium-...@chromium.org.
To unsubscribe from this group, send email to chromium-extens...@chromium.org.
For more options, visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/?hl=en.


Rafael Weinstein

unread,
Feb 17, 2012, 1:34:53 PM2/17/12
to Mohamed Mansour, Ernest Delgado, Chromium-extensions
The short answer is: Yes.

Anything you can accomplish with Mutation Events, you should be able
to accomplish with Mutation Observers -- and it'll be faster to boot.

It already looks to me like you'll likely to want to use the Mutation
Summary library for both of these cases.

It looks like you only really care if elements are inserted, so
MutationSummary's "element query" will suit you:

var summaryObserver = new MutationSummary({ callback: handleChanges,
queries: [{ element: "*" }] });
function handleChanges(summaries) {
var elementSummary = summaries[0];
// look for added elements that are significant:
processAddedElements(elementSummary.added);
}

I'm curious about your use cases. Perhaps you can explain a bit more
about what is going on below (i.e. what changes you expect to be
seeing that you are responding to)?

On Fri, Feb 17, 2012 at 7:30 AM, Mohamed Mansour <m...@chromium.org> wrote:
> Hi Ernest,
>
> Would that allow me to rewrite this with Mutation Events?
> https://github.com/mohamedmansour/extended-share-extension/blob/master/js/extended_injection.js#L54

This appears to be listening to DOMNodeInserted and handling two cases:

1) If the inserted node's *grandparent* is the #contentPane, =>
renderAllItems(e.target)
2) If the inserted node is an element with an id that starts with
'update' => look for 'div > div:nth-of-type(3)' and
renderItem(actionBar).

I can't exactly make out what's happening here.

It does look like you are adding a className to the element here to
prevent yourself from doing the same thing twice ('crx-lazy-box') in
response to DOMNodeInserted. If that's true then if you use the
MutationSummary, you may be able to ditch this because it will only
ever tell you about elements that truly *new* within the area of the
document you are observing.

Mohamed Mansour

unread,
Feb 17, 2012, 9:45:43 PM2/17/12
to Rafael Weinstein, Ernest Delgado, Chromium-extensions
Thanks Rafael, I will give it a try. While reading the project page, I really like:

If you need to react to those changes by making more changes -- won’t you hear about those changes the next time it calls you back? Not unless you ask for that. 

That is the reason why I used a className to tell myself that I already rendered. But now I don't need to do that. I will try it out this long weekend!

What I will be doing is basically listening on Google+ DOM:
  1. When new posts happen on the stream. (It gets added to the top of the stream)
  2. When a share dialog appears. (A dom gets created then destroys when your done)
  3. When a hovercard gets shown on the screen (A dom gets created then destroys when your done
Most of them require complex selectors because Google+ uses non human readable class names. And most of it is auto discovery (figuring out if it is a sharebox or a hovercard). So we will see this weekend! 

Thanks,
Mohamed Mansour

Yao Ziyuan

unread,
Apr 15, 2012, 12:09:39 PM4/15/12
to Chromium-extensions
I'm developing a Chrome extension that watches all text changes on web
pages and do some transformation to any new or changed text nodes
(it's like toUppercase every new/changed text node value).

I've looked at the mutation-summary library's project page and played
with pagemirror_extension.

I noticed pagemirror_extension's README says: "Web sites that use
iframes (like Gmail) won't work correctly because this example doesn't
attempt to recursively mirror the contents of iframes."

This is a serious problem. For example, although pagemirror_extension
does well for www.google.com, it can't correctly mirror a G+ search
page like https://plus.google.com/s/is .

If I add

"all_frames": true

to the extension's manifest.json, the extension simply won't mirror
any page at all now.

So if the extension can't be easily adapted to work on pages that use
frames/iframes, is this the extension's problem or is it the mutation-
summary library's inherent problem (i.e. too premature to replace the
good old DOM mutation events)?

Yao Ziyuan

unread,
Apr 15, 2012, 12:43:33 PM4/15/12
to Chromium-extensions
I just wrote this contentscript.js to test the mutation-summary
library. It can't capture new/updated text on https://plus.google.com/u/0/s/is
. Where am I wrong?

if (typeof WebKitMutationObserver != 'function') {
alert("This browser extension requires MutationObservers. Try Chrome
18+.");
return;
}

function handleTextChanges(summaries)
{
var textSummary=summaries[0];
var s="New text:\n\n";
textSummary.added.forEach(function(newText) {
s+=newText.nodeValue+"\n";
});
alert(s);
s="Updated text:\n\n";
textsummary.valueChanged.forEach(function(changedText) {
s+=changedText.nodeValue+"\n";
});
alert(s);
}

var observer = new MutationSummary({
callback: handleTextChanges,
rootNode: document.body,
queries: [{ characterData: true }]
});


On Apr 16, 12:09 am, Yao Ziyuan <yaoziy...@gmail.com> wrote:
> I'm developing a Chrome extension that watches all text changes on web
> pages and do some transformation to any new or changed text nodes
> (it's like toUppercase every new/changed text node value).
>
> I've looked at the mutation-summary library's project page and played
> with pagemirror_extension.
>
> I noticed pagemirror_extension's README says: "Web sites that use
> iframes (like Gmail) won't work correctly because this example doesn't
> attempt to recursively mirror the contents of iframes."
>
> This is a serious problem. For example, although pagemirror_extension
> does well forwww.google.com, it can't correctly mirror a G+ search

Yao Ziyuan

unread,
Apr 15, 2012, 3:31:03 PM4/15/12
to Chromium-extensions
Oh, now I know why my code doesn't work...

On Apr 16, 12:43 am, Yao Ziyuan <yaoziy...@gmail.com> wrote:
> I just wrote this contentscript.js to test the mutation-summary
> library. It can't capture new/updated text onhttps://plus.google.com/u/0/s/is

Rafael Weinstein

unread,
Apr 16, 2012, 4:49:52 PM4/16/12
to Yao Ziyuan, Chromium-extensions
On Sun, Apr 15, 2012 at 9:09 AM, Yao Ziyuan <yaoz...@gmail.com> wrote:
> I'm developing a Chrome extension that watches all text changes on web
> pages and do some transformation to any new or changed text nodes
> (it's like toUppercase every new/changed text node value).
>
> I've looked at the mutation-summary library's project page and played
> with pagemirror_extension.
>
> I noticed pagemirror_extension's README says: "Web sites that use
> iframes (like Gmail) won't work correctly because this example doesn't
> attempt to recursively mirror the contents of iframes."
>
> This is a serious problem. For example, although pagemirror_extension
> does well for www.google.com, it can't correctly mirror a G+ search
> page like https://plus.google.com/s/is .
>
> If I add
>
>    "all_frames": true
>
> to the extension's manifest.json, the extension simply won't mirror
> any page at all now.
>
> So if the extension can't be easily adapted to work on pages that use
> frames/iframes, is this the extension's problem or is it the mutation-
> summary library's inherent problem (i.e. too premature to replace the
> good old DOM mutation events)?

It's simply a case of the extension not attempting to implement it.
It's totally possible -- it's just left as an exercise to the user of
the MutationSummary library.

The basic approach would be to just use a separate instance of
MutationSummary to observe each iframe's contentDocument.

>
> On Feb 17, 4:48 am, Ernest Delgado <erne...@google.com> wrote:
>> Many extensions are currently using Mutation Events to trigger some
>> action in the extension when a change in the page DOM occurs. Mutation
>> Events has been deprecated in the DOM spec and will be going away at
>> some point.
>>
>> Mutation Observers are faster, safer & fully implemented in Chrome
>> (Mutation Events were never fully implemented). Mutation Observers are
>> available in Chrome Beta and are on track to make it to Chrome 18.
>>
>> Thanks to Rafael Weinstein, we've open-sourced a JS Library that most
>> use cases will want to use: code.google.com/p/mutation-summary(also
>> contains more info about Mutation Observers)
>>
>> If you are currently using Mutation Events and have any question about
>> it feel free to drop a question here, although we encourage to use our
>> StackOverflow channel instead:http://stackoverflow.com/questions/tagged/google-chrome-extension
>

Reply all
Reply to author
Forward
0 new messages