view_inspect 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.markdown +34 -0
- data/example/sample.html +118 -0
- data/lib/view_inspect/erb.rb +4 -2
- data/lib/view_inspect/middleware.rb +49 -0
- data/lib/view_inspect/railtie.rb +8 -3
- data/lib/view_inspect/version.rb +3 -0
- data/lib/view_inspect/view_inspect.js +109 -0
- data/lib/view_inspect.rb +0 -2
- data/view_inspect.gemspec +3 -1
- metadata +7 -4
- data/README.rdoc +0 -31
- data/VERSION +0 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODE1N2FkNDI2ZjU5NjYxMWIzNzc5NjJhYzYyYjRjNTdjOGJlMDk4ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjE1NjI1MjczOGRiNmM4ZGE3Zjk5YTZjMmE1MmJmZTRiZDVhMDVkZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZWIzNDFiYTgyODE0NDhmMTA5ZjQ3MTk5MDE2ODE0MjM3YzhiYTI3NTg5NjBh
|
10
|
+
ZjNlMjM3NWQyNWZkNWE5NmNmODJjODQ3NzdkODc2MzY1MDM4NzFiNThjMzc5
|
11
|
+
Mzc3Zjc0N2Q0MzE5MzNiMTNkNWE2M2I3NGJjZTI3MTdhYjVhMjY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmJlOTI0YWZhNGFlOWU4YTgxNjZiZDZlYjk5NjI2ODlkMDUyY2NjMWZhNDMw
|
14
|
+
NTkzYTY5N2QyZWM0YzJiZGI1MWNmYmJjZjQ2YmVhZDFiOWQzNjE1NjI1Nzkz
|
15
|
+
M2E3ZDljZmQ5YzQ4NjlmZTA5ZjkwNzUwYTExMmI5Y2FjZTA2MjI=
|
data/README.markdown
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= View Inspect
|
2
|
+
|
3
|
+
View Inspect shows you the source location of a client or server rendered DOM element. It currently only works for Rails where erb and haml templates are supported. For client rendered DOM, only basic javascript, jQuery, and Backbone.js is supported.
|
4
|
+
|
5
|
+
== Demo
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem "view_inspect"
|
11
|
+
end
|
12
|
+
|
13
|
+
To enable javascript DOM source location tracking, you 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 client-side DOM insertion. See How it Works to understand why.
|
14
|
+
|
15
|
+
<head data-orig-exclude-list="jquery,backbone">
|
16
|
+
|
17
|
+
== How it Works
|
18
|
+
|
19
|
+
For server-rendered DOM elements, we monkey patch view template generation to include the file and line information in the html nodes.
|
20
|
+
|
21
|
+
For client-rendered DOM elements, we intercept the native DOM insertion methods such as `appendChild`, `insertBefore`, or `replaceChild`, look at the stacktrace, and go through it to find the most recent caller that includes our javascript code.
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
== Warning
|
26
|
+
|
27
|
+
Don't run this on production. Preferably, you should only run this locally, not even on staging environments. View Inspect shows you the fullpath of your and back-end and front-end code. That is unless you dont mind people seeing things like /home/nandato/rails/app/releases/20131012158211/app/views/ganbatte/show.html.erb:2 in the HTML source
|
28
|
+
|
29
|
+
|
30
|
+
== Copyright
|
31
|
+
|
32
|
+
Copyright (c) 2014 Reginald Tan. See LICENSE.txt for
|
33
|
+
further details.
|
34
|
+
|
data/example/sample.html
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="pt-BR">
|
3
|
+
<head data-orig-exclude-list='jquery'>
|
4
|
+
<title>Yes</title>
|
5
|
+
|
6
|
+
<meta charset="utf-8">
|
7
|
+
<meta name="keywords" content=""/>
|
8
|
+
<meta name="description" content=""/>
|
9
|
+
|
10
|
+
<link rel="shortcut icon" href="favicon.ico">
|
11
|
+
|
12
|
+
<style type="text/css" media="screen">
|
13
|
+
.white {
|
14
|
+
width: 50px;
|
15
|
+
height: 50px;
|
16
|
+
background-color: white;
|
17
|
+
border: solid 1px black;
|
18
|
+
}
|
19
|
+
|
20
|
+
.black {
|
21
|
+
width: 50px;
|
22
|
+
height: 50px;
|
23
|
+
background-color: black;
|
24
|
+
border: solid 1px black;
|
25
|
+
margin-top: 20px;
|
26
|
+
}
|
27
|
+
|
28
|
+
.green {
|
29
|
+
width: 30px;
|
30
|
+
height: 10px;
|
31
|
+
background-color: green;
|
32
|
+
}
|
33
|
+
|
34
|
+
.blue {
|
35
|
+
width: 20px;
|
36
|
+
height: 30px;
|
37
|
+
background-color: blue;
|
38
|
+
}
|
39
|
+
|
40
|
+
.red {
|
41
|
+
width: 40px;
|
42
|
+
height: 20px;
|
43
|
+
background-color: red;
|
44
|
+
}
|
45
|
+
|
46
|
+
.yellow {
|
47
|
+
width: 10px;
|
48
|
+
height: 10px;
|
49
|
+
background-color: yellow;
|
50
|
+
}
|
51
|
+
</style>
|
52
|
+
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
|
53
|
+
<script src="./../lib/view_inspect/view_inspect.js" type="text/javascript" charset="utf-8"></script>
|
54
|
+
|
55
|
+
<!--[if IE]>
|
56
|
+
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
57
|
+
<![endif]-->
|
58
|
+
</head>
|
59
|
+
|
60
|
+
<body>
|
61
|
+
<header>
|
62
|
+
</header>
|
63
|
+
|
64
|
+
<section id="main">
|
65
|
+
</section>
|
66
|
+
|
67
|
+
<footer>
|
68
|
+
</footer>
|
69
|
+
</body>
|
70
|
+
|
71
|
+
<script type="text/javascript" language="javascript" charset="utf-8">
|
72
|
+
//<![CDATA[
|
73
|
+
|
74
|
+
jQuery(document).ready(function(){
|
75
|
+
var node;
|
76
|
+
var child;
|
77
|
+
|
78
|
+
node = document.createElement("div");
|
79
|
+
node.className = "white";
|
80
|
+
|
81
|
+
document.getElementById("main").appendChild(node);
|
82
|
+
|
83
|
+
child = document.createElement("div");
|
84
|
+
child.className = "green";
|
85
|
+
|
86
|
+
node.appendChild(child);
|
87
|
+
|
88
|
+
child_2 = document.createElement("div");
|
89
|
+
child_2.className = "green";
|
90
|
+
|
91
|
+
node.replaceChild(child_2,child);
|
92
|
+
|
93
|
+
child_3 = document.createElement("div");
|
94
|
+
child_3.className = "blue";
|
95
|
+
|
96
|
+
node.insertBefore(child_3,child_2);
|
97
|
+
|
98
|
+
$node = $("<div class='black'>");
|
99
|
+
|
100
|
+
$("#main").append($node);
|
101
|
+
|
102
|
+
$child = $("<div class='green'>");
|
103
|
+
|
104
|
+
$node.append($child);
|
105
|
+
|
106
|
+
|
107
|
+
$child_2 = $("<div class='yellow'>");
|
108
|
+
|
109
|
+
$child.replaceWith($child_2);
|
110
|
+
|
111
|
+
$child_3 = $("<div class='red'>");
|
112
|
+
|
113
|
+
$child_3.insertBefore($child_2);
|
114
|
+
|
115
|
+
});
|
116
|
+
//]]>
|
117
|
+
</script>
|
118
|
+
</html>
|
data/lib/view_inspect/erb.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
1
3
|
module ViewInspect
|
2
4
|
module ERB
|
3
5
|
# from erubis 2.7.0
|
@@ -29,10 +31,10 @@ module ViewInspect
|
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.add_file_line(source, filepath)
|
32
|
-
doc = Nokogiri::HTML(source)
|
34
|
+
doc = ::Nokogiri::HTML(source)
|
33
35
|
|
34
36
|
doc.traverse do |node|
|
35
|
-
if node.is_a?(Nokogiri::XML::Element)
|
37
|
+
if node.is_a?(::Nokogiri::XML::Element)
|
36
38
|
file_line = [filepath, node.line].join(":")
|
37
39
|
node.set_attribute "data-orig-file-line", file_line
|
38
40
|
end
|
@@ -0,0 +1,49 @@
|
|
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.body.to_s =~ 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
|
+
index = get_insert_position(body)
|
24
|
+
body.insert(index, get_inline_script)
|
25
|
+
body
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_insert_position(body)
|
29
|
+
index = body.index(HEAD_REGEXP)
|
30
|
+
match = $1
|
31
|
+
return index + match.length
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_script
|
35
|
+
filepath = File.expand_path("view_inspect.js",File.dirname(__FILE__))
|
36
|
+
File.read(filepath)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_inline_script
|
40
|
+
<<-CODE
|
41
|
+
<script type="text/javascript" language="javascript" charset="utf-8">
|
42
|
+
//<![CDATA[
|
43
|
+
#{get_script}
|
44
|
+
//]]>
|
45
|
+
</script>
|
46
|
+
CODE
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/view_inspect/railtie.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
+
require 'view_inspect/middleware'
|
2
|
+
|
1
3
|
module ViewInspect
|
2
4
|
class Railtie < Rails::Railtie
|
3
|
-
initializer "view_inspect_railtie.configure_rails_initialization" do
|
4
|
-
ViewInspect.
|
5
|
+
initializer "view_inspect_railtie.configure_rails_initialization" do |app|
|
6
|
+
if ViewInspect.allow_view_source_location?
|
7
|
+
ViewInspect.enable
|
8
|
+
app.middleware.use ViewInspect::Middleware
|
9
|
+
end
|
5
10
|
end
|
6
11
|
end
|
7
|
-
end
|
12
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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
|
+
})();
|
data/lib/view_inspect.rb
CHANGED
data/view_inspect.gemspec
CHANGED
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.
|
4
|
+
version: 0.2.0
|
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-10-
|
11
|
+
date: 2014-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -35,13 +35,16 @@ files:
|
|
35
35
|
- .gitignore
|
36
36
|
- Gemfile
|
37
37
|
- LICENSE.txt
|
38
|
-
- README.
|
38
|
+
- README.markdown
|
39
39
|
- Rakefile
|
40
|
-
-
|
40
|
+
- example/sample.html
|
41
41
|
- lib/view_inspect.rb
|
42
42
|
- lib/view_inspect/erb.rb
|
43
43
|
- lib/view_inspect/haml.rb
|
44
|
+
- lib/view_inspect/middleware.rb
|
44
45
|
- lib/view_inspect/railtie.rb
|
46
|
+
- lib/view_inspect/version.rb
|
47
|
+
- lib/view_inspect/view_inspect.js
|
45
48
|
- test/helper.rb
|
46
49
|
- test/test_view_inspect.rb
|
47
50
|
- view_inspect.gemspec
|
data/README.rdoc
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
= View Inspect
|
2
|
-
|
3
|
-
View Inspect shows you the source location of a client or server rendered DOM element.
|
4
|
-
|
5
|
-
== Demo
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
== Installation
|
10
|
-
|
11
|
-
group :development do
|
12
|
-
gem "view_inspect"
|
13
|
-
end
|
14
|
-
|
15
|
-
== Warning
|
16
|
-
|
17
|
-
Don't run this on production. Preferably, you should only run this locally, not even on staging environments. View Inspect shows you the fullpath of your and back-end and front-end code. That is unless you dont mind people seeing things like /home/nandato/rails/app/releases/20131012158211/app/views/ganbatte/show.html.erb:2 in the HTML source
|
18
|
-
|
19
|
-
== Support
|
20
|
-
|
21
|
-
Server Side:
|
22
|
-
works with plain html, erb, haml
|
23
|
-
|
24
|
-
Client Side:
|
25
|
-
works with plain Javascript, and tested with Backbone, Ember
|
26
|
-
|
27
|
-
== Copyright
|
28
|
-
|
29
|
-
Copyright (c) 2014 Reginald Tan. See LICENSE.txt for
|
30
|
-
further details.
|
31
|
-
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.1.0
|