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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MGRmOTVlYTY1Mjk4MjU1MmZkYmQwNDU0NWQ0NTM4ZmRmZGI3NzdhZA==
4
+ MzRkNWEzMjNkY2JjOGVmZTZjNmY5MzhhN2VlNjZiYWYwMzhlOGYxMg==
5
5
  data.tar.gz: !binary |-
6
- OTFhNWVkNTBkOWY1OTlmODQ5ZGExZjk0MmZjYmMzZDkyNDI1NjRjOA==
6
+ MzE0M2E2NzRmN2M4MzMwN2RmN2FhNTU4NTI0OTc4NTUxYmUzYTljZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MDY2ZjY5NzA2MThhZGNmMDcwZTBmNDcyYmUwNmMzMjAwODFiYWUzMTAyNTg1
10
- NWIwZjQyYmNlNzljNGZlMTVmMTY4YjIwZmFlZTcwZGEwMDliN2ZkYjc1YjI5
11
- Y2JkNDhjOTk0MWE2NzMyOTFlN2I0MDY5YzNhZDIyODc2ZTQwNzc=
9
+ OGNlMGU4MTE0ZDViMmU4NDYxM2RlZDUxZTJhN2M4OTM2ZjdlMjFmYjY2NzMy
10
+ YmY0NjI1NGRkNjhiNDgzMGFlMTdlMjNkNGU5MjNhYWI5NTdmMTBhNGIwZGY0
11
+ Y2Q3MmE1ZWE0ZTZkNTA5NTg0MDU3ZWZhY2IxZDZiNzU3ODljNDU=
12
12
  data.tar.gz: !binary |-
13
- NGQ1ZDZhODc5NjBkY2RlNTcwOGMzNDAzMGIyNTA4ZTFjYzYzYzllOGE3MGI5
14
- MDMzNDcwYTkwMmRkYTI4MmMzZTQ4OTY3NzI3Y2E2NGNiMGU1Mzg4Njk4YzQ1
15
- N2Y0YmM0OGNmNmI4ZDc0YTJlYmNjZjczZWZlZjVlM2U0NTVkNTI=
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
- Javascript DOM insertion
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
- If you use a lot of javascript/jquery to manually insert DOM elements, you can also enable javascript DOM insertion tracking by adding this line to `config/environments/development.rb`.
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)
@@ -2,7 +2,7 @@ module ViewInspect
2
2
  module Rails
3
3
  class Railtie < ::Rails::Railtie
4
4
  initializer "view_inspect_railtie.configure_rails_initialization" do |app|
5
- ViewInspect.init(app)
5
+ ViewInspect.init
6
6
  end
7
7
  end
8
8
  end
@@ -1,3 +1,3 @@
1
1
  module ViewInspect
2
- VERSION = "0.3.5"
2
+ VERSION = "0.3.6"
3
3
  end
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(app)
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
- if track_javascript?
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.enable_javascript_tracking!(*library_exclude_list)
27
- @track_javascript = true
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.track_javascript?
32
- @track_javascript
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.5
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-12 00:00:00.000000000 Z
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