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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YmU4ZjA5Yjg2OTdkZTg0NjhjOTlhYzllZDIyZDMyZDM1NjYwZTZiZg==
4
+ ODE1N2FkNDI2ZjU5NjYxMWIzNzc5NjJhYzYyYjRjNTdjOGJlMDk4ZQ==
5
5
  data.tar.gz: !binary |-
6
- NjdiM2UwMzZiMjlmYjM4YmVmYzRjNjQ4MDI4MTMzYzk2MWUyNWYxNA==
6
+ YjE1NjI1MjczOGRiNmM4ZGE3Zjk5YTZjMmE1MmJmZTRiZDVhMDVkZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YmZlNTIyNjllZWM2YjQ2NjY2YzQ5ZjEwYTAyZTJlZDAyNjY0YjU0Nzk3NmI5
10
- NWViOGQ2MzdlYTJkZjUxYTE1MzA4OGQzMmU5MDMwOGU4NDY0NTU4NWRiNWQ0
11
- MWRjNDA5ZTNkMDJkMzYwNDNkOTJlYWU1ZjA5N2E5ZjMzOWRmZDc=
9
+ ZWIzNDFiYTgyODE0NDhmMTA5ZjQ3MTk5MDE2ODE0MjM3YzhiYTI3NTg5NjBh
10
+ ZjNlMjM3NWQyNWZkNWE5NmNmODJjODQ3NzdkODc2MzY1MDM4NzFiNThjMzc5
11
+ Mzc3Zjc0N2Q0MzE5MzNiMTNkNWE2M2I3NGJjZTI3MTdhYjVhMjY=
12
12
  data.tar.gz: !binary |-
13
- NTBmMjVkNTYyMmE3OGFkZTc5N2JlNGQwODYwNGUzNWY0MTU4MGE1YTlmNjBm
14
- MWNiOTVlNDY2MjZmNDQ4MjFiNzM0MDUyY2E5YjQyMzg0NjVhYWNlY2M2MDg1
15
- YjliMmZkZDkzZTM4NzI2MmEzYmNjZWJjZWU1ODE5MTY4YjA0NjQ=
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
+
@@ -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>
@@ -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
@@ -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.enable
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,3 @@
1
+ module ViewInspect
2
+ VERSION = "0.2.0"
3
+ 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
@@ -3,8 +3,6 @@ require 'view_inspect/haml'
3
3
 
4
4
  module ViewInspect
5
5
  def self.enable
6
- return unless allow_view_source_location?
7
-
8
6
  ERB.enable
9
7
  Haml.enable
10
8
  end
data/view_inspect.gemspec CHANGED
@@ -1,6 +1,8 @@
1
+ require File.expand_path('../lib/view_inspect/version', __FILE__)
2
+
1
3
  Gem::Specification.new do |s|
2
4
  s.name = "view_inspect"
3
- s.version = "0.1.0"
5
+ s.version = ViewInspect::VERSION
4
6
 
5
7
  s.required_rubygems_version = ">= 1.9.3"
6
8
 
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.1.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-17 00:00:00.000000000 Z
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.rdoc
38
+ - README.markdown
39
39
  - Rakefile
40
- - VERSION
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