31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Andres Suarez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/eventPage.js:
--------------------------------------------------------------------------------
1 | /* global chrome, jQueryAudit */
2 |
3 | // The DevTools page is the only one that can "eval" code within
4 | // the context of the inspected page. But, it has no way of knowing
5 | // that the panel was closed. So, we need this trickery to clean up
6 | // after the DevTools are closed.
7 |
8 | var cleanup = serializeAsIIFE(function(imports) {
9 | var script = document.createElement('script');
10 | script.innerHTML = imports.remove;
11 | document.head.appendChild(script);
12 | setTimeout(function() {
13 | document.head.removeChild(script);
14 | });
15 | }, {
16 | remove: serializeAsIIFE(function() {
17 | if (!window.jQueryAudit) return;
18 | jQueryAudit.cleanup();
19 | delete window.jQueryAudit;
20 | })
21 | });
22 |
23 | chrome.runtime.onConnect.addListener(function(port) {
24 | if (port.name !== 'devtools-jqueryaudit') return;
25 |
26 | var tabId;
27 | var tabIdListener = function(message/*, sender, sendResponse*/) {
28 | if (!message.tabId) return;
29 | tabId = message.tabId;
30 | port.onMessage.removeListener(tabIdListener);
31 | };
32 | port.onMessage.addListener(tabIdListener);
33 |
34 | port.onDisconnect.addListener(function() {
35 | if (tabId == null || !chrome.tabs) return;
36 | chrome.tabs.executeScript(tabId, {
37 | code: cleanup
38 | });
39 | });
40 |
41 | });
42 |
43 | function serializeAsIIFE(fn) {
44 | var params = Array.prototype.slice
45 | .call(arguments, 1)
46 | .map(function(arg) {
47 | return JSON.stringify(arg);
48 | }).join(',');
49 | return [ '(', fn.toString(), ')(', params, ')' ].join('');
50 | }
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jQuery Audit
2 | ------------
3 |
4 | #### **Install it from the [Chrome Web Store](https://chrome.google.com/webstore/detail/jquery-audit/dhhnpbajdcgdmbbcoakfhmfgmemlncjg/).**
5 |
6 | `jQuery Audit` is a Chrome Developer Tools extension for ~~debugging~~ auditing jQuery — it creates a sidebar in the `Elements panel` containing jQuery **delegated events**, internal data, and more, as **live `DOM nodes`, `functions`, and `objects`**.
7 |
8 | 
9 |
10 |
11 | ##### Live `DOM nodes`, `functions`, and `objects`
12 | * Variables in the `jQuery Audit` sidebar behave like objects in the `Sources panel` → `Scope Variables` sidebar. You can right-click on a `function` and goto **"Show Function Definition"**, or hover over a `DOM node` to highlight it in the document, as well as right-clicking it to **"Reveal in Elements Panel"**.
13 |
14 | 
15 |
16 |
17 | ##### Direct access to the `document` and `window` objects
18 | * The `document` and the `window` objects don't have representations in the `Elements panel` but can nonetheless be event targets and/or have associated jQuery data. `jQuery Audit` adds two comment nodes above the `` to represent them. The `` as a stand-in for the `document` object, and the `` as a stand-in for the `window` object. Select either to audit the represented object in the `jQuery Audit` sidebar.
19 |
20 | 
21 |
22 | **Requirements:** `jQuery Audit` does a `typeof window.jQuery === 'function'` whenever a `node` is selected. If it can't find a `jQuery` function in the global scope, the sidebar will display `Error: "@(window.jQuery is missing)"`.
23 |
24 | **Tip:** Text wrapped in `@(...)` are "messages" from `jQuery Audit`. This was the compromise made to get live objects in the sidebar and be able to show informative messages.
25 |
26 | ***
27 |
28 | ### Sidebar sections
29 |
30 | ##### `@(this element)`
31 | * The element currently selected.
32 |
33 | ##### `Data`
34 | * _Data_ contains the would-be result of invoking `$(element).data()`. `jQuery Audit` doesn't invoke `.data()` because calling it creates a data object in jQuery's internal store if one doesn't already exist for that element. Instead, `jQuery Audit` directly looks in the internal store for the data object and returns it. If there isn't one, you'll see `@(none)`, or if it's an empty object you'll see `@(empty Object)`.
35 |
36 | ##### `Events([number_of_events])`
37 | * These are the events that the element would **react to**. That means any delegated events, or any directly bound events that don't delegate. (Directly bound events are under `Internal Data` → `events`). For each event name, there is a corresponding jQuery event object associated with it, that has:
38 | * a `delegator`: The ancestor element that delegates the event, or `@(this element)` when the event is directly bound to the element and there is no delegation.
39 | * a `handler`: The function that handles the event. More often than not, the `handler` is a _bound_ function and not directly the function that does the "work". The section below on [Finding bound handlers](#finding-bound-handlers) shows you where common _binder_ functions store the _bound_ function.
40 | * And more.
41 |
42 | ##### `Internal Data`
43 | * The internal data jQuery keeps on the element - it is the result of calling `$._data(element)`. This is not the same as the data object from `$(element).data()`, though the data object is kept here in the internal store.
44 |
45 | ##### `dataset`
46 | * The value of `HTMLElement.dataset`. This is not the same as _Data_ above, but closely related to it. `HTMLElement.dataset` contains the raw `data-*` attributes. While _Data_ is the parsed content of any `data-*` attributes jQuery found on the element along with any other arbitrary information. (jQuery converts `Boolean`, `Number` and `JSON` in `data-*` attributes when you call `.data()`).
47 |
48 | ##### `own HTML`
49 | * The result of removing the `innerHTML` from the `outerHTML` of an element. This helps debug character encoding issues, since what the `Elements panel` shows is a decoded "pretty" version of the HTML and not the actual HTML.
50 |
51 | ### Finding bound handlers
52 | Often event `handlers` are _bound_ functions. In these cases, the function under `Events` → `event_name` → `handler` is the `binder` function and not the `bindee`. Depending on the `binder` used, the `bindee` function is usually near by.
53 |
54 | ##### `_.bind` from [Lo-Dash](http://lodash.com/)
55 | * Expand the `handler` function followed by the `__bindData__` property. In this array, the first element is the `bindee` function, the other elements contain the `this` context and any parameters to be partially applied. Older versions of Lo-Dash might not have this structure.
56 |
57 | 
58 |
59 | ##### `_.bind` from [Underscore](http://underscorejs.org/) and native `Function.prototype.bind`
60 | * Underscore uses to the native `bind` function. A clear sign that the `binder` is the native `bind` function is `function () { [native code] }` for a `handler`. Expand the `handler` to locate the `bindee` function is under `[[TargetFunction]]`. The `this` context is found in `[[BoundThis]]` and any parameters to be partially applied are in `[[BoundArgs]]`.
61 |
62 | 
63 |
64 | ##### `$.proxy` from [jQuery](http://jquery.com/)
65 | * With `$.proxy` the `bindee` can't be found as a property on the `binder` but rather in a `Closure`. Expand the `handler`, followed by `` and then the inner-most `Closure`. One of the variables in this scope contains the `bindee` - the name of the variable that contains the `bindee` will likely vary because of minification.
66 |
67 | 
68 |
69 | ***
70 |
71 | ### FAQ
72 | * Does `jQuery Audit` work with `