view_inspect 0.3.5 → 0.3.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.markdown +10 -18
- data/lib/view_inspect/handlers/html_template.rb +23 -1
- data/lib/view_inspect/rails/railtie.rb +1 -1
- data/lib/view_inspect/version.rb +1 -1
- data/lib/view_inspect.rb +6 -14
- metadata +2 -4
- data/lib/view_inspect/handlers/javascript_handler.js +0 -109
- data/lib/view_inspect/rails/middleware.rb +0 -58
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzRkNWEzMjNkY2JjOGVmZTZjNmY5MzhhN2VlNjZiYWYwMzhlOGYxMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MzE0M2E2NzRmN2M4MzMwN2RmN2FhNTU4NTI0OTc4NTUxYmUzYTljZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OGNlMGU4MTE0ZDViMmU4NDYxM2RlZDUxZTJhN2M4OTM2ZjdlMjFmYjY2NzMy
|
10
|
+
YmY0NjI1NGRkNjhiNDgzMGFlMTdlMjNkNGU5MjNhYWI5NTdmMTBhNGIwZGY0
|
11
|
+
Y2Q3MmE1ZWE0ZTZkNTA5NTg0MDU3ZWZhY2IxZDZiNzU3ODljNDU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
M2I1MzgxZGU5OTllM2UwMGYyNWVkZDQyZmUxZmM5NDA0OWI1NGU4ODQ5Njg3
|
14
|
+
ZGJiNmU5NDkyZjViODc1ZmE4OTcyYjRjMmY0Y2FiODMwNmE3NzY2ODk5N2Vk
|
15
|
+
Y2E1YTRhMWU2OWQ5MmVlYWFmYTE1YTkzNWI3YWJiZTdiN2NlZjQ=
|
data/README.markdown
CHANGED
@@ -3,8 +3,6 @@ View Inspect
|
|
3
3
|
|
4
4
|
View Inspect tells you which server-side or client-side template is responsible for rendering a DOM element. Instead of using grep to filter through a large codebase, the source location can be found right away in its data-attribute when you open up web inspector. Works with Rails 3 and 4. See below for templates supported and their required libraries.
|
5
5
|
|
6
|
-
Source location is added by first stubbing out all template specific expressions (i.e. `<% %>` for erb). Nokogiri parses the resulting valid HTML fragment and adds file:line information to each DOM node. After which stubs are replaced back with original template expressions.
|
7
|
-
|
8
6
|
Demo
|
9
7
|
----
|
10
8
|
- [Diaspora: Haml + Backbone.js](https://i.imgur.com/bhK6lap.png)
|
@@ -37,6 +35,12 @@ By default, this is only enabled for development to avoid exposing source code f
|
|
37
35
|
|
38
36
|
ViewInspect.disable = true
|
39
37
|
|
38
|
+
How it Works
|
39
|
+
----
|
40
|
+
|
41
|
+
Except for Haml and Slim where the compiler/parser is monkeypatched to include file:line information to each node, the rest of the templates are augment by preprocessing them with an HTML parser. Basically, we first stub out all template specific expressions (i.e. `<% %>` for erb) from a template file. Then, we use the Nokogiri HTML Parser to parse the resulting valid HTML fragment, and add file:line information to its child nodes. Once this is done, we bring back our original template expressions and remove the stubs. A little bit hacky but it works.
|
42
|
+
|
43
|
+
|
40
44
|
Server-Side Templates
|
41
45
|
----
|
42
46
|
|
@@ -49,25 +53,13 @@ For client-side templates to work, they have to live in separate files as oppose
|
|
49
53
|
|
50
54
|
rake tmp:clear
|
51
55
|
|
52
|
-
|
56
|
+
HTML Syntax Errors
|
53
57
|
----
|
58
|
+
ViewInspect depends on Nokogiri to preprocess a template and add file:line information to each node. If there's any invalid HTML in your file, Nokogiri would delete it, and sometimes your HTML would look different in the browser because of this. To prevent that from happening, a Warning message would be shown to the user detailing where the HTML syntax errors are located so that the user can remove it. This is the default behavior.
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
ViewInspect.enable_javascript_tracking!
|
58
|
-
|
59
|
-
Then, you need to make sure that in your `config/environments/development.rb`, asset compression is turned off
|
60
|
-
|
61
|
-
config.assets.compress = false
|
62
|
-
|
63
|
-
Also, depending which library you're using, you may need to specify external libraries you wish to prevent from showing up as a potential source location. This is because of the way we track the origin of javascript DOM insertion. In order to do that, pass in an array of library names you want to exclude to `enable_javascript_tracking!` . For example:
|
64
|
-
|
65
|
-
ViewInspect.enable_javascript_tracking!([:jquery, :backbone])
|
66
|
-
|
67
|
-
|
68
|
-
The reason why you may need to do this is because of the way we track the javascript file:line. We intercept the native DOM insertion methods such as appendChild, insertBefore, or replaceChild, look at the stacktrace, and then go through it to find the most recent caller which corresponds to our javascript code.
|
69
|
-
|
60
|
+
An alternative solution is to avoid adding file:line information to DOM elements whenever Nokogiri encounters HTML syntax errors. Instead, it'll just show the original HTML template. If you prefer this behavior, you can set it by adding this line to config/environments/development.rb
|
70
61
|
|
62
|
+
ViewInspect.show_html_syntax_error = false
|
71
63
|
|
72
64
|
Copyright
|
73
65
|
----
|
@@ -27,6 +27,8 @@ module ViewInspect
|
|
27
27
|
def add_file_line(source, filepath)
|
28
28
|
doc = ::Nokogiri::HTML.fragment(source)
|
29
29
|
|
30
|
+
return source if doc.errors.count > 0 && !ViewInspect.show_html_syntax_error?
|
31
|
+
|
30
32
|
doc.traverse do |node|
|
31
33
|
if node.is_a?(::Nokogiri::XML::Element)
|
32
34
|
file_line = [filepath, node.line].join(":")
|
@@ -34,7 +36,27 @@ module ViewInspect
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
CGI.unescapeHTML(doc.inner_html)
|
39
|
+
source = CGI.unescapeHTML(doc.inner_html)
|
40
|
+
|
41
|
+
if doc.errors.length > 0
|
42
|
+
error_msg = build_html_syntax_error_msg(doc.errors, filepath)
|
43
|
+
"#{error_msg}#{source}"
|
44
|
+
else
|
45
|
+
source
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_html_syntax_error_msg(errors, filepath)
|
50
|
+
errors_list = errors.inject("") do |result, error|
|
51
|
+
result << "<li>line #{error.line} - #{error.to_s}</li>"
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
"<div id='view_inspect_error_message' style='border: solid 1px black; z-index: 9999; position: absolute; margin-left: 200px; width: 800px; padding: 20px; background-color: rgb(255, 229, 229); color: black;'>
|
56
|
+
<h3 style='font-size: 20px; line-height: 20px; font-weight: bold; background-color: lightgray; padding: 5px; display: inline-block; border: solid 1px black;'>Please correct HTML syntax errors</h3>
|
57
|
+
<h3 style='font-size: 16px; line-height: 16px; margin-bottom: 20px;'>#{filepath}</h3>
|
58
|
+
<ul style='list-style: none;'>#{errors_list}</ul>
|
59
|
+
</div>"
|
38
60
|
end
|
39
61
|
|
40
62
|
def replace_expression_with_stub(source)
|
data/lib/view_inspect/version.rb
CHANGED
data/lib/view_inspect.rb
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
require 'view_inspect/server_side_template'
|
2
2
|
require 'view_inspect/client_side_template'
|
3
|
-
require 'view_inspect/rails/middleware'
|
4
3
|
|
5
4
|
module ViewInspect
|
6
5
|
|
7
|
-
def self.init
|
6
|
+
def self.init
|
8
7
|
return unless allow_view_source_location?
|
9
8
|
|
10
9
|
ServerSideTemplate.handle
|
11
10
|
ClientSideTemplate.handle
|
12
11
|
|
13
|
-
|
14
|
-
app.middleware.use ViewInspect::Middleware
|
15
|
-
end
|
12
|
+
@show_html_syntax_error = true
|
16
13
|
end
|
17
14
|
|
18
15
|
def self.allow_view_source_location?
|
@@ -23,17 +20,12 @@ module ViewInspect
|
|
23
20
|
@disable = bool
|
24
21
|
end
|
25
22
|
|
26
|
-
def self.
|
27
|
-
@
|
28
|
-
@library_exclude_list = library_exclude_list.flatten
|
23
|
+
def self.show_html_syntax_error?
|
24
|
+
@show_html_syntax_error
|
29
25
|
end
|
30
26
|
|
31
|
-
def self.
|
32
|
-
@
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.library_exclude_list
|
36
|
-
Array(@library_exclude_list)
|
27
|
+
def self.show_html_syntax_error=(bool)
|
28
|
+
@show_html_syntax_error = bool
|
37
29
|
end
|
38
30
|
|
39
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: view_inspect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reginald Tan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -45,10 +45,8 @@ files:
|
|
45
45
|
- lib/view_inspect/handlers/haml.rb
|
46
46
|
- lib/view_inspect/handlers/handlebars.rb
|
47
47
|
- lib/view_inspect/handlers/html_template.rb
|
48
|
-
- lib/view_inspect/handlers/javascript_handler.js
|
49
48
|
- lib/view_inspect/handlers/jst.rb
|
50
49
|
- lib/view_inspect/handlers/slim.rb
|
51
|
-
- lib/view_inspect/rails/middleware.rb
|
52
50
|
- lib/view_inspect/rails/railtie.rb
|
53
51
|
- lib/view_inspect/server_side_template.rb
|
54
52
|
- lib/view_inspect/version.rb
|
@@ -1,109 +0,0 @@
|
|
1
|
-
(function(){
|
2
|
-
var DOM_INSERT_METHOD_NAMES = [
|
3
|
-
"appendChild",
|
4
|
-
"insertBefore",
|
5
|
-
"replaceChild",
|
6
|
-
];
|
7
|
-
|
8
|
-
var fileExcludeList;
|
9
|
-
|
10
|
-
var getStacktrace = function() {
|
11
|
-
var e = new Error('dummy');
|
12
|
-
var stack = e.stack.replace(/^[^\(]+?[\n$]/gm, '')
|
13
|
-
.replace(/^\s+at\s+/gm, '')
|
14
|
-
.replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@')
|
15
|
-
.split('\n');
|
16
|
-
|
17
|
-
stack.splice(0,3); // HACK: we dont want 3 top most callers since they belong to our code
|
18
|
-
return stack;
|
19
|
-
};
|
20
|
-
|
21
|
-
var isInFileExcludeList = function(caller) {
|
22
|
-
var exclude;
|
23
|
-
|
24
|
-
for (var i = 0; i < fileExcludeList.length; i++) {
|
25
|
-
exclude = fileExcludeList[i];
|
26
|
-
if (caller.indexOf(exclude) !== -1) {
|
27
|
-
return true;
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
return false;
|
32
|
-
};
|
33
|
-
|
34
|
-
var removeUrlParams = function(fileline) {
|
35
|
-
var match = fileline.match(/(\?.*):/);
|
36
|
-
|
37
|
-
if (match) {
|
38
|
-
match = match.pop();
|
39
|
-
fileline = fileline.replace(match, "");
|
40
|
-
}
|
41
|
-
|
42
|
-
return fileline;
|
43
|
-
};
|
44
|
-
|
45
|
-
var getOrigFileLine = function() {
|
46
|
-
var stacktrace = getStacktrace();
|
47
|
-
var regex = /(file|http|https)\:\/\/.+?(\/.*:\d+):\d+/;
|
48
|
-
var match;
|
49
|
-
var fileline = "";
|
50
|
-
|
51
|
-
for (var i = 0; i < stacktrace.length; i++) {
|
52
|
-
caller = stacktrace[i];
|
53
|
-
if ((match = caller.match(regex)) && !isInFileExcludeList(caller)) {
|
54
|
-
fileline = match.pop();
|
55
|
-
fileline = removeUrlParams(fileline);
|
56
|
-
break;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
return fileline;
|
61
|
-
};
|
62
|
-
|
63
|
-
var canSetFileLine = function(node,fileline) {
|
64
|
-
return typeof node.setAttribute !== "undefined" &&
|
65
|
-
!node.getAttribute("data-orig-file-line") &&
|
66
|
-
fileline.length > 0;
|
67
|
-
};
|
68
|
-
|
69
|
-
var setFileLineToElement = function(node,fileline) {
|
70
|
-
var child;
|
71
|
-
|
72
|
-
if (canSetFileLine(node, fileline)) {
|
73
|
-
node.setAttribute("data-orig-file-line", fileline);
|
74
|
-
|
75
|
-
for (var i = 0; i < node.children.length; i++) {
|
76
|
-
child = node.children[i];
|
77
|
-
setFileLineToElement(child, fileline);
|
78
|
-
}
|
79
|
-
}
|
80
|
-
};
|
81
|
-
|
82
|
-
var setFileLineOnCall = function(methodName) {
|
83
|
-
var method = Element.prototype[methodName];
|
84
|
-
|
85
|
-
Element.prototype[methodName] = function(){
|
86
|
-
method.apply(this, arguments);
|
87
|
-
var node = arguments[0];
|
88
|
-
var fileline = getOrigFileLine();
|
89
|
-
setFileLineToElement(node, fileline);
|
90
|
-
return node;
|
91
|
-
};
|
92
|
-
};
|
93
|
-
|
94
|
-
var getFileExcluseList = function() {
|
95
|
-
var list = document.getElementsByTagName("head")[0].getAttribute("data-orig-exclude-list");
|
96
|
-
list = list ? list.split(",") : [];
|
97
|
-
return list;
|
98
|
-
};
|
99
|
-
|
100
|
-
var enableViewInspect = function() {
|
101
|
-
fileExcludeList = getFileExcluseList();
|
102
|
-
for (var i = 0; i < DOM_INSERT_METHOD_NAMES.length; i++) {
|
103
|
-
var methodName = DOM_INSERT_METHOD_NAMES[i];
|
104
|
-
setFileLineOnCall(methodName);
|
105
|
-
}
|
106
|
-
};
|
107
|
-
|
108
|
-
enableViewInspect();
|
109
|
-
})();
|
@@ -1,58 +0,0 @@
|
|
1
|
-
module ViewInspect
|
2
|
-
class Middleware
|
3
|
-
HEAD_REGEXP = /(<head.*?>)/
|
4
|
-
HTML_CONTENT_TYPE_REGEXP = /text\/html|application\/xhtml\+xml/
|
5
|
-
|
6
|
-
def initialize(app)
|
7
|
-
@app = app
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(env)
|
11
|
-
status, headers, response = @app.call(env)
|
12
|
-
|
13
|
-
if headers["Content-Type"] =~ HTML_CONTENT_TYPE_REGEXP && response.each.to_a.join("") =~ HEAD_REGEXP
|
14
|
-
body = insert_view_inspect_script(response.body)
|
15
|
-
headers["Content-Length"] = body.length.to_s
|
16
|
-
response = [body]
|
17
|
-
end
|
18
|
-
|
19
|
-
[status, headers, response]
|
20
|
-
end
|
21
|
-
|
22
|
-
def insert_view_inspect_script(body)
|
23
|
-
body = add_library_exclude_list(body)
|
24
|
-
index = get_insert_position(body)
|
25
|
-
body.insert(index, get_inline_script)
|
26
|
-
body
|
27
|
-
end
|
28
|
-
|
29
|
-
def add_library_exclude_list(body)
|
30
|
-
index = body.index(HEAD_REGEXP)
|
31
|
-
old_head = $1
|
32
|
-
new_head = old_head.dup
|
33
|
-
new_head.insert("<head".length, " data-orig-exclude-list='#{ViewInspect.library_exclude_list.join(",")}' ")
|
34
|
-
body.sub(old_head,new_head)
|
35
|
-
end
|
36
|
-
|
37
|
-
def get_insert_position(body)
|
38
|
-
index = body.index(HEAD_REGEXP)
|
39
|
-
match = $1
|
40
|
-
return index + match.length
|
41
|
-
end
|
42
|
-
|
43
|
-
def get_script
|
44
|
-
filepath = File.expand_path("javascript_handler.js","#{File.dirname(__FILE__)}/../handlers")
|
45
|
-
File.read(filepath)
|
46
|
-
end
|
47
|
-
|
48
|
-
def get_inline_script
|
49
|
-
<<-CODE
|
50
|
-
<script type="text/javascript" language="javascript" charset="utf-8">
|
51
|
-
//<![CDATA[
|
52
|
-
#{get_script}
|
53
|
-
//]]>
|
54
|
-
</script>
|
55
|
-
CODE
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|