xray-rails 0.1.23 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -10
- data/app/assets/javascripts/xray.js +471 -0
- data/lib/xray-rails.rb +0 -46
- data/lib/xray/engine.rb +32 -20
- data/lib/xray/middleware.rb +3 -4
- data/lib/xray/version.rb +1 -1
- metadata +4 -62
- data/app/assets/javascripts/xray-backbone.js.coffee +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af26d9471fb39cf9697c4142f11d1218b282949f
|
4
|
+
data.tar.gz: 2dec43a0a579d6cce8a8159c3b97cb5a42d6168d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36432e25ecbaa3cebacb6d6942de25567e7af1a082baea0f3946c821a2260aea6f53d436c4109f7428051db2c080daacf68a9f1821895dd37d757bc0f74725aa
|
7
|
+
data.tar.gz: ac7a9ef35f340e7e039d3f0a438c69e7b17e0de362f07a52af7c15e9326fa431cfd0bcc04987aeaab92dda88b5d51cf3da12992e7e99c54dac8b2276378921c6
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Xray-rails
|
|
6
6
|
|
7
7
|
### Reveal your UI's bones
|
8
8
|
|
9
|
-
The dev tools available to web developers in modern browsers are great. Many of us can't remember what life was like before "Inspect Element". But what we see in the compiled output sent to our browser is often the wrong level of detail - what about visualizing the higher level components of your UI? Controllers, templates, partials,
|
9
|
+
The dev tools available to web developers in modern browsers are great. Many of us can't remember what life was like before "Inspect Element". But what we see in the compiled output sent to our browser is often the wrong level of detail - what about visualizing the higher level components of your UI? Controllers, view templates, partials, JS templates, etc.
|
10
10
|
|
11
11
|
Xray is the missing link between the browser and your app code. Press **cmd+shift+x** (Mac) or **ctrl+shift+x** to reveal an overlay of the files that rendered your UI, and click anything to open the file in your editor. [See Xray in action](http://f.cl.ly/items/1A0o3y1y3Q13103V3F1l/xray-rails-large.gif).
|
12
12
|
|
@@ -19,12 +19,11 @@ Xray is intended for Rails 3.1+ and Ruby 1.9+.
|
|
19
19
|
So far, Xray can reveal:
|
20
20
|
|
21
21
|
* Rails views and partials
|
22
|
-
* Backbone View instances if using the asset pipeline
|
23
22
|
* Javascript templates if using the asset pipeline with the .jst extension
|
24
23
|
|
25
24
|
## Installation
|
26
25
|
|
27
|
-
Xray depends on **jQuery**.
|
26
|
+
Xray depends on **jQuery**.
|
28
27
|
|
29
28
|
This gem should only be present during development. Add it to your Gemfile:
|
30
29
|
|
@@ -44,20 +43,15 @@ Restart your app, visit it in your browser, and press **cmd+shift+x** (Mac) or *
|
|
44
43
|
|
45
44
|
#### Note about `config.assets.debug`
|
46
45
|
|
47
|
-
|
46
|
+
By default, Xray will insert itself into your views automatically. To do this, `config.assets.debug = true` (Rails' default) must be set in development.rb.
|
48
47
|
|
49
48
|
Otherwise, you can insert Xray's scripts yourself, for example like so in application.js:
|
50
49
|
|
51
50
|
```js
|
52
51
|
//= require jquery
|
53
52
|
//= require xray
|
54
|
-
...
|
55
|
-
//= require backbone
|
56
|
-
//= require xray-backbone
|
57
53
|
```
|
58
54
|
|
59
|
-
Backbone support via `xray-backbone` is optional.
|
60
|
-
|
61
55
|
## Configuration
|
62
56
|
|
63
57
|
By default, Xray will check a few environment variables to determine
|
@@ -80,7 +74,6 @@ For something more complex, use the `$file` placeholder.
|
|
80
74
|
## How this works
|
81
75
|
|
82
76
|
* At run time, HTML responses from Rails are wrapped with HTML comments containing filepath info.
|
83
|
-
* Additionally, JS templates and Backbone view constructors are modified during asset compilation.
|
84
77
|
* A middleware inserts `xray.js`, `xray.css`, and the Xray bar into all successful HTML response bodies.
|
85
78
|
* When the overlay is shown, `xray.js` examines the inserted filepath info to build the overlay.
|
86
79
|
|
@@ -0,0 +1,471 @@
|
|
1
|
+
// Generated by CoffeeScript 1.9.2
|
2
|
+
(function() {
|
3
|
+
var $, MAX_ZINDEX, util,
|
4
|
+
hasProp = {}.hasOwnProperty,
|
5
|
+
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
|
6
|
+
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
7
|
+
|
8
|
+
window.Xray = {};
|
9
|
+
|
10
|
+
if (!($ = window.jQuery)) {
|
11
|
+
return;
|
12
|
+
}
|
13
|
+
|
14
|
+
MAX_ZINDEX = 2147483647;
|
15
|
+
|
16
|
+
Xray.init = (function() {
|
17
|
+
var is_mac;
|
18
|
+
if (Xray.initialized) {
|
19
|
+
return;
|
20
|
+
}
|
21
|
+
Xray.initialized = true;
|
22
|
+
is_mac = navigator.platform.toUpperCase().indexOf('MAC') !== -1;
|
23
|
+
$(document).keydown(function(e) {
|
24
|
+
if ((is_mac && e.metaKey || !is_mac && e.ctrlKey) && e.shiftKey && e.keyCode === 88) {
|
25
|
+
if (Xray.isShowing) {
|
26
|
+
Xray.hide();
|
27
|
+
} else {
|
28
|
+
Xray.show();
|
29
|
+
}
|
30
|
+
}
|
31
|
+
if (Xray.isShowing && e.keyCode === 27) {
|
32
|
+
return Xray.hide();
|
33
|
+
}
|
34
|
+
});
|
35
|
+
return $(function() {
|
36
|
+
new Xray.Overlay;
|
37
|
+
Xray.findTemplates();
|
38
|
+
return typeof console !== "undefined" && console !== null ? console.log("Ready to Xray. Press " + (is_mac ? 'cmd+shift+x' : 'ctrl+shift+x') + " to scan your UI.") : void 0;
|
39
|
+
});
|
40
|
+
})();
|
41
|
+
|
42
|
+
Xray.specimens = function() {
|
43
|
+
return Xray.ViewSpecimen.all.concat(Xray.TemplateSpecimen.all);
|
44
|
+
};
|
45
|
+
|
46
|
+
Xray.constructorInfo = function(constructor) {
|
47
|
+
var func, info, ref;
|
48
|
+
if (window.XrayPaths) {
|
49
|
+
ref = window.XrayPaths;
|
50
|
+
for (info in ref) {
|
51
|
+
if (!hasProp.call(ref, info)) continue;
|
52
|
+
func = ref[info];
|
53
|
+
if (func === constructor) {
|
54
|
+
return JSON.parse(info);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return null;
|
59
|
+
};
|
60
|
+
|
61
|
+
Xray.findTemplates = function() {
|
62
|
+
return util.bm('findTemplates', function() {
|
63
|
+
var $templateContents, _, comment, comments, el, i, id, len, path, ref, results;
|
64
|
+
comments = $('*:not(iframe,script)').contents().filter(function() {
|
65
|
+
return this.nodeType === 8 && this.data.slice(0, 10) === "XRAY START";
|
66
|
+
});
|
67
|
+
results = [];
|
68
|
+
for (i = 0, len = comments.length; i < len; i++) {
|
69
|
+
comment = comments[i];
|
70
|
+
ref = comment.data.match(/^XRAY START (\d+) (.*)$/), _ = ref[0], id = ref[1], path = ref[2];
|
71
|
+
$templateContents = new jQuery;
|
72
|
+
el = comment.nextSibling;
|
73
|
+
while (!(!el || (el.nodeType === 8 && el.data === ("XRAY END " + id)))) {
|
74
|
+
if (el.nodeType === 1 && el.tagName !== 'SCRIPT') {
|
75
|
+
$templateContents.push(el);
|
76
|
+
}
|
77
|
+
el = el.nextSibling;
|
78
|
+
}
|
79
|
+
if ((el != null ? el.nodeType : void 0) === 8) {
|
80
|
+
el.parentNode.removeChild(el);
|
81
|
+
}
|
82
|
+
comment.parentNode.removeChild(comment);
|
83
|
+
results.push(Xray.TemplateSpecimen.add($templateContents, {
|
84
|
+
name: path.split('/').slice(-1)[0],
|
85
|
+
path: path
|
86
|
+
}));
|
87
|
+
}
|
88
|
+
return results;
|
89
|
+
});
|
90
|
+
};
|
91
|
+
|
92
|
+
Xray.open = function(path) {
|
93
|
+
return $.ajax({
|
94
|
+
url: "/_xray/open?path=" + path
|
95
|
+
});
|
96
|
+
};
|
97
|
+
|
98
|
+
Xray.show = function(type) {
|
99
|
+
if (type == null) {
|
100
|
+
type = null;
|
101
|
+
}
|
102
|
+
return Xray.Overlay.instance().show(type);
|
103
|
+
};
|
104
|
+
|
105
|
+
Xray.hide = function() {
|
106
|
+
return Xray.Overlay.instance().hide();
|
107
|
+
};
|
108
|
+
|
109
|
+
Xray.toggleSettings = function() {
|
110
|
+
return Xray.Overlay.instance().settings.toggle();
|
111
|
+
};
|
112
|
+
|
113
|
+
Xray.Specimen = (function() {
|
114
|
+
Specimen.add = function(el, info) {
|
115
|
+
if (info == null) {
|
116
|
+
info = {};
|
117
|
+
}
|
118
|
+
return this.all.push(new this(el, info));
|
119
|
+
};
|
120
|
+
|
121
|
+
Specimen.remove = function(el) {
|
122
|
+
var ref;
|
123
|
+
return (ref = this.find(el)) != null ? ref.remove() : void 0;
|
124
|
+
};
|
125
|
+
|
126
|
+
Specimen.find = function(el) {
|
127
|
+
var i, len, ref, specimen;
|
128
|
+
if (el instanceof jQuery) {
|
129
|
+
el = el[0];
|
130
|
+
}
|
131
|
+
ref = this.all;
|
132
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
133
|
+
specimen = ref[i];
|
134
|
+
if (specimen.el === el) {
|
135
|
+
return specimen;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
return null;
|
139
|
+
};
|
140
|
+
|
141
|
+
Specimen.reset = function() {
|
142
|
+
return this.all = [];
|
143
|
+
};
|
144
|
+
|
145
|
+
function Specimen(contents, info) {
|
146
|
+
if (info == null) {
|
147
|
+
info = {};
|
148
|
+
}
|
149
|
+
this.makeLabel = bind(this.makeLabel, this);
|
150
|
+
this.el = contents instanceof jQuery ? contents[0] : contents;
|
151
|
+
this.$contents = $(contents);
|
152
|
+
this.name = info.name;
|
153
|
+
this.path = info.path;
|
154
|
+
}
|
155
|
+
|
156
|
+
Specimen.prototype.remove = function() {
|
157
|
+
var idx;
|
158
|
+
idx = this.constructor.all.indexOf(this);
|
159
|
+
if (idx !== -1) {
|
160
|
+
return this.constructor.all.splice(idx, 1);
|
161
|
+
}
|
162
|
+
};
|
163
|
+
|
164
|
+
Specimen.prototype.isVisible = function() {
|
165
|
+
return this.$contents.length && this.$contents.is(':visible');
|
166
|
+
};
|
167
|
+
|
168
|
+
Specimen.prototype.makeBox = function() {
|
169
|
+
this.bounds = util.computeBoundingBox(this.$contents);
|
170
|
+
this.$box = $("<div class='xray-specimen " + this.constructor.name + "'>").css(this.bounds).attr('title', this.path);
|
171
|
+
if (this.$contents.css('position') === 'fixed') {
|
172
|
+
this.$box.css({
|
173
|
+
position: 'fixed',
|
174
|
+
top: this.$contents.css('top'),
|
175
|
+
left: this.$contents.css('left')
|
176
|
+
});
|
177
|
+
}
|
178
|
+
this.$box.click((function(_this) {
|
179
|
+
return function() {
|
180
|
+
return Xray.open(_this.path);
|
181
|
+
};
|
182
|
+
})(this));
|
183
|
+
return this.$box.append(this.makeLabel);
|
184
|
+
};
|
185
|
+
|
186
|
+
Specimen.prototype.makeLabel = function() {
|
187
|
+
return $("<div class='xray-specimen-handle " + this.constructor.name + "'>").append(this.name);
|
188
|
+
};
|
189
|
+
|
190
|
+
return Specimen;
|
191
|
+
|
192
|
+
})();
|
193
|
+
|
194
|
+
Xray.ViewSpecimen = (function(superClass) {
|
195
|
+
extend(ViewSpecimen, superClass);
|
196
|
+
|
197
|
+
function ViewSpecimen() {
|
198
|
+
return ViewSpecimen.__super__.constructor.apply(this, arguments);
|
199
|
+
}
|
200
|
+
|
201
|
+
ViewSpecimen.all = [];
|
202
|
+
|
203
|
+
return ViewSpecimen;
|
204
|
+
|
205
|
+
})(Xray.Specimen);
|
206
|
+
|
207
|
+
Xray.TemplateSpecimen = (function(superClass) {
|
208
|
+
extend(TemplateSpecimen, superClass);
|
209
|
+
|
210
|
+
function TemplateSpecimen() {
|
211
|
+
return TemplateSpecimen.__super__.constructor.apply(this, arguments);
|
212
|
+
}
|
213
|
+
|
214
|
+
TemplateSpecimen.all = [];
|
215
|
+
|
216
|
+
return TemplateSpecimen;
|
217
|
+
|
218
|
+
})(Xray.Specimen);
|
219
|
+
|
220
|
+
Xray.Overlay = (function() {
|
221
|
+
Overlay.instance = function() {
|
222
|
+
return this.singletonInstance || (this.singletonInstance = new this);
|
223
|
+
};
|
224
|
+
|
225
|
+
function Overlay() {
|
226
|
+
Xray.Overlay.singletonInstance = this;
|
227
|
+
this.bar = new Xray.Bar('#xray-bar');
|
228
|
+
this.settings = new Xray.Settings('#xray-settings');
|
229
|
+
this.shownBoxes = [];
|
230
|
+
this.$overlay = $('<div id="xray-overlay">');
|
231
|
+
this.$overlay.click((function(_this) {
|
232
|
+
return function() {
|
233
|
+
return _this.hide();
|
234
|
+
};
|
235
|
+
})(this));
|
236
|
+
}
|
237
|
+
|
238
|
+
Overlay.prototype.show = function(type) {
|
239
|
+
if (type == null) {
|
240
|
+
type = null;
|
241
|
+
}
|
242
|
+
this.reset();
|
243
|
+
Xray.isShowing = true;
|
244
|
+
return util.bm('show', (function(_this) {
|
245
|
+
return function() {
|
246
|
+
var element, i, len, results, specimens;
|
247
|
+
_this.bar.$el().find('#xray-bar-togglers .xray-bar-btn').removeClass('active');
|
248
|
+
if (!_this.$overlay.is(':visible')) {
|
249
|
+
$('body').append(_this.$overlay);
|
250
|
+
_this.bar.show();
|
251
|
+
}
|
252
|
+
switch (type) {
|
253
|
+
case 'templates':
|
254
|
+
Xray.findTemplates();
|
255
|
+
specimens = Xray.TemplateSpecimen.all;
|
256
|
+
_this.bar.$el().find('.xray-bar-templates-toggler').addClass('active');
|
257
|
+
break;
|
258
|
+
case 'views':
|
259
|
+
specimens = Xray.ViewSpecimen.all;
|
260
|
+
_this.bar.$el().find('.xray-bar-views-toggler').addClass('active');
|
261
|
+
break;
|
262
|
+
default:
|
263
|
+
Xray.findTemplates();
|
264
|
+
specimens = Xray.specimens();
|
265
|
+
_this.bar.$el().find('.xray-bar-all-toggler').addClass('active');
|
266
|
+
}
|
267
|
+
results = [];
|
268
|
+
for (i = 0, len = specimens.length; i < len; i++) {
|
269
|
+
element = specimens[i];
|
270
|
+
if (!element.isVisible()) {
|
271
|
+
continue;
|
272
|
+
}
|
273
|
+
element.makeBox();
|
274
|
+
element.$box.css({
|
275
|
+
zIndex: Math.ceil(MAX_ZINDEX * 0.9 + element.bounds.top + element.bounds.left)
|
276
|
+
});
|
277
|
+
_this.shownBoxes.push(element.$box);
|
278
|
+
results.push($('body').append(element.$box));
|
279
|
+
}
|
280
|
+
return results;
|
281
|
+
};
|
282
|
+
})(this));
|
283
|
+
};
|
284
|
+
|
285
|
+
Overlay.prototype.reset = function() {
|
286
|
+
var $box, i, len, ref;
|
287
|
+
ref = this.shownBoxes;
|
288
|
+
for (i = 0, len = ref.length; i < len; i++) {
|
289
|
+
$box = ref[i];
|
290
|
+
$box.remove();
|
291
|
+
}
|
292
|
+
return this.shownBoxes = [];
|
293
|
+
};
|
294
|
+
|
295
|
+
Overlay.prototype.hide = function() {
|
296
|
+
Xray.isShowing = false;
|
297
|
+
this.$overlay.detach();
|
298
|
+
this.reset();
|
299
|
+
return this.bar.hide();
|
300
|
+
};
|
301
|
+
|
302
|
+
return Overlay;
|
303
|
+
|
304
|
+
})();
|
305
|
+
|
306
|
+
Xray.Bar = (function() {
|
307
|
+
function Bar(el) {
|
308
|
+
this.el = el;
|
309
|
+
}
|
310
|
+
|
311
|
+
Bar.prototype.$el = function() {
|
312
|
+
if ((this.$el_memo != null) && $.contains(window.document, this.$el_memo[0])) {
|
313
|
+
return this.$el_memo;
|
314
|
+
}
|
315
|
+
this.$el_memo = $(this.el);
|
316
|
+
this.$el_memo.css({
|
317
|
+
zIndex: MAX_ZINDEX
|
318
|
+
});
|
319
|
+
this.$el_memo.find('#xray-bar-controller-path .xray-bar-btn').click(function() {
|
320
|
+
return Xray.open($(this).attr('data-path'));
|
321
|
+
});
|
322
|
+
this.$el_memo.find('.xray-bar-all-toggler').click(function() {
|
323
|
+
return Xray.show();
|
324
|
+
});
|
325
|
+
this.$el_memo.find('.xray-bar-templates-toggler').click(function() {
|
326
|
+
return Xray.show('templates');
|
327
|
+
});
|
328
|
+
this.$el_memo.find('.xray-bar-views-toggler').click(function() {
|
329
|
+
return Xray.show('views');
|
330
|
+
});
|
331
|
+
this.$el_memo.find('.xray-bar-settings-btn').click(function() {
|
332
|
+
return Xray.toggleSettings();
|
333
|
+
});
|
334
|
+
return this.$el_memo;
|
335
|
+
};
|
336
|
+
|
337
|
+
Bar.prototype.show = function() {
|
338
|
+
this.$el().show();
|
339
|
+
this.originalPadding = parseInt($('html').css('padding-bottom'));
|
340
|
+
if (this.originalPadding < 40) {
|
341
|
+
return $('html').css({
|
342
|
+
paddingBottom: 40
|
343
|
+
});
|
344
|
+
}
|
345
|
+
};
|
346
|
+
|
347
|
+
Bar.prototype.hide = function() {
|
348
|
+
this.$el().hide();
|
349
|
+
return $('html').css({
|
350
|
+
paddingBottom: this.originalPadding
|
351
|
+
});
|
352
|
+
};
|
353
|
+
|
354
|
+
return Bar;
|
355
|
+
|
356
|
+
})();
|
357
|
+
|
358
|
+
Xray.Settings = (function() {
|
359
|
+
function Settings(el) {
|
360
|
+
this.displayUpdateMsg = bind(this.displayUpdateMsg, this);
|
361
|
+
this.save = bind(this.save, this);
|
362
|
+
this.toggle = bind(this.toggle, this);
|
363
|
+
this.el = el;
|
364
|
+
}
|
365
|
+
|
366
|
+
Settings.prototype.$el = function() {
|
367
|
+
if ((this.$el_memo != null) && $.contains(window.document, this.$el_memo[0])) {
|
368
|
+
return this.$el_memo;
|
369
|
+
}
|
370
|
+
this.$el_memo = $(this.el);
|
371
|
+
this.$el_memo.find('form').submit(this.save);
|
372
|
+
return this.$el_memo;
|
373
|
+
};
|
374
|
+
|
375
|
+
Settings.prototype.toggle = function() {
|
376
|
+
return this.$el().toggle();
|
377
|
+
};
|
378
|
+
|
379
|
+
Settings.prototype.save = function(e) {
|
380
|
+
var editor;
|
381
|
+
e.preventDefault();
|
382
|
+
editor = this.$el().find('#xray-editor-input').val();
|
383
|
+
return $.ajax({
|
384
|
+
url: '/_xray/config',
|
385
|
+
type: 'POST',
|
386
|
+
data: {
|
387
|
+
editor: editor
|
388
|
+
},
|
389
|
+
success: (function(_this) {
|
390
|
+
return function() {
|
391
|
+
return _this.displayUpdateMsg(true);
|
392
|
+
};
|
393
|
+
})(this),
|
394
|
+
error: (function(_this) {
|
395
|
+
return function() {
|
396
|
+
return _this.displayUpdateMsg(false);
|
397
|
+
};
|
398
|
+
})(this)
|
399
|
+
});
|
400
|
+
};
|
401
|
+
|
402
|
+
Settings.prototype.displayUpdateMsg = function(success) {
|
403
|
+
var $msg;
|
404
|
+
if (success) {
|
405
|
+
$msg = $("<span class='xray-settings-success xray-settings-update-msg'>Success!</span>");
|
406
|
+
} else {
|
407
|
+
$msg = $("<span class='xray-settings-error xray-settings-update-msg'>Uh oh, something went wrong!</span>");
|
408
|
+
}
|
409
|
+
this.$el().append($msg);
|
410
|
+
return $msg.delay(2000).fadeOut(500, (function(_this) {
|
411
|
+
return function() {
|
412
|
+
$msg.remove();
|
413
|
+
return _this.toggle();
|
414
|
+
};
|
415
|
+
})(this));
|
416
|
+
};
|
417
|
+
|
418
|
+
return Settings;
|
419
|
+
|
420
|
+
})();
|
421
|
+
|
422
|
+
util = {
|
423
|
+
bm: function(name, fn) {
|
424
|
+
var result, time;
|
425
|
+
time = new Date;
|
426
|
+
result = fn();
|
427
|
+
return result;
|
428
|
+
},
|
429
|
+
computeBoundingBox: function($contents) {
|
430
|
+
var $el, boxFrame, el, frame, i, len;
|
431
|
+
if ($contents.length === 1 && $contents.height() <= 0) {
|
432
|
+
return util.computeBoundingBox($contents.children());
|
433
|
+
}
|
434
|
+
boxFrame = {
|
435
|
+
top: Number.POSITIVE_INFINITY,
|
436
|
+
left: Number.POSITIVE_INFINITY,
|
437
|
+
right: Number.NEGATIVE_INFINITY,
|
438
|
+
bottom: Number.NEGATIVE_INFINITY
|
439
|
+
};
|
440
|
+
for (i = 0, len = $contents.length; i < len; i++) {
|
441
|
+
el = $contents[i];
|
442
|
+
$el = $(el);
|
443
|
+
if (!$el.is(':visible')) {
|
444
|
+
continue;
|
445
|
+
}
|
446
|
+
frame = $el.offset();
|
447
|
+
frame.right = frame.left + $el.outerWidth();
|
448
|
+
frame.bottom = frame.top + $el.outerHeight();
|
449
|
+
if (frame.top < boxFrame.top) {
|
450
|
+
boxFrame.top = frame.top;
|
451
|
+
}
|
452
|
+
if (frame.left < boxFrame.left) {
|
453
|
+
boxFrame.left = frame.left;
|
454
|
+
}
|
455
|
+
if (frame.right > boxFrame.right) {
|
456
|
+
boxFrame.right = frame.right;
|
457
|
+
}
|
458
|
+
if (frame.bottom > boxFrame.bottom) {
|
459
|
+
boxFrame.bottom = frame.bottom;
|
460
|
+
}
|
461
|
+
}
|
462
|
+
return {
|
463
|
+
left: boxFrame.left,
|
464
|
+
top: boxFrame.top,
|
465
|
+
width: boxFrame.right - boxFrame.left,
|
466
|
+
height: boxFrame.bottom - boxFrame.top
|
467
|
+
};
|
468
|
+
}
|
469
|
+
};
|
470
|
+
|
471
|
+
}).call(this);
|
data/lib/xray-rails.rb
CHANGED
@@ -17,52 +17,6 @@ module Xray
|
|
17
17
|
Thread.current[:request_info] ||= {}
|
18
18
|
end
|
19
19
|
|
20
|
-
# Patterns for the kind of JS constructors Xray is interested in knowing the
|
21
|
-
# filepath of. Unforunately, these patterns will result in a lot of false
|
22
|
-
# positives, because we can't only match direct Backbone.View subclasses -
|
23
|
-
# the app's JS may have a more complex class hierarchy than that.
|
24
|
-
CONSTRUCTOR_PATTERNS = [
|
25
|
-
'(?!jQuery|_)[\w\.]+\.extend\({', # Match uses of extend(), excluding jQuery and underscore
|
26
|
-
'\(function\(_super\) {' # Coffeescript-generated constructors
|
27
|
-
]
|
28
|
-
|
29
|
-
# Example matches:
|
30
|
-
# MyView = Backbone.View.extend({ ...
|
31
|
-
# Foo.MyView = Backbone.View.extend({ ...
|
32
|
-
# MyView = (function(_super) { ...
|
33
|
-
#
|
34
|
-
# Captures:
|
35
|
-
# $1 = space before the constructor
|
36
|
-
# $2 = the constructor's name
|
37
|
-
# $3 = the beginning of the constructor function
|
38
|
-
CONSTRUCTOR_REGEX = /^( *)([\w\.]+) *= *(#{CONSTRUCTOR_PATTERNS.join('|')})/
|
39
|
-
|
40
|
-
# Returns augmented JS source where constructors Xray wants to know the
|
41
|
-
# filepath of are captured in such a way that at runtime, xray.js can look
|
42
|
-
# up a view constructor's filepath and name.
|
43
|
-
#
|
44
|
-
# This:
|
45
|
-
# MyView = Backbone.View.extend({ ...
|
46
|
-
#
|
47
|
-
# Becomes:
|
48
|
-
# MyView = (window.XrayPaths||(window.XrayPaths={}))['{"name":"MyView","path":"/path/to/file.js"}'] = Backbone.View.extend({ ...
|
49
|
-
#
|
50
|
-
# A goal here was to not add any new lines to the source so as not to throw
|
51
|
-
# off line numbers if an exception is thrown, hence the odd pattern of
|
52
|
-
# abusing an object set operation in a multiple assignment.
|
53
|
-
#
|
54
|
-
# TODO: This is simple and gets the job done, but is a bit ridiculous.
|
55
|
-
# I've also seen this appear in stack traces :( Would love to find a
|
56
|
-
# way to do this without actually writing to the files.
|
57
|
-
def self.augment_js(source, path)
|
58
|
-
source.gsub(CONSTRUCTOR_REGEX) do
|
59
|
-
space, class_name, func = $1, $2, $3
|
60
|
-
info = {name: class_name, path: path.to_s}
|
61
|
-
xray = "(window.XrayPaths||(window.XrayPaths={}))['#{info.to_json}']"
|
62
|
-
"#{space}#{class_name} = #{xray} = #{func}"
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
20
|
# Returns augmented HTML where the source is simply wrapped in an HTML
|
67
21
|
# comment with filepath info. Xray.js uses these comments to associate
|
68
22
|
# elements with the templates that rendered them.
|
data/lib/xray/engine.rb
CHANGED
@@ -10,24 +10,12 @@ module Xray
|
|
10
10
|
app.middleware.use Xray::Middleware
|
11
11
|
|
12
12
|
# Required by Rails 4.1
|
13
|
-
app.config.assets.precompile += %w(xray.js xray
|
13
|
+
app.config.assets.precompile += %w(xray.js xray.css)
|
14
14
|
end
|
15
15
|
|
16
16
|
config.after_initialize do |app|
|
17
17
|
ensure_asset_pipeline_enabled! app
|
18
18
|
|
19
|
-
# Register as a Sprockets processor to augment JS files, including
|
20
|
-
# compiled coffeescript, with filepath information. See
|
21
|
-
# `Xray.augment_js` for details.
|
22
|
-
app.assets.register_postprocessor 'application/javascript', :xray do |context, data|
|
23
|
-
path = context.pathname.to_s
|
24
|
-
if path =~ /^#{app.root}.+\.(js|coffee)(\.|$)/
|
25
|
-
Xray.augment_js(data, path)
|
26
|
-
else
|
27
|
-
data
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
19
|
# Monkey patch ActionView::Template to augment server-side templates
|
32
20
|
# with filepath information. See `Xray.augment_template` for details.
|
33
21
|
ActionView::Template.class_eval do
|
@@ -52,16 +40,40 @@ module Xray
|
|
52
40
|
alias_method_chain :render, :xray
|
53
41
|
end
|
54
42
|
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
43
|
+
# Sprockets preprocessor interface which supports all versions of Sprockets.
|
44
|
+
# See: https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
|
45
|
+
class JavascriptPreprocessor
|
46
|
+
def initialize(filename, &block)
|
47
|
+
@filename = filename
|
48
|
+
@source = block.call
|
49
|
+
end
|
50
|
+
|
51
|
+
def render(context, empty_hash_wtf)
|
52
|
+
self.class.run(@filename, @source, context)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.run(filename, source, context)
|
56
|
+
path = context.pathname.to_s
|
57
|
+
if path =~ /^#{Rails.root}.+\.(jst)(\.|$)/
|
58
|
+
Xray.augment_template(source, path)
|
59
|
+
else
|
60
|
+
source
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.call(input)
|
65
|
+
filename = input[:filename]
|
66
|
+
source = input[:data]
|
67
|
+
context = input[:environment].context_class.new(input)
|
68
|
+
|
69
|
+
result = run(filename, source, context)
|
70
|
+
context.metadata.merge(data: result)
|
62
71
|
end
|
63
72
|
end
|
64
73
|
|
74
|
+
# Augment JS templates
|
75
|
+
app.assets.register_preprocessor 'application/javascript', JavascriptPreprocessor
|
76
|
+
|
65
77
|
# This event is called near the beginning of a request cycle. We use it to
|
66
78
|
# collect information about the controller and action that is responding, for
|
67
79
|
# display in the Xray bar.
|
data/lib/xray/middleware.rb
CHANGED
@@ -4,9 +4,9 @@ module Xray
|
|
4
4
|
OPEN_PATH = '/_xray/open'
|
5
5
|
UPDATE_CONFIG_PATH = '/_xray/config'
|
6
6
|
|
7
|
-
# This middleware is responsible for injecting xray.js
|
8
|
-
# the
|
9
|
-
#
|
7
|
+
# This middleware is responsible for injecting xray.js and the Xray bar into
|
8
|
+
# the app's pages. It also listens for requests to open files with the user's
|
9
|
+
# editor.
|
10
10
|
class Middleware
|
11
11
|
def initialize(app)
|
12
12
|
@app = app
|
@@ -44,7 +44,6 @@ module Xray
|
|
44
44
|
elsif Rails.application.config.assets.debug
|
45
45
|
# Otherwise try to inject xray.js if assets are unbundled
|
46
46
|
if append_js!(body, 'jquery', 'xray')
|
47
|
-
append_js!(body, 'backbone', 'xray-backbone')
|
48
47
|
inject_xray_bar!(body)
|
49
48
|
end
|
50
49
|
end
|
data/lib/xray/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xray-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brent Dillingham
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 3.1.0
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: coffee-rails
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: rspec-rails
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,34 +66,6 @@ dependencies:
|
|
80
66
|
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: backbone-rails
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: sass-rails
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
69
|
- !ruby/object:Gem::Dependency
|
112
70
|
name: haml
|
113
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,20 +80,6 @@ dependencies:
|
|
122
80
|
- - ">="
|
123
81
|
- !ruby/object:Gem::Version
|
124
82
|
version: '0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: eco
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
83
|
- !ruby/object:Gem::Dependency
|
140
84
|
name: capybara
|
141
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,7 +95,7 @@ dependencies:
|
|
151
95
|
- !ruby/object:Gem::Version
|
152
96
|
version: '0'
|
153
97
|
description: Provides a dev bar and an overlay in-browser to visualize your UI's rendered
|
154
|
-
partials
|
98
|
+
partials
|
155
99
|
email:
|
156
100
|
- brentdillingham@gmail.com
|
157
101
|
executables: []
|
@@ -160,7 +104,7 @@ extra_rdoc_files: []
|
|
160
104
|
files:
|
161
105
|
- LICENSE
|
162
106
|
- README.md
|
163
|
-
- app/assets/javascripts/xray
|
107
|
+
- app/assets/javascripts/xray.js
|
164
108
|
- app/assets/javascripts/xray.js.coffee
|
165
109
|
- app/assets/stylesheets/xray.css
|
166
110
|
- app/views/_xray_bar.html.erb
|
@@ -173,9 +117,7 @@ homepage: https://github.com/brentd/xray-rails
|
|
173
117
|
licenses:
|
174
118
|
- MIT
|
175
119
|
metadata: {}
|
176
|
-
post_install_message:
|
177
|
-
Backbone.js support will be removed from xray-rails in version 0.2.0.
|
178
|
-
If you need backbone.js support, lock xray-rails to 0.1.22 to avoid breaking changes.
|
120
|
+
post_install_message:
|
179
121
|
rdoc_options: []
|
180
122
|
require_paths:
|
181
123
|
- lib
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# Xray Backbone integration. This involves hooking into the lifecycle
|
2
|
-
# of Backbone.View by monkey patching its prototype. Would love a cleaner
|
3
|
-
# way of doing this, as nobody wants to this stuff in their stack traces.
|
4
|
-
|
5
|
-
return unless window.Backbone && window.Xray
|
6
|
-
|
7
|
-
# Wrap Backbone.View::_ensureElement to add the view to Xray once
|
8
|
-
# its element has been setup.
|
9
|
-
_ensureElement = Backbone.View::_ensureElement
|
10
|
-
Backbone.View::_ensureElement = ->
|
11
|
-
_.defer =>
|
12
|
-
if info = Xray.constructorInfo @constructor
|
13
|
-
Xray.ViewSpecimen.add @el, info
|
14
|
-
_ensureElement.apply(this, arguments)
|
15
|
-
|
16
|
-
# Cleanup when view is removed.
|
17
|
-
_remove = Backbone.View::remove
|
18
|
-
Backbone.View::remove = ->
|
19
|
-
Xray.ViewSpecimen.remove @el
|
20
|
-
_remove.apply(this, arguments)
|