Element DOM Tree jQuery plugin – Firebug like functionality | RockingCode

Element DOM Tree jQuery plugin – Firebug like functionality | RockingCode

Element DOM Tree jQuery plugin – Firebug like functionality

11 0
Rate this

Have you even seen G+ Feedback page style? It works pretty much like firebug, when you find something working work, you an ordinary user, will point and click which element is buggy so they will know what they need to do.

Here we’ll see a plugin that allows you to do such functionality. It gives you firebug-like selectors but with one really big advantage, it returns the correct element tree, so you’ll know exactly which element is broken. For instance, if you have a bug report on “#content p” you may never know that actually the broken paragraph was the 10th one.

And we’ll learn a little bit about DOM tree and how to get things easily done without messing around with jQuery (when we don’t need it, of course).

 

Demo & Download

I’ve done a simple test page so you can see how this DOM tree thing works. See the demo or download our sample files so you can easily play and try new things.

DOM tree? What?

No, I’m not talking about this tree.

DOM (Document Object Model) defines a standard way to access and manipulate HTML elements. So window.document means same thing for every browser. It works pretty much like a tree (duh!), where you have parent and children for every element (unless the first and last one, or we’ll enter in an infinite loop).

When you type $(“body”) you are actually saying “Hey jQuery, get this window.document.body element and bring it here in a way that we can manipulate it”. As you can imagine we can actually access and modify things directly via JavaScript, without jQuery. Every “node” stores info about itself and its children, so with a couple of lines we can access precious data about it!

Let’s go through our plugin, now.

HTML & JS

We’ll use jQuery Boilerplate and BootStrap. Both tools help us a lot here, and I think you should be using them :)

After putting a simple dummy content, we’ll get started with functionality.

Activate & De-activate functions

I think it’s not that good have this thing enabled all the time, so we’ll create a simple button and bind clicks on it:

?
1
< a href = "#" id = "elemtree" class = "btn" >Start debugging!</ a >
?
1
2
3
4
5
6
7
8
<script type= "text/javascript" >
     $( function (){
         $( "#elemtree" ).click( function (event){
             event.preventDefault();
             $( "#container" ).eltree();
         });
     });
</script>

Now once plugin is activated all other click functions should be disabled. So what we’ll do is to add this to our plugin file:

?
1
2
3
4
5
6
7
8
9
10
11
12
Plugin.prototype.init = function () {
     var obj = this .obj,
         $ this = "" ,
         debugDiv = "" ,
         debugCss = "" ,
         debugJS = "" ,
         debug = this .options.debug;
 
     obj.addClass( "debugging" ).click( function (event){
         event.preventDefault(); // so links wont be opened while debugging
     });
  };

As you may notice we have a couple of variables there. One really important is the “debug”, since it is our debugging panel. It’s default value is:

?
1
2
3
defaults = {
     debug: "<div id='eltreeDebug'><span id='eltreeCSSSel'></span><span id='eltreeJSSel'></span><a href='#' class='btn primary' id='eltreeStop'>Stop debugging</a></div>"
  };

So, when you call it you create that bigger panel, CSS panel, JS panel and disable button. Disable function will be the easiest one, we’ll just reload page since disabling binds can be bad in some browsers (try enabling / disabling binds 100 times and you’ll know what I’m talking about).

?
1
2
3
4
//prepare remove functions
$( "#eltreeStop" ).click( function (){
     window.location.reload(); // Instead of unbinding everything, just reload page. Now, IE, you can take a deep breath
});

Finding the element’s DOM tree

Now to understand our logic you must to know about 2 DOM accessing functions:

  • parentNode – When #content is your current element, for instance, you parentNode is “body”. It goes up one level on DOM tree
  • childNodes – Again, if your current element is #content childNodes will be all its children (h2, p, blockquote..). It is an array of elements

Our code logic will be:

  • User clicks element
  • Loop starts; Condition: current element isn’t window.element
    • create a parent var
    • check for all child nodes of this parent var, which one is our element
    • now if this element has id, store it, otherwise if it has class, store it,otherwise just get his tagname
    • element’s parent will be our current element

Ok, let’s translate it to JS and put a few other variables to store values that we’ll need:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function selectors(elem) {
     var css = "" ,
         continueCss = 1,
         js = "" ,
         parent = "" ,
         ret = new Array();
 
     while (elem !== window.document) {
         parent = elem.parentNode;
 
         //js selector
         x=0;
         while (  ( $(parent.childNodes[x])[0] !== elem ) && (x < parent.childNodes.length) ) {
             x++;
         }
         //now we have our childNode!
         js = x + "," + js;
 
         //CSS selector
         if (continueCss) {
             if (elem.id) {
                 css = elem.nodeName + '#' + elem.id + " " + css;
                 continueCss = 0;
             } else if (elem.className) {
                 css = elem.nodeName + '.' + elem.className + " " + css;
             } else {
                 css = elem.nodeName + " " + css;
             }
         }
         //let's go up one level
         elem = elem.parentNode;
     }
     //let's make our js selector useful
     js = (js.slice(0, -1)).split( "," );
     for (x=0; x< js.length; x++) {
         js[x] = "childNodes[" + js[x] + "]" ;
     }
     js = "window. document. " + js.join( ". " );
 
     ret[0] = css.toLowerCase(); //css
     ret[1] = js; //js
     return ret;
}

