I'm working on a small chrome extension for fun, and one thing I need it to be able to do, is to detect when the text inside a div is changed by the webpage itself.The code I'm using is:
var status = document.getElementById("status").innerHTML;
status.onchange = function() {
console.log("CHANGE DETECTED")
And this doesn't seem to work, so what should I use instead?
NOTE: I'd prefer not to use jquery, as I am not even very proficient with javascript at the moment, but if it would be that much simpler/easier, that would be fine.
use this trick
source:https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/
// select the target node
var target = document.querySelector('#some-id');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
You can't do what you want using change event. On newer browsers, you can use Mutation Observers. On older browsers... well, you ask people to upgrade to newer browsers. :P
Related
I have a single page application where a div with a class "abc" is getting loaded dynamically. I want to run a script only after that particular element and all its children have been loaded in the DOM. I don't want to use a timer which calls the function again and again. How do I go about this. This is probably related to mutation observer but I am not understanding how to use that.
Example with mutation observer
var target = document.querySelector('.class');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
So for each mutation of the target element
this code console.log(mutation.type);
will be execute
$(document).on('DOMNodeInserted', '.abc', function() {
});
This will wait until the DOM element is ready and then run your code.
Is there a way to fire a function when element loses some custom attribute? For example, when custom_attribute is removed, then show me some alert. What's the way to do it? Plain JS is preferable, although jQuery is also okay.
<div class="someclass" custom_attribute>...</div>
You can use MutationObserver:
// select the target node
var target = document.querySelector('.someclass');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
fire_function();
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
This fires the fire_function() every time an attribute is changed. So you can check, if the particular attribute is missing or changed.
How would I change the following code (which makes the timeago plugin work) to use the on() function (or others) so that it can be used live? I can't quite seem to figure it out (I'm fairly new to JQuery).
jQuery(document).ready(function() {
jQuery("a.timeago").timeago();
});
How would this be done?
You can use MutationObserver to check when the DOM was modified: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
You pick a node to observe. For your project you should observe the container the a.timeago elements will be created into. <body> is fine but will incur more work for the browser. Then, whenever the dom changes, a callback will be fired. Catch the elements you care about.
Modified from the documentation:
// select the target node
var target = document.querySelector('#your-container');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
mutation.addedNodes.forEach(function(addedNode) {
// if the addedNode matches $('a.timeago')
// $(addedNode).timeago();
});
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
I have a function called x(). I want to call x() every time an arbitrary node's innerHTML property is being changed (please note that I want x() to be called for all nodes, not just 1 node). Initially, I thought innerHTML was a function of the HTMLElement object, and wanted to monkey patch it, but after playing around in Chrome's Javascript console, I failed to find the innerHTML function in the HTMLElement object.
I also thought about using the DOMAttrModified event (http://help.dottoro.com/ljdchxcl.php) but it's not supported in Chrome. Any suggestions are welcome.
#Cecchi's answer is cool but it's not a true monkey patch that applies globally to all HTMLElement instances. Browsers have new capabilities since that answer.
This is tricky because HTMLElement.prototype.innerHTML is a setter, but I was able to get it to work like so:
//create a separate JS context that's clean
var iframe = document.createElement('iframe');
//have to append it to get access to HTMLElement
document.body.appendChild(iframe);
//grab the setter. note that __lookupSetter__ is deprecated maybe try getOwnPropertyDescriptor? anyways this works currently
let origSetter = iframe.contentWindow.HTMLElement.prototype.__lookupSetter__('innerHTML');
//mangle the global HTMLElement in this JS context
Object.defineProperty(HTMLElement.prototype, 'innerHTML', {
set: function (val) {
console.log('innerHTML called', val);
// *** do whatever you want here ***
return origSetter.call(this, val); //allow the method to be called like normal
}
});
Now to test it:
document.createElement('div').innerHTML = '<p>oh, hey</p>';
//logs: innerHTML called <p>oh, hey</p>
Here's a JSBin http://jsbin.com/qikoce/1/edit?js,console
Depending on what you are developing for and the browser support you need (it sounds like just Chrome, and hopefully just modern Chrome), you can look into the MutationObserver interface (exampled borrowed and slightly modified from the Mozilla Hacks Blog:
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
x(mutation.target);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// select the target nodes
Array.prototype.slice.apply(
document.querySelectorAll('.nodes-to-observe')
).forEach(function(target) {
observer.observe(target, config);
});
// later, you can stop observing
observer.disconnect();
More on MutationObservers can be found here:
https://developer.mozilla.org/en-US/docs/DOM/MutationObserver
This was implemented in Chrome 18 & Firefox 14.
I want to write a browser extension that will do something when certain events happen and I am wondering if there is such an API (Firefox or Chrome) already.
I am mostly interested in DOM changes and window changes.
Let's consider this example:
<html>
<head>
<script type="text/javascript">
function addContentToDocument(content){
document.cookie = "debug=true"; //<--- Notify
if(content != null){
document.write(content); //<--- Notify
};
}
</script>
</head>
<body onload="addContentToDocument('Say cheese')">
<h3>My Content</h3>
</body>
</html>
So in this simple example I would be interested in 2 events: document.cookie alteration and document.write method call. I want to be notified in my extension when these things happen.
Not if these statements are present in the available javascript context, but if they are actually being executed.
I tried to search for an API in Firefox extensions and Chrome extensions but couldn't find anything useful.
Thank you.
UPDATE: Other methods I would be interested are the call of eval() method and localStorage modifications
Current Firefox (and Chrome, with the webkit prefix) supports Mutation Observers. I don't think you can trap cookie changes with that, but you can definitely trap changes made to the DOM (whether or not made with document.write).
Example from the Mozilla docs:
// select the target node
var target = document.querySelector('#some-id');
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type);
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
// later, you can stop observing
observer.disconnect();
If you want to monitor changes to a Document open in a tab/window, then MutationObservers are the way to do it. If you want to monitor methods called in pure JS, you'll need to look into the JSEngine apis for Spidermonkey in particular the apis arou nd profiling & tracing:
https://developer.mozilla.org/en-US/docs/SpiderMonkey/JSAPI_User_Guide#Tracing_and_Profiling