Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alter the prototype of an image tag?

Tags:

javascript

dom

I am trying to write a library that would do the following.

When the library is included in the head, it would alter the HTMLImageElement prototype such that any image tag that the user happened to use in their HTML or that they create dynamically in javascript would have a default onerror function that is defined by my library.

The result of this would be that if any of the users images failed to load because they pointed to a bad url my library would handle it in a graceful way.

I am trying the following just as an experiment,

var img = document.createElement('img');
  img.__proto__.onerror = function() {
    alert('hi');
  };
  document.body.innerHTML = '<img id="foo" src="bar.png"/>'

where the file bar.png does not exist and it does not work.

However if I just do something like

  document.body.innerHTML = '<img id="foo" src="bar.png" ' +
    'onerror="this.src = MODIT.getImage(\'blackTile\').src;"/>';

that works fine. Here MODIT.getImage() is a function that returns an image element. You can play with this code here: https://mod.it/ciR_BxqJ/

Is what I'm trying to do possible? Alternatively is there a way to globally catch all 403 GET errors and handle them with javascript in some way?

Thanks!

like image 596
asutherland Avatar asked Aug 09 '13 17:08

asutherland


People also ask

What is the prototype of an object?

The prototype of an object is referred to by the prototype property of the constructor function that creates and initializes the object. The isPrototypeOf() method provides a way to determine if one object is the prototype of another. This technique can be used to determine the class of an object.

What is prototype in JavaScript example?

In JavaScript, every function and object has a property named prototype by default. For example, function Person () { this.name = 'John', this. age = 23 } const person = new Person(); // checking the prototype value console.

What is prototype in JavaScript and how do you use it?

A prototype is an existing inbuilt functionality in JavaScript. Whenever we create a JavaScript function, JavaScript adds a prototype property to that function. A prototype is an object, where it can add new variables and methods to the existing object.

What is prototype in react?

Prototype is a JavaScript framework that aims to ease development of dynamic web applications. It offers a familiar class-style OO framework, extensive Ajax support, higher-order programming constructs, and easy DOM manipulation.


2 Answers

window.addEventListener("error", function(e) {
    if ( e && e.target && e.target.nodeName && e.target.nodeName.toLowerCase() == "img" ) {
        alert( 'Bad image src: ' + e.target.src);
    }
}, true);

See: http://jsfiddle.net/Vudsm/

like image 171
Vlad Avatar answered Sep 21 '22 10:09

Vlad


Important note: Vlad's solution is definitely simpler! But if you want to attach an event listener to any newly added element without using event bubbling (attaching event listeners to the document), read on.


After reading the following questions, I switched to a completely different solution.

  • Modify prototypes of every possible DOM element

  • JavaScript: override Date.prototype.constructor

It seems that one cannot override an event listener (as far as I have researched until now).

The actual solution: DOM mutation events

After creating a MutationObserver, one listens for added nodes, then checks whether they are images and one dynamically adds an error handler.

jsFiddle

function imgError() {
    alert("Failed to load image!");
}

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

var config = {
    childList: true
};

var observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
        var addedNodesCount = mutation.addedNodes.length;
        for (var i=0; i<addedNodesCount; i++) {
            var node = mutation.addedNodes.item(i);

            if (node.tagName == "IMG") {
                node.addEventListener("error", imgError);
            }
        }
    });
});

// pass in the target node, as well as the observer options
observer.observe(document.body, config);

document.body.innerHTML = '<img id="foo" src="bar.png"/>'

You can also use the old DOMNodeInserted event which is also supported by IE 9:

jsFiddle

function imgError() {
    alert("Failed to load image!");
}

document.body.addEventListener("DOMNodeInserted", function (evt) {
    if (evt.target.tagName == "IMG") {
        evt.target.addEventListener("error", imgError);
    }
});

document.body.innerHTML = '<img id="foo" src="bar.png"/>'
like image 21
ComFreek Avatar answered Sep 24 '22 10:09

ComFreek