Output function

If you’re planning to use it as a feedback system, it’s these lines that you should change. After we have our selectors this function just display them in our debug panels:

?
1
2
3
4
5
6
function logThis(elem, css, js ) {
     var sel = selectors(elem);
     //if you want to do something else with results (like sending to a feedback plugin) add stuff here
     css.text( sel[0] );
     js.text( sel[1] );
}

Final result!

This is our final plugin code, check it out:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
  *  Project: Rocking Element Tree (a.k.a. eltree)
  *  Description: Adds a firebug-like functionality on page, that gives you element tree and properties by clicking on it
  *  Author: Rochester Oliveira
  *  License: GNU General Public License ( http://en.wikipedia.org/wiki/GNU_General_Public_License )
  */
 
// awesome structure from http://jqueryboilerplate.com/
;( function ( $, window, document, undefined ) {
     // Create the defaults once
     var pluginName = 'eltree' ,
         defaults = {
             debug: "<div id='eltreeDebug'><span id='eltreeCSSSel'></span><span id='eltreeJSSel'></span><a href='#' class='btn primary' id='eltreeStop'>Stop debugging</a></div>"
         };
 
     // The actual plugin constructor
     function Plugin( element, options ) {
         this .element = element;
 
         this .options = $.extend( {}, defaults, options) ;
 
         this ._defaults = defaults;
         this ._name = pluginName;
 
         this .obj = $( this .element);
 
         this .init();
     }
 
     Plugin.prototype.init = function () {
         var obj = this .obj,
             $ this = "" ,
             debugDiv = "" ,
             debugCss = "" ,
             debugJS = "" ,
             debug = this .options.debug;
 
         //add our debugger box and cache
         debugDiv = $(debug).appendTo($( "body" ));
         debugCss = debugDiv.children( "#eltreeCSSSel" );
         debugJS = debugDiv.children( "#eltreeJSSel" );
 
         //prepare remove functions
         $( "#eltreeStop" ).click( function (){
             window.location.reload(); // Instead of unbinding everything, just reload page. Now, IE, you can take a deep breath
         });
         //now we'll add those logger functions
         obj.addClass( "debugging" ).click( function (event){
             event.preventDefault(); // so links wont be opened while debugging
             logThis( event.target, debugCss, debugJS ); //and let's add this to our logger spans
         });
     };
     function logThis(elem, css, js ) {
         var sel = selectors(elem);
         //if you want to do something else with results (like sending to a feedback plugin) add stuff here
         css.text( sel[0] );
         js.text( sel[1] );
     }
     function selectors(elem) {
         var css = "" ,
             continueCss = 1,
             js = "" ,
             parent = "" ,
             ret = new Array();
 
         while (elem !== window.document) {
             parent = elem.parentNode;
 
             //js selector
             x=0;
             while (  ( $(parent.childNodes[x])[0] !== elem ) && (x < parent.childNodes.length) ) {
                 x++;
             }
             //now we have our childNode!
             js = x + "," + js;
 
             //CSS selector
             if (continueCss) {
                 if (elem.id) {
                     css = elem.nodeName + '#' + elem.id + " " + css;
                     continueCss = 0;
                 } else if (elem.className) {
                     css = elem.nodeName + '.' + elem.className + " " + css;
                 } else {
                     css = elem.nodeName + " " + css;
                 }
             }
             //let's go up one level
             elem = elem.parentNode;
         }
         //let's make our js selector useful
         js = (js.slice(0, -1)).split( "," );
         for (x=0; x< js.length; x++) {
             js[x] = "childNodes[" + js[x] + "]" ;
         }
         js = "window. document. " + js.join( ". " );
 
         ret[0] = css.toLowerCase(); //css
         ret[1] = js; //js
         return ret;
     }
     // A really lightweight plugin wrapper around the constructor, preventing against multiple instantiations
     $.fn[pluginName] = function ( options ) {
         return this .each( function () {
             if (!$.data( this , 'plugin_' + pluginName)) {
                 $.data( this , 'plugin_' + pluginName, new Plugin( this , options ));
             }
         });
     }
})(jQuery, window, document);

What do you think?

Don’t be shy and share your thoughts with us ;)

posted on 2014-03-12 19:04  lexus 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/p/3597007.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值