├── js ├── parsers │ ├── jsBase.js │ ├── mootools.js │ ├── dom0.js │ ├── prototype.js │ ├── yui2.js │ ├── extjs.js │ ├── glow.js │ ├── eventi.js │ ├── entwine.js │ ├── jQuery1.3.js │ └── jQuery.js ├── VisualEvent_Loader.js ├── VisualEvent.js └── shCore.js ├── bookmarklet.html ├── Readme.markdown └── css ├── VisualEvent.css └── shCore.css /js/parsers/jsBase.js: -------------------------------------------------------------------------------- 1 | 2 | (function(window, document, $, VisualEvent){ 3 | 4 | /*global jsBase*/ 5 | 6 | VisualEvent.parsers.push( function () { 7 | if ( typeof jsBase == 'undefined' ) { 8 | return []; 9 | } 10 | 11 | var elements = []; 12 | var a = jsBase.aEventCache; 13 | var i, iLen; 14 | 15 | for ( i=0, iLen=a.length ; i 0) { 25 | for (var k=0; k 0) { 37 | elements.push( { 38 | "node": cache.el.dom, 39 | "listeners": listeners 40 | } ); 41 | } 42 | } 43 | } 44 | } 45 | 46 | return elements; 47 | } ); 48 | 49 | })(window, document, jQuery, VisualEvent); 50 | -------------------------------------------------------------------------------- /js/parsers/glow.js: -------------------------------------------------------------------------------- 1 | 2 | (function(window, document, $, VisualEvent){ 3 | 4 | /*global glow*/ 5 | 6 | VisualEvent.parsers.push( function () { 7 | if ( typeof glow == 'undefined' || typeof glow.events.listenersByObjId == 'undefined' ) { 8 | return []; 9 | } 10 | 11 | var listeners = glow.events.listenersByObjId; 12 | var globalGlow = "__eventId"+glow.UID; 13 | var elements = []; 14 | var all = document.getElementsByTagName('*'); 15 | var i, iLen, j, jLen; 16 | var eventIndex, eventType, typeEvents; 17 | 18 | for ( i=0, iLen=all.length ; i 4 | */ 5 | /* global jQuery, VisualEvent */ 6 | "use strict"; 7 | 8 | (function(window, document, $, VE) { 9 | 10 | function entwineParser() { 11 | if (!jQuery || !jQuery.fn.entwine) { 12 | return []; 13 | } 14 | 15 | var out = []; 16 | 17 | for(var namespace in jQuery.entwine.namespaces) { 18 | if (!jQuery.entwine.namespaces.hasOwnProperty(namespace)) { 19 | continue; 20 | } 21 | 22 | var store = jQuery.entwine.namespaces[namespace].store; 23 | 24 | for(var key in store) { 25 | 26 | if (!store.hasOwnProperty(key)) { 27 | continue; 28 | } 29 | 30 | // only look for events, entwine allows other functions too. 31 | if (!key.match(/^on/)) { 32 | continue; 33 | } 34 | 35 | var eventName = key.replace(/^on/, ''); 36 | 37 | for(var i=0; i < store[key].length; i++) { 38 | var binding = store[key][i]; 39 | 40 | if (typeof binding !== 'object' || !binding.selector) { 41 | continue; 42 | } 43 | 44 | var nodes = $(binding.selector.selector); 45 | 46 | for (var j = 0; j < nodes.length; j++) { 47 | out.push({ 48 | node: nodes[j], 49 | listeners: [{ 50 | type: eventName, 51 | func: binding.func.toString(), 52 | removed: false, 53 | source: "jquery.entwine" 54 | }] 55 | }); 56 | } // end node loop 57 | } // end store[key] contents loop 58 | } // end store keys loop 59 | } 60 | return out; 61 | } 62 | 63 | VE.parsers.push(entwineParser); 64 | })(window, document, jQuery, VisualEvent); 65 | -------------------------------------------------------------------------------- /js/parsers/jQuery1.3.js: -------------------------------------------------------------------------------- 1 | 2 | (function(window, document, $, VE){ 3 | 4 | /*global jQuery*/ 5 | 6 | // jQuery 1.3 7 | VE.parsers.push( function () { 8 | if ( !jQuery || VE.versionCompare( jQuery.fn.jquery, '>', '1.3' ) ) { 9 | return []; 10 | } 11 | 12 | var elements = []; 13 | var cache = jQuery.cache; 14 | 15 | for ( var i in cache ) { 16 | if ( typeof cache[i].events == 'object' ) { 17 | var nEventNode = cache[i].handle.elem; 18 | 19 | elements.push( { 20 | "node": nEventNode, 21 | "listeners": [] 22 | } ); 23 | 24 | for ( var type in cache[i].events ) 25 | { 26 | var oEvent = cache[i].events[type]; 27 | var iFunctionIndex; 28 | for ( iFunctionIndex in oEvent) { 29 | break; 30 | } 31 | 32 | /* We use jQuery for the Visual Event events... don't really want to display them */ 33 | var func = oEvent[ iFunctionIndex ].toString(); 34 | if ( !func.match(/VisualEvent/) && !func.match(/EventLoader/) ) 35 | { 36 | elements[ elements.length-1 ].listeners.push( { 37 | "type": type, 38 | "func": func, 39 | "removed": false, 40 | "source": 'jQuery' 41 | } ); 42 | } 43 | } 44 | } 45 | } 46 | 47 | return elements; 48 | } ); 49 | 50 | 51 | // jQuery 1.3 live events 52 | VE.parsers.push( function () { 53 | if ( !jQuery || jQuery.fn.live != 'undefined' || 54 | typeof jQuery.data == 'undefined' || 55 | typeof jQuery.data(document, "events") == 'undefined' || 56 | typeof jQuery.data(document, "events").live == 'undefined' ) 57 | { 58 | return []; 59 | } 60 | 61 | var elements = []; 62 | var cache = jQuery.cache; 63 | 64 | jQuery.each( jQuery.data(document, "events").live || [], function(i, fn) { 65 | var event = fn.type.split('.'); 66 | event = event[0]; 67 | var selector = fn.data; 68 | 69 | $(selector).each( function(i) { 70 | elements.push( { 71 | node: this, 72 | listeners: [], 73 | } ); 74 | 75 | elements[elements.length - 1].listeners.push({ 76 | type: event, 77 | func: 'Unable to obtain function from live() bound event.', 78 | removed: false, 79 | source: "jQuery 1.3 live" 80 | } ); 81 | } ); 82 | } ); 83 | 84 | return elements; 85 | } ); 86 | 87 | })(window, document, jQuery, VisualEvent); 88 | -------------------------------------------------------------------------------- /bookmarklet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Visual Event javascript booklet 6 | 7 | 24 | 25 | 26 | 47 | 48 | 49 |
50 |

Visual Event bookmarklet generator

51 |

52 | Visual Event is a bookmarklet which will visually show you which elements on an HTML 53 | page have Javascript events assigned to them. This page can be used to generate the 54 | bookmarklet that you want to use for testing or deployment of Visual Event. 55 |

56 |

57 | To generate a bookmarklet, modify the Javascript in the textarea below, the 58 | bookmarklet link will be updated as you type (typically you will only need to 59 | change the URL to load Visual Event) and then click and drag the 60 | Visual Event link to your bookmarklet bar. 61 |

62 | 63 |

64 | Visual Event 65 |

66 | 67 | 88 |
89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /js/parsers/jQuery.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | (function(window, document, $, VE) { 4 | 5 | /*global jQuery*/ 6 | 7 | // jQuery 1.5, 1.6 8 | VE.parsers.push( function () { 9 | if ( ! jQuery || 10 | VE.versionCompare( jQuery.fn.jquery, '<', '1.5' ) || 11 | VE.versionCompare( jQuery.fn.jquery, '>=', '1.7' ) ) 12 | { 13 | return []; 14 | } 15 | 16 | var elements = []; 17 | for ( var j in jQuery.cache ) { 18 | jQueryGenericLoop( elements, jQuery.cache[j] ); 19 | } 20 | 21 | return elements; 22 | }); 23 | 24 | 25 | // jQuery 1.4, 1.7 26 | VE.parsers.push( function () { 27 | if ( ! jQuery ) { 28 | return []; 29 | } 30 | 31 | if ( 32 | ( VE.versionCompare( jQuery.fn.jquery, '>=', '1.4' ) && VE.versionCompare( jQuery.fn.jquery, '<', '1.5' ) ) || 33 | ( VE.versionCompare( jQuery.fn.jquery, '>=', '1.7' ) && VE.versionCompare( jQuery.fn.jquery, '<', '1.8' ) ) ) 34 | { 35 | var elements = []; 36 | jQueryGenericLoop( elements, jQuery.cache ); 37 | return elements; 38 | } 39 | 40 | return []; 41 | }); 42 | 43 | 44 | // jQuery 1.8+ 45 | VE.parsers.push( function () { 46 | if ( ! jQuery || VE.versionCompare( jQuery.fn.jquery, '<', '1.8' ) ) { 47 | return []; 48 | } 49 | 50 | var elements = []; 51 | 52 | // Get all 'live' (on) events 53 | $(document).each(function(index1, element) { 54 | jQueryGeneric(elements, element, element); 55 | }); 56 | 57 | // Get events on nodes 58 | $('*').each(function(index1, element) { 59 | jQueryGeneric(elements, element, element); 60 | }); 61 | 62 | return elements; 63 | }); 64 | 65 | 66 | function jQueryGenericLoop (elements, cache) { 67 | $.each( cache, function ( key, val ) { 68 | if ( val.handle ) { 69 | jQueryGeneric(elements, val, val.handle.elem); 70 | } 71 | } ); 72 | } 73 | 74 | function jQueryGeneric (elements, eventsObject, node) { 75 | if ( typeof eventsObject == 'object' ) { 76 | var events; 77 | 78 | if (typeof eventsObject.events == 'object') { 79 | events = eventsObject.events; 80 | } 81 | 82 | if ( ! events ) { 83 | events = $._data(eventsObject, 'events'); 84 | } 85 | 86 | var func; 87 | 88 | for ( var type in events ) { 89 | if ( Object.hasOwnProperty.bind( events )( type ) ) { 90 | /* Ignore live event object - live events are listed as normal events as well */ 91 | if ( type == 'live' ) { 92 | continue; 93 | } 94 | 95 | var oEvents = events[type]; 96 | 97 | for ( var j in oEvents ) { 98 | if ( oEvents.hasOwnProperty( j ) ) { 99 | var aNodes = []; 100 | var sjQuery = "jQuery " + jQuery.fn.jquery; 101 | 102 | if ( typeof oEvents[j].selector != 'undefined' && oEvents[j].selector !== null ) { 103 | aNodes = $(oEvents[j].selector, node); 104 | sjQuery += " (live event)"; 105 | } 106 | else { 107 | aNodes.push( node ); 108 | } 109 | 110 | for ( var k=0, kLen=aNodes.length ; kspan { 33 | color: white !important; 34 | } 35 | 36 | #Event_Label span.Event_LabelClose, 37 | #Event_Label span.Event_LabelHelp { 38 | display: inline-block; 39 | width: 17px; 40 | text-align: center; 41 | border: 1px solid #627ba9; 42 | background-color: #93a8cf; 43 | color: #4b6698; 44 | margin-right: 5px; 45 | cursor: pointer; 46 | *cursor: hand; 47 | } 48 | 49 | #Event_Label span.Event_LabelClose:hover, 50 | #Event_Label span.Event_LabelHelp:hover { 51 | background-color: #aebfdd; 52 | } 53 | 54 | #Event_Label span.Event_LabelHelp { 55 | margin-right: 10px; 56 | } 57 | 58 | #Event_Label span.Event_LabelBy { 59 | display: inline-block; 60 | font-size: 10px; 61 | margin-right: 10px; 62 | } 63 | 64 | #Event_Label span.Event_LabelBy a { 65 | color: #eee; 66 | } 67 | 68 | table.Event_LabelColorInfo td { 69 | text-align: center; 70 | font-size: 12px; 71 | } 72 | 73 | div.Event_LabelColour { 74 | margin: 0 auto; 75 | height: 20px; 76 | width: 20px; 77 | } 78 | 79 | 80 | 81 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 82 | * Help 83 | */ 84 | 85 | #Event_Help { 86 | position: fixed; 87 | top: 0; 88 | right: 0; 89 | bottom: 0; 90 | left: 0; 91 | z-index: 55001; 92 | background-color: #ddd; 93 | color: #222; 94 | font-size: 14px; 95 | font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; 96 | } 97 | 98 | #Event_Help div.Event_HelpInner { 99 | width: 800px; 100 | margin: 30px auto 0 auto; 101 | } 102 | 103 | #Event_Help h1 { 104 | font-size: 18px; 105 | border-bottom: 1px solid #ccc; 106 | color: #222; 107 | } 108 | 109 | #Event_Help p { 110 | margin: 1em 0; 111 | color: #222; 112 | } 113 | 114 | #Event_Help table { 115 | width: 90%; 116 | margin: 0 auto; 117 | } 118 | 119 | #Event_Help p.Event_HelpClose { 120 | text-align: center; 121 | margin-top: 2em; 122 | } 123 | 124 | 125 | 126 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 127 | * Lightbox 128 | */ 129 | 130 | #Event_Lightbox { 131 | position: absolute; 132 | display: none; 133 | color: #111; 134 | width: 660px; 135 | z-index: 55003; 136 | text-align: left; 137 | border-radius: 10px; 138 | -moz-border-radius: 10px; 139 | -webkit-border-radius: 10px; 140 | padding: 5px; 141 | font-size: 12px; 142 | direction : ltr; 143 | background-color: #F8F8F8; 144 | border: 4px solid #7C94C0; 145 | -moz-box-shadow: 3px 3px 5px #111; 146 | -webkit-box-shadow: 3px 3px 5px #111; 147 | box-shadow: 3px 3px 5px #111; 148 | font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; 149 | box-sizing: content-box; 150 | } 151 | 152 | #Event_Lightbox * { 153 | box-sizing: content-box !important; 154 | } 155 | 156 | #Event_Lightbox ul { 157 | list-style-type: none; 158 | margin: 0; 159 | padding: 0; 160 | } 161 | 162 | #Event_Lightbox ul li { 163 | display: block; 164 | width: 90px; 165 | padding: 5px; 166 | cursor: pointer; 167 | *cursor: hand; 168 | } 169 | 170 | #Event_Lightbox ul li.Event_EventSelected { 171 | background-color: #eee; 172 | } 173 | 174 | #Event_Lightbox div.Event_NodeRemove { 175 | float: right; 176 | font-size: 10px; 177 | color: #4E6CA3; 178 | cursor: pointer; 179 | *cursor: hand; 180 | } 181 | 182 | #Event_Lightbox div.Event_NodeRemove:hover { 183 | text-decoration: underline; 184 | } 185 | 186 | #Event_Lightbox #Event_Trigger { 187 | color: #4E6CA3; 188 | cursor: pointer; 189 | *cursor: hand; 190 | } 191 | 192 | #Event_Lightbox #Event_Trigger:hover { 193 | text-decoration: underline; 194 | } 195 | 196 | #Event_Lightbox div.Event_Nav { 197 | float: left; 198 | width: 100px; 199 | } 200 | 201 | #Event_Lightbox div.Event_Code { 202 | float: left; 203 | width: 550px; 204 | background-color: #eee; 205 | padding: 5px; 206 | } 207 | 208 | #Event_Lightbox div.Event_Code p { 209 | padding: 0 0 12px 0; 210 | margin: 0; 211 | } 212 | 213 | #Event_Lightbox div.Event_NodeName { 214 | padding: 5px; 215 | } 216 | 217 | 218 | 219 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 220 | * Display 221 | */ 222 | 223 | #Event_Display { 224 | position: absolute; 225 | top: 0; 226 | left: 0; 227 | height: 100%; 228 | width: 100%; 229 | z-index: 55001; 230 | background-color: rgba(0, 0, 0, 0.2); 231 | } 232 | 233 | 234 | #Event_Display div.Event_info { 235 | float: left; 236 | width: 15px; 237 | height: 15px; 238 | z-index: 55002; 239 | border: transparent 2px solid; 240 | } 241 | 242 | #Event_Help div.Event_bg_blue, 243 | #Event_Display div.Event_bg_blue { 244 | background-color: rgba(0, 0, 255, 0.3); 245 | border: rgba(0, 0, 255, 0.5) 2px solid; 246 | } 247 | 248 | #Event_Display div.Event_bg_blue:hover { 249 | border: rgba(0, 0, 255, 1) 2px solid; 250 | } 251 | 252 | #Event_Help div.Event_bg_red, 253 | #Event_Display div.Event_bg_red { 254 | background-color: rgba(255, 0, 0, 0.3); 255 | border: rgba(255, 0, 0, 0.5) 2px solid; 256 | } 257 | 258 | #Event_Display div.Event_bg_red:hover { 259 | border: rgba(255, 0, 0, 1) 2px solid; 260 | } 261 | 262 | #Event_Help div.Event_bg_yellow, 263 | #Event_Display div.Event_bg_yellow { 264 | background-color: rgba(255, 204, 51, 0.3); 265 | border: rgba(245, 184, 0, 0.5) 2px solid; 266 | } 267 | 268 | #Event_Display div.Event_bg_yellow:hover { 269 | border: rgba(255, 204, 51, 1) 2px solid; 270 | } 271 | 272 | #Event_Help div.Event_bg_green, 273 | #Event_Display div.Event_bg_green { 274 | background-color: rgba(0, 167, 0, 0.3); 275 | border: rgba(0, 167, 0, 0.5) 2px solid; 276 | } 277 | 278 | #Event_Display div.Event_bg_green:hover { 279 | border: rgba(0, 167, 0, 1) 2px solid; 280 | } 281 | 282 | #Event_Help div.Event_bg_purple, 283 | #Event_Display div.Event_bg_purple { 284 | background-color: rgba(167, 0, 145, 0.3); 285 | border: rgba(167, 0, 145, 0.5) 2px solid; 286 | } 287 | 288 | #Event_Display div.Event_bg_purple:hover { 289 | border: rgba(167, 0, 145, 1) 2px solid; 290 | } 291 | 292 | #Event_Help div.Event_bg_orange, 293 | #Event_Display div.Event_bg_orange { 294 | background-color: rgba(201, 145, 35, 0.3); 295 | border: rgba(201, 145, 35, 0.5) 2px solid; 296 | } 297 | 298 | #Event_Display div.Event_bg_orange:hover { 299 | border: rgba(201, 145, 35, 1) 2px solid; 300 | } 301 | 302 | #Event_Help div.Event_bg_black, 303 | #Event_Display div.Event_bg_black { 304 | background-color: rgba(190, 190, 190, 0.3); 305 | border: rgba(190, 190, 190, 0.5) 2px solid; 306 | } 307 | 308 | #Event_Display div.Event_bg_black:hover { 309 | border: rgba(190, 190, 190, 1) 2px solid; 310 | } 311 | -------------------------------------------------------------------------------- /css/shCore.css: -------------------------------------------------------------------------------- 1 | /** 2 | * SyntaxHighlighter 3 | * http://alexgorbatchev.com/SyntaxHighlighter 4 | * 5 | * SyntaxHighlighter is donationware. If you are using it, please donate. 6 | * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 7 | * 8 | * @version 9 | * 3.0.83 (July 02 2010) 10 | * 11 | * @copyright 12 | * Copyright (C) 2004-2010 Alex Gorbatchev. 13 | * 14 | * @license 15 | * Dual licensed under the MIT and GPL licenses. 16 | */ 17 | .Event_syntaxHighlighter a, 18 | .Event_syntaxHighlighter div, 19 | .Event_syntaxHighlighter code, 20 | .Event_syntaxHighlighter table, 21 | .Event_syntaxHighlighter table td, 22 | .Event_syntaxHighlighter table tr, 23 | .Event_syntaxHighlighter table tbody, 24 | .Event_syntaxHighlighter table thead, 25 | .Event_syntaxHighlighter table caption, 26 | .Event_syntaxHighlighter textarea { 27 | -moz-border-radius: 0 0 0 0 !important; 28 | -webkit-border-radius: 0 0 0 0 !important; 29 | background: none !important; 30 | border: 0 !important; 31 | bottom: auto !important; 32 | float: none !important; 33 | height: auto !important; 34 | left: auto !important; 35 | line-height: 1.1em !important; 36 | margin: 0 !important; 37 | outline: 0 !important; 38 | overflow: visible !important; 39 | padding: 0 !important; 40 | position: static !important; 41 | right: auto !important; 42 | text-align: left !important; 43 | top: auto !important; 44 | vertical-align: baseline !important; 45 | width: auto !important; 46 | box-sizing: content-box !important; 47 | font-family: "Source Code Pro","Consolas","Monaco","Bitstream Vera Sans Mono","Courier New",Courier,monospace !important; 48 | font-weight: normal !important; 49 | font-style: normal !important; 50 | font-size: 1em !important; 51 | min-height: inherit !important; 52 | min-height: auto !important; 53 | } 54 | 55 | .Event_syntaxHighlighter { 56 | width: 100% !important; 57 | margin: 1em 0 1em 0 !important; 58 | position: relative !important; 59 | overflow: auto !important; 60 | font-size: 1em !important; 61 | } 62 | .Event_syntaxHighlighter.source { 63 | overflow: hidden !important; 64 | } 65 | .Event_syntaxHighlighter .bold { 66 | font-weight: bold !important; 67 | } 68 | .Event_syntaxHighlighter .italic { 69 | font-style: italic !important; 70 | } 71 | .Event_syntaxHighlighter .line { 72 | white-space: pre !important; 73 | } 74 | .Event_syntaxHighlighter table { 75 | width: 100% !important; 76 | } 77 | .Event_syntaxHighlighter table caption { 78 | text-align: left !important; 79 | padding: .5em 0 0.5em 1em !important; 80 | } 81 | .Event_syntaxHighlighter table td.code { 82 | width: 100% !important; 83 | } 84 | .Event_syntaxHighlighter table td.code .container { 85 | position: relative !important; 86 | } 87 | .Event_syntaxHighlighter table td.code .container textarea { 88 | box-sizing: border-box !important; 89 | position: absolute !important; 90 | left: 0 !important; 91 | top: 0 !important; 92 | width: 100% !important; 93 | height: 100% !important; 94 | border: none !important; 95 | background: white !important; 96 | padding-left: 1em !important; 97 | overflow: hidden !important; 98 | white-space: pre !important; 99 | } 100 | .Event_syntaxHighlighter table td.gutter .line { 101 | text-align: right !important; 102 | padding: 2px 0.5em 2px 1em !important; 103 | } 104 | .Event_syntaxHighlighter table td.code .line { 105 | padding: 2px 1em !important; 106 | } 107 | .Event_syntaxHighlighter.nogutter td.code .container textarea, .Event_syntaxHighlighter.nogutter td.code .line { 108 | padding-left: 0em !important; 109 | } 110 | .Event_syntaxHighlighter.show { 111 | display: block !important; 112 | } 113 | .Event_syntaxHighlighter.collapsed table { 114 | display: none !important; 115 | } 116 | .Event_syntaxHighlighter.collapsed .toolbar { 117 | padding: 0.1em 0.8em 0em 0.8em !important; 118 | font-size: 1em !important; 119 | position: static !important; 120 | width: auto !important; 121 | height: auto !important; 122 | } 123 | .Event_syntaxHighlighter.collapsed .toolbar span { 124 | display: inline !important; 125 | margin-right: 1em !important; 126 | } 127 | .Event_syntaxHighlighter.collapsed .toolbar span a { 128 | padding: 0 !important; 129 | display: none !important; 130 | } 131 | .Event_syntaxHighlighter.collapsed .toolbar span a.expandSource { 132 | display: inline !important; 133 | } 134 | .Event_syntaxHighlighter .toolbar { 135 | position: absolute !important; 136 | right: 1px !important; 137 | top: 1px !important; 138 | font-size: 10px !important; 139 | z-index: 10 !important; 140 | } 141 | .Event_syntaxHighlighter .toolbar span.title { 142 | display: inline !important; 143 | } 144 | .Event_syntaxHighlighter .toolbar a { 145 | display: block !important; 146 | text-align: center !important; 147 | text-decoration: none !important; 148 | padding-top: 1px !important; 149 | } 150 | .Event_syntaxHighlighter .toolbar a.expandSource { 151 | display: none !important; 152 | } 153 | .Event_syntaxHighlighter.ie { 154 | font-size: .9em !important; 155 | padding: 1px 0 1px 0 !important; 156 | } 157 | .Event_syntaxHighlighter.ie .toolbar { 158 | line-height: 8px !important; 159 | } 160 | .Event_syntaxHighlighter.ie .toolbar a { 161 | padding-top: 0px !important; 162 | } 163 | .Event_syntaxHighlighter.printing .line.alt1 .content, 164 | .Event_syntaxHighlighter.printing .line.alt2 .content, 165 | .Event_syntaxHighlighter.printing .line.highlighted .number, 166 | .Event_syntaxHighlighter.printing .line.highlighted.alt1 .content, 167 | .Event_syntaxHighlighter.printing .line.highlighted.alt2 .content { 168 | background: none !important; 169 | } 170 | .Event_syntaxHighlighter.printing .line .number { 171 | color: #bbbbbb !important; 172 | } 173 | .Event_syntaxHighlighter.printing .line .content { 174 | color: black !important; 175 | } 176 | .Event_syntaxHighlighter.printing .toolbar { 177 | display: none !important; 178 | } 179 | .Event_syntaxHighlighter.printing a { 180 | text-decoration: none !important; 181 | } 182 | .Event_syntaxHighlighter.printing .plain, .Event_syntaxHighlighter.printing .plain a { 183 | color: black !important; 184 | } 185 | .Event_syntaxHighlighter.printing .comments, .Event_syntaxHighlighter.printing .comments a { 186 | color: #008200 !important; 187 | } 188 | .Event_syntaxHighlighter.printing .string, .Event_syntaxHighlighter.printing .string a { 189 | color: blue !important; 190 | } 191 | .Event_syntaxHighlighter.printing .keyword { 192 | color: #006699 !important; 193 | font-weight: bold !important; 194 | } 195 | .Event_syntaxHighlighter.printing .preprocessor { 196 | color: gray !important; 197 | } 198 | .Event_syntaxHighlighter.printing .variable { 199 | color: #aa7700 !important; 200 | } 201 | .Event_syntaxHighlighter.printing .value { 202 | color: #009900 !important; 203 | } 204 | .Event_syntaxHighlighter.printing .functions { 205 | color: #ff1493 !important; 206 | } 207 | .Event_syntaxHighlighter.printing .constants { 208 | color: #0066cc !important; 209 | } 210 | .Event_syntaxHighlighter.printing .script { 211 | font-weight: bold !important; 212 | } 213 | .Event_syntaxHighlighter.printing .color1, .Event_syntaxHighlighter.printing .color1 a { 214 | color: gray !important; 215 | } 216 | .Event_syntaxHighlighter.printing .color2, .Event_syntaxHighlighter.printing .color2 a { 217 | color: #ff1493 !important; 218 | } 219 | .Event_syntaxHighlighter.printing .color3, .Event_syntaxHighlighter.printing .color3 a { 220 | color: red !important; 221 | } 222 | .Event_syntaxHighlighter.printing .break, .Event_syntaxHighlighter.printing .break a { 223 | color: black !important; 224 | } 225 | 226 | 227 | 228 | /** 229 | * SyntaxHighlighter 230 | * http://alexgorbatchev.com/SyntaxHighlighter 231 | * 232 | * SyntaxHighlighter is donationware. If you are using it, please donate. 233 | * http://alexgorbatchev.com/SyntaxHighlighter/donate.html 234 | * 235 | * @version 236 | * 3.0.83 (July 02 2010) 237 | * 238 | * @copyright 239 | * Copyright (C) 2004-2010 Alex Gorbatchev. 240 | * 241 | * @license 242 | * Dual licensed under the MIT and GPL licenses. 243 | */ 244 | .Event_syntaxHighlighter { 245 | background-color: white !important; 246 | font-size: 13px !important; 247 | overflow: visible !important; 248 | } 249 | .Event_syntaxHighlighter .line.alt1 { 250 | background-color: white !important; 251 | } 252 | .Event_syntaxHighlighter .line.alt2 { 253 | background-color: #F8F8F8 !important; 254 | } 255 | .Event_syntaxHighlighter .line.highlighted.alt1, .Event_syntaxHighlighter .line.highlighted.alt2 { 256 | background-color: #e0e0e0 !important; 257 | } 258 | .Event_syntaxHighlighter .line.highlighted.number { 259 | color: black !important; 260 | } 261 | .Event_syntaxHighlighter table caption { 262 | color: black !important; 263 | } 264 | .Event_syntaxHighlighter .gutter { 265 | } 266 | .Event_syntaxHighlighter .gutter div { 267 | color: #5C5C5C !important; 268 | } 269 | .Event_syntaxHighlighter .gutter .line.alt1, .Event_syntaxHighlighter .gutter .line.alt2 { 270 | background-color: white !important; 271 | } 272 | .odd .Event_syntaxHighlighter .gutter .line.alt1, .odd .Event_syntaxHighlighter .gutter .line.alt2 { 273 | background-color: #F2F2F2 !important; 274 | } 275 | .Event_syntaxHighlighter .gutter .line { 276 | border-right: 3px solid #4E6CA3 !important; 277 | } 278 | .Event_syntaxHighlighter .gutter .line.highlighted { 279 | background-color: #4E6CA3 !important; 280 | color: white !important; 281 | } 282 | .Event_syntaxHighlighter.printing .line .content { 283 | border: none !important; 284 | } 285 | .Event_syntaxHighlighter.collapsed { 286 | overflow: visible !important; 287 | } 288 | .Event_syntaxHighlighter.collapsed .toolbar { 289 | color: blue !important; 290 | background: white !important; 291 | border: 1px solid #4E6CA3 !important; 292 | } 293 | .Event_syntaxHighlighter.collapsed .toolbar a { 294 | color: blue !important; 295 | } 296 | .Event_syntaxHighlighter.collapsed .toolbar a:hover { 297 | color: red !important; 298 | } 299 | .Event_syntaxHighlighter .toolbar { 300 | color: white !important; 301 | border: none !important; 302 | } 303 | .Event_syntaxHighlighter .toolbar a { 304 | font: 100%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif !important; 305 | color: white !important; 306 | background: #4E6CA3 !important; 307 | float: right !important; 308 | padding: 2px 5px !important; 309 | clear: both; 310 | } 311 | .Event_syntaxHighlighter .toolbar a:hover { 312 | color: #b7c5df !important; 313 | background: #39568b !important; 314 | } 315 | .Event_syntaxHighlighter .plain, .Event_syntaxHighlighter .plain a { 316 | color: black !important; 317 | } 318 | .Event_syntaxHighlighter .comments, .Event_syntaxHighlighter .comments a { 319 | color: #008200 !important; 320 | } 321 | .Event_syntaxHighlighter .string, .Event_syntaxHighlighter .string a { 322 | color: blue !important; 323 | } 324 | .Event_syntaxHighlighter .keyword { 325 | color: #006699 !important; 326 | } 327 | .Event_syntaxHighlighter .preprocessor { 328 | color: gray !important; 329 | } 330 | .Event_syntaxHighlighter .variable { 331 | color: #aa7700 !important; 332 | } 333 | .Event_syntaxHighlighter .value { 334 | color: #009900 !important; 335 | } 336 | .Event_syntaxHighlighter .functions { 337 | color: #ff1493 !important; 338 | } 339 | .Event_syntaxHighlighter .constants { 340 | color: #0066cc !important; 341 | } 342 | .Event_syntaxHighlighter .script { 343 | font-weight: bold !important; 344 | color: #006699 !important; 345 | background-color: none !important; 346 | } 347 | .Event_syntaxHighlighter .color1, .Event_syntaxHighlighter .color1 a { 348 | color: gray !important; 349 | } 350 | .Event_syntaxHighlighter .color2, .Event_syntaxHighlighter .color2 a { 351 | color: #ff1493 !important; 352 | } 353 | .Event_syntaxHighlighter .color3, .Event_syntaxHighlighter .color3 a { 354 | color: red !important; 355 | } 356 | 357 | .Event_syntaxHighlighter .keyword { 358 | font-weight: bold !important; 359 | } 360 | 361 | .datatables_ref:hover { 362 | text-decoration: underline; 363 | cursor: pointer; 364 | *cursor: hand; 365 | } 366 | 367 | .Event_syntaxHighlighter .dtapi { 368 | color: #069; 369 | } 370 | 371 | .Event_syntaxHighlighter .dtapi:hover { 372 | text-decoration: underline; 373 | cursor: pointer; 374 | *cursor: hand; 375 | } 376 | 377 | .Event_syntaxHighlighter table { 378 | table-layout: fixed !important; 379 | } 380 | 381 | .Event_syntaxHighlighter table td.gutter { 382 | width: 46px !important; /* enough for three digits */ 383 | } 384 | 385 | .Event_syntaxHighlighter table td.code { 386 | width: auto !important; 387 | overflow: auto !important; 388 | } 389 | 390 | -------------------------------------------------------------------------------- /js/VisualEvent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @summary Visual Event 3 | * @description Visual Event - show Javascript events which have been attached to objects, and 4 | * the event's associated function code, visually. 5 | * @file VisualEvent_Loader.js 6 | * @author Allan Jardine (www.sprymedia.co.uk) 7 | * @license GPL v2 8 | * @contact www.sprymedia.co.uk/contact 9 | * 10 | * @copyright Copyright 2007-2013 Allan Jardine. 11 | * 12 | * This source file is free software, under the GPL v2 license: 13 | * http://www.gnu.org/licenses/gpl-2.0.html 14 | */ 15 | 16 | (function(window, document, $){ 17 | 18 | /*global VisualEvent,VisualEvent_Loader,VisualEvents,VisualEventSyntaxHighlighter*/ 19 | 20 | 21 | /** 22 | * Visual Event will show, visually, which DOM elements on a web-page have events attached to 23 | * them, information about those events and the code accossiated with each handler for the 24 | * event. It does this by parsing through the cache of Javascript libraries (as there is no DOM 25 | * method to get the information required), thus a major part of Visual Event are the library 26 | * parsers. A result of this is that universal display of events is not possible - there must 27 | * be a parser available. 28 | * 29 | * Visual Event's display is broken into four major areas: 30 | * - Label - The information toolbar at the bottom of the window (fixed) showing Visual Event 31 | * controls (close and help), the name of the program and information about the events that have 32 | * been found on the page. 33 | * 34 | * - Help - The help view is a completely blocking layer which shows information about Visual 35 | * Event and how to use it. A single click will remove the help layer and restore the standard 36 | * Visual Event view. 37 | * 38 | * - Display - A layer which provides a background to Visual Event (thus when Visual Event is 39 | * active is it blocking to the web-page below it) and acts as a container for the boxes (DIVs) 40 | * which serve as a visual indicator that there is an event attached to the element below it 41 | * (sized to match the element with the event attached). 42 | * 43 | * - Lightbox - The event information and code display of attached events. 44 | * 45 | * Note that currently there can only be one instance of Visual Event at a time, due to 46 | * practicality (no point in showing the same thing twice, at the same time) and the use of 47 | * element IDs in the script. 48 | * 49 | * @class VisualEvent 50 | * @constructor 51 | * 52 | * @example 53 | * new VisualEvent(); 54 | */ 55 | window.VisualEvent = function () 56 | { 57 | // Sanity check 58 | if ( ! this instanceof VisualEvent ) { 59 | alert( "VisualEvent warning: Must be initialised with the 'new' keyword." ); 60 | return; 61 | } 62 | 63 | // Only one instance of VisualEvent at a time, in the current running mode. So if there is a 64 | // current instance, shut it down first 65 | if ( VisualEvent.instance !== null ) { 66 | VisualEvent.instance.close(); 67 | } 68 | VisualEvent.instance = this; 69 | 70 | 71 | /** 72 | * Settings object containing customisable information for the class instance 73 | * @namespace 74 | */ 75 | this.s = { 76 | /** 77 | * Array of objects containing information about the nodes which have been found to have 78 | * events attached to them. Each object contains the following parameters: 79 | * {element} node The DOM element in question 80 | * {array} listeners Array of objects which with details about each of the events on this node 81 | * {string} func Source of the event handler (from Function.toString()) 82 | * {string} source Library name / version 83 | * {string} type Type of event (click, change, keyup etc) 84 | * {boolean} removed Flag to indicate if the event has been removed (for API) 85 | * @type array 86 | * @default null 87 | */ 88 | "elements": null, 89 | 90 | /** 91 | * setTimeout reference for delayed hiding of the lightbox layer 92 | * @type int 93 | * @default null 94 | * @private 95 | */ 96 | "mouseTimer": null, 97 | 98 | /** 99 | * Counter for the number of events which have been found from a JS library's cache, but 100 | * are not currently available in the document's DOM 101 | * @type int 102 | * @default null 103 | * @private 104 | */ 105 | "nonDomEvents": 0, 106 | 107 | /** 108 | * Array of objects holding information about each SCRIPT tag that is found in the DOM. Each 109 | * object contains the parameters: 110 | * {string} src The URL of the script source (or inline string if no src attribute) 111 | * {string} code The code (.text) from the script 112 | * @type array 113 | * @default [] 114 | * @private 115 | */ 116 | "scripts": [] 117 | }; 118 | 119 | /** 120 | * DOM elements used by the class instance 121 | * @namespace 122 | */ 123 | this.dom = { 124 | /** 125 | * Label layer - for showing that Visual Event is currently running and information and 126 | * controls, about and for this instance 127 | * @type element 128 | * @default See code 129 | */ 130 | "label": $( 131 | '
'+ 132 | 'x'+ 133 | '?'+ 134 | 'Visual Event by Allan Jardine.'+ 135 | ' events were found attached to '+ 136 | ' nodes. '+ 137 | ' events were attached to elements not currently in the document.'+ 138 | '
')[0], 139 | 140 | /** 141 | * Display layer - background layer and container for Visual Event visual node indicators 142 | * @type element 143 | * @default See code 144 | */ 145 | "display": $('
')[0], 146 | 147 | /** 148 | * Lightbox layer - Template for information display about a given node, and the code for 149 | * a given event handler 150 | * @type element 151 | * @default See code 152 | */ 153 | "lightbox": $( 154 | '
'+ 155 | '
Node: '+ 156 | '
Remove from display
'+ 157 | '
'+ 158 | '
'+ 159 | '
'+ 160 | '
    '+ 161 | '
    '+ 162 | '
    '+ 163 | '
    '+ 164 | '
    ')[0], 165 | 166 | /** 167 | * Help layer - information about Visual Event and how to use it 168 | * @type element 169 | * @default See code 170 | */ 171 | "help": $( 172 | '
    '+ 173 | '
    '+ 174 | '

    Visual Event help

    '+ 175 | '

    Visual Event will show which elements on any given page have Javascript events attached '+ 176 | 'to them, what those events are and the code associated with the events. In Webkit '+ 177 | 'browsers and Opera, Visual Event will also indicate where the code in question was '+ 178 | 'defined.

    '+ 179 | '

    Note that Visual Event is only able to show events for Javascript libraries for which '+ 180 | 'it has a parser. This is currently: DOM0 events, Glow, jQuery, MooTools, Prototype and YUI2.

    '+ 181 | '

    Commands:

    '+ 182 | ''+ 183 | ''+ 184 | ''+ 185 | ''+ 186 | ''+ 187 | ''+ 188 | ''+ 189 | ''+ 190 | ''+ 191 | ''+ 192 | ''+ 193 | ''+ 194 | ''+ 195 | ''+ 196 | ''+ 197 | ''+ 198 | ''+ 199 | ''+ 200 | ''+ 201 | ''+ 202 | ''+ 203 | '
    Double click element with eventHide event indicator. Allows access to nodes underneath
    Key: spaceRestore all events to be visible
    Key: escQuit out of Visual Event
    Key: hShow / hide this help box
    Key: rReload and display events on page
    '+ 204 | '

    The colour of the elements that have been detected to have an event reflect the type of '+ 205 | 'events that are attached to the element:

    '+ 206 | ''+ 207 | ''+ 208 | ''+ 209 | ''+ 210 | ''+ 211 | ''+ 212 | ''+ 213 | ''+ 214 | ''+ 215 | ''+ 216 | ''+ 217 | ''+ 218 | ''+ 219 | ''+ 220 | ''+ 221 | ''+ 222 | ''+ 223 | ''+ 224 | ''+ 225 | '
    Mouse eventUI eventHTML eventMouse + HTMLMouse + UIHTML + UIMouse + HTML + UI
    '+ 226 | '

    Visual Event is open source software (GPLv2). If you would like to contribute an '+ 227 | 'enhancement, please fork the project on '+ 228 | 'Github!

    '+ 229 | '

    Click anywhere to close this help box.

    '+ 230 | '
    '+ 231 | '
    ')[0], 232 | 233 | 234 | /** 235 | * Reference to the visual event node indicator - so we have a reference to what node we are 236 | * showing the lightbox information about 237 | * @type element 238 | * @default See code 239 | */ 240 | "activeEventNode": null 241 | }; 242 | 243 | this._construct(); 244 | }; 245 | 246 | 247 | VisualEvent.prototype = { 248 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 249 | * API methods 250 | */ 251 | 252 | /** 253 | * Shutdown Visual Event and return to the original page 254 | * @param {event} e Event object 255 | */ 256 | "close": function ( e ) 257 | { 258 | // Remove all events that we've added 259 | $('*').unbind('.VisualEvent'); 260 | $(document).unbind( 'keydown.VisualEvent' ); 261 | 262 | $(this.dom.display).remove(); 263 | $(this.dom.lightbox).remove(); 264 | $(this.dom.label).remove(); 265 | $(this.dom.help).remove(); 266 | 267 | if ( typeof VisualEvent_Loader !== 'undefined' && !VisualEvent_Loader.jQueryPreLoaded ) { 268 | $.noConflict(); 269 | } 270 | 271 | VisualEvent.instance = null; 272 | }, 273 | 274 | 275 | /** 276 | * Reinitialise Visual Event (i.e. bring it up-to-date with any new events which might have 277 | * been added 278 | */ 279 | "reInit": function () 280 | { 281 | $('*').unbind('.VisualEvent'); 282 | $(document).unbind( 'keydown.VisualEvent' ); 283 | 284 | $(this.dom.display).empty(); 285 | $(this.dom.display).remove(); 286 | $(this.dom.lightbox).remove(); 287 | $(this.dom.label).remove(); 288 | $(this.dom.help).remove(); 289 | 290 | this.s.elements.splice(0, this.s.elements.length); 291 | this.s.nonDomEvents = 0; 292 | 293 | this._construct(); 294 | }, 295 | 296 | 297 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 298 | * Private methods 299 | */ 300 | 301 | /** 302 | * Visual Event constructor 303 | * @private 304 | */ 305 | "_construct": function () 306 | { 307 | var that = this; 308 | var i, iLen; 309 | var windowHeight = $(document).height(); 310 | var windowWidth = $(document).width(); 311 | 312 | /* Prep the DOM */ 313 | this.dom.display.style.width = windowWidth+'px'; 314 | this.dom.display.style.height = windowHeight+'px'; 315 | 316 | document.body.appendChild( this.dom.display ); 317 | document.body.appendChild( this.dom.lightbox ); 318 | document.body.appendChild( this.dom.label ); 319 | 320 | /* Event handlers */ 321 | $(this.dom.lightbox).bind('mouseover.VisualEvent', function (e) { 322 | that._timerClear( e ); 323 | } ).bind( 'mousemove.VisualEvent', function (e) { 324 | that._timerClear( e ); 325 | } ).bind( 'mouseout.VisualEvent', function (e) { 326 | that._lightboxHide(); 327 | } ); 328 | 329 | $('div.Event_NodeRemove', this.dom.lightbox).bind('click.VisualEvent', function (e) { 330 | that.dom.activeEventNode.style.display = "none"; 331 | that.dom.lightbox.style.display = "none"; 332 | } ); 333 | 334 | $(document).bind( 'keydown.VisualEvent', function( e ) { 335 | if ( e.which === 0 || e.which === 27 ) { // esc 336 | that.close(); 337 | } 338 | if ( e.which === 72 ) { // 'h' 339 | if ( $(that.dom.help).filter(':visible').length === 0 ) { 340 | that._help(); 341 | } 342 | else { 343 | that._hideHelp(); 344 | } 345 | } 346 | else if ( e.which === 32 ) { // space 347 | $('div.EventLabel').css('display', 'block'); 348 | e.preventDefault(); 349 | } 350 | else if ( e.which === 82 ) { // r 351 | that.reInit(); 352 | } 353 | } ); 354 | 355 | /* Build the events list and display */ 356 | this.s.elements = this._eventsLoad(); 357 | for ( i=0, iLen=this.s.elements.length ; i 0 ) { 404 | return; 405 | } 406 | 407 | var loadQueue = []; 408 | var scripts = document.getElementsByTagName('script'); 409 | for ( var i=0, iLen=scripts.length ; i'+this._scriptName(srcFiles[0].src)+':'+ srcFiles[0].line + "
    "; 498 | } else { 499 | origin += srcFiles[0].src+"
    "; 500 | } 501 | } else { 502 | origin = "Function could originate in multiple locations:
    "; 503 | for ( i=0, iLen=srcFiles.length ; i'+this._scriptName(srcFiles[i].src)+':'+srcFiles[i].line+'
    '; 506 | } 507 | } 508 | 509 | return origin; 510 | }, 511 | 512 | 513 | /** 514 | * Get the name of a file from a URL (i.e. the last part in a slash seperated string) 515 | * @param {string} src URL to get the file name from 516 | * @returns {string} File name 517 | * @private 518 | */ 519 | "_scriptName": function ( src ) 520 | { 521 | var a = src.split('/'); 522 | return a[ a.length-1 ]; 523 | }, 524 | 525 | 526 | 527 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 528 | * Display 529 | */ 530 | 531 | /** 532 | * Build the list of nodes that have events attached to them by going through all installed 533 | * parsers 534 | * @returns {array} List of nodes with their associated events 535 | * @private 536 | */ 537 | "_eventsLoad": function () 538 | { 539 | var i, iLen; 540 | var elements=[], libraryListeners; 541 | 542 | /* Gather the events from the supported libraries */ 543 | for ( i=0, iLen=VisualEvent.parsers.length ; i