gal007
gal007

Reputation: 7192

How can I get the JS code of an existing HTML element?

I wonder if there's any way to get the JS code of an existing HTML element using any existing method. I am trying to print the code generator of any DOM element, so when the user clicks on any HTML element of the webpage, a message will be shown with the source code to create that element in Javascript.

For example, I have a Div created:

var div = document.createElement("div");
div.style.border = "1px dotted red";
div.onmouseover=function(){div.style.color = "red"};
div.innerHTML = "I'm the div";

And then I was trying to obtain the source code, but:

document.body.appendChild(div.innerHTML);

This option only writes the textual content: "I'm the div". SO I tryed:

document.body.appendChild(div.outerHTML);

But it writes the HTML code without the onmouseover function: "I'm the div"

What I really need is to show this code (or something similar):

var div = document.createElement("div");
div.style.border = "1px dotted red";
div.onmouseover=function(){div.style.color = "red"};
div.innerHTML = "I'm the div";

http://jsfiddle.net/x2zJs/

Do you have any idea where can I start reading? Thanks a lot,

Upvotes: 3

Views: 305

Answers (4)

Tom Bowers
Tom Bowers

Reputation: 5140

If you have control over the creation of the elements you could ensure that each element is created in it's own separate function. Then a simple function can get the function body.

function createElement1() {
    var div = document.createElement("div");
    div.style.border = "1px dotted red";
    div.onmouseover=function(){div.style.color = "red"};
    div.innerHTML = "I'm the div";
}

function getFunctionBody(func) {
    var functionText = func.toString();
    return functionText.slice(functionText.indexOf("{") + 1, functionText.lastIndexOf("}"));
}

Here's a working example. http://jsfiddle.net/C5b7n/

Upvotes: 0

Jan Turoň
Jan Turoň

Reputation: 32912

outerHTML

outerHTML is a good choice with several limitations:

  1. today (2014) you can't get attached listeners natively
  2. outerHTML uses html node serialization, which uses uses xml attributes serialization algorithm

In other words, IDL attributes are ignored, only content attributes are serialized.

Events by IDL attributes are coded as

div.onmouseover=function(){div.style.color = "red"};
div.addEventListener("mouseover",function() {div.style.backgroundColor="blue";});

See more about events

Whereas events by content attributes are coded as

div.setAttribute("onmouseover","this.style.color='red'");

Using content attribute, the outerHTML looks like this:

<div onmouseover="this.style.color='red'" style="border: 1px dotted red;">
  I'm the div
</div>

See your updated fiddle.

Long story short, there are two ways to code a handler:

var setColor = function(e) { e.target.style.color = "red"; }
div.onmouseover = setColor; // IDL, not seen by outerHTML
div.setAttribute("onmouseover","setColor(event)"); // content, seen by outerHTML

eventListenerList

If you want to retrieve the IDL events somehow, nice proposed eventListenerList property was removed from DOM3 spec proposal (see here).

If you want to write a firefox addon (something like code inspector), extending the Element.prototype will do the trick (as I tested, it works in Firefox, Chrome and Opera, it doesn't work in IE7):

(function() {
  Element.prototype.eventListenerList = {};
  Element.prototype._addEventListener = Element.prototype.addEventListener;
  Element.prototype.addEventListener = function(a,b,c) {
    this._addEventListener(a,b,c);
    if(!this.eventListenerList[a]) this.eventListenerList[a] = [];
    this.eventListenerList[a].push(b);
  };
})();

To be precise, you should also override the Element.prototype.removeEventListener to remove the event from the custom EventListenerList.

Now you can add the events by addEventListener as usual:

function handlerA() { alert('a'); }
function handlerB() { alert('b'); }
function handlerC() { alert('c'); }

// attach handlers
div.onclick = handlerC;
div.addEventListener("click",handlerA);
div.addEventListener("click",handlerB);

...and to display the code of the listeners. I will do this for onclick event, in your code you should iterate through every possible event. Don't forget the eventual onclick listener (you can't override Element.prototype.onclick because it is non-configurable property):

var clickListeners = "";
if(div.eventListenerList.click)
div.eventListenerList.click.forEach(function(f) {
  clickListeners+= f.toString();
});
if(div.onclick) clickListeners+= div.onclick.toString();
alert(clickListeners);

See and test the fiddle. Put these pieces together as it suits to your addon.

Upvotes: 2

smnh
smnh

Reputation: 1745

Well, you could wrap the creation of your div element with a function and then parse and print contents of that function.

Following is a working example (tested in Chrome, Firefox and Safari):
Also here http://jsfiddle.net/smnh/x2zJs/2/

function createDiv() {
    var div = document.createElement("div");
    div.style.border = "1px dotted red";
    div.onmouseover = function() {div.style.color = "red"};
    div.innerHTML = "I'm the div";
    div.creationString = getFunctionContnet(createDiv); // noprint
    return div; // noprint
}

function getFunctionContnet(func) {
    var regExp = /function[^(]*\([^)]*\)[^{]*{(?:\s*\n)?(\s*)([\s\S]*)(?:\n\s*)}/,
        match,
        indention, indentionRE,
        noprintRE = /\/\/.*noprint.*/,
        content = null,
        lines, i;

    match = regExp.exec(func.toString());

    if (match !== null) {
        indention = match[1];
        content = match[2];

        lines = content.split("\n");

        // if first line of the function is indented,
        // remove that indention from all function lines.
        if (typeof indention !== "undefined") {
            indentionRE = new RegExp("^" + indention);
            for (i = 0; i < lines.length; i++) {
                if (indentionRE.test(lines[i])) {
                    lines[i] = lines[i].substr(indention.length);
                }
            }
        }

        // don't print lines with "// noprint"
        for (i = lines.length - 1; i >= 0; i--) {
            if (noprintRE.test(lines[i])) {
                lines.splice(i, 1);
            }
        }

        content = lines.join("\n");
    }

    return content;
}

Here if you create your div and log the creationString you will get the text of the function.

div = createDiv();
console.log(div.creationString);

enter image description here

Upvotes: 0

M.J. Saedy
M.J. Saedy

Reputation: 336

There is nothing built-in that will give you what you want, try the "aardvark bookmarklet" it has a somewhat nice js generating command. http://karmatics.com/aardvark/bookmarklet.html

Upvotes: 0

Related Questions