capybara-ember-inspector 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +37 -0
  6. data/Rakefile +2 -0
  7. data/capybara-ember-inspector.gemspec +26 -0
  8. data/lib/capybara/ember/inspector.rb +12 -0
  9. data/lib/capybara/ember/inspector/extension/.gitignore +0 -0
  10. data/lib/capybara/ember/inspector/extension/background-script.js +74 -0
  11. data/lib/capybara/ember/inspector/extension/content-script.js +58 -0
  12. data/lib/capybara/ember/inspector/extension/devtools.html +24 -0
  13. data/lib/capybara/ember/inspector/extension/devtools.js +5 -0
  14. data/lib/capybara/ember/inspector/extension/ember_debug/ember_debug.js +3173 -0
  15. data/lib/capybara/ember/inspector/extension/images/arrow_down.svg +52 -0
  16. data/lib/capybara/ember/inspector/extension/images/calculate.svg +15 -0
  17. data/lib/capybara/ember/inspector/extension/images/ember-icon-final.png +0 -0
  18. data/lib/capybara/ember/inspector/extension/images/fishy_tomster.png +0 -0
  19. data/lib/capybara/ember/inspector/extension/images/hamster.png +0 -0
  20. data/lib/capybara/ember/inspector/extension/images/icon128.png +0 -0
  21. data/lib/capybara/ember/inspector/extension/images/icon16.png +0 -0
  22. data/lib/capybara/ember/inspector/extension/images/icon19.png +0 -0
  23. data/lib/capybara/ember/inspector/extension/images/icon38.png +0 -0
  24. data/lib/capybara/ember/inspector/extension/images/icon48.png +0 -0
  25. data/lib/capybara/ember/inspector/extension/images/send.png +0 -0
  26. data/lib/capybara/ember/inspector/extension/images/send_arrow.png +0 -0
  27. data/lib/capybara/ember/inspector/extension/images/tomster.png +0 -0
  28. data/lib/capybara/ember/inspector/extension/in-page-script.js +14 -0
  29. data/lib/capybara/ember/inspector/extension/manifest.json +39 -0
  30. data/lib/capybara/ember/inspector/extension/options.html +62 -0
  31. data/lib/capybara/ember/inspector/extension/options.js +26 -0
  32. data/lib/capybara/ember/inspector/extension/panes/ember_extension.css +1411 -0
  33. data/lib/capybara/ember/inspector/extension/panes/ember_extension.js +4687 -0
  34. data/lib/capybara/ember/inspector/extension/panes/index.html +17 -0
  35. data/lib/capybara/ember/inspector/extension/panes/start.js +3 -0
  36. data/lib/capybara/ember/inspector/extension/vendor/chrome-bootstrap.css +636 -0
  37. data/lib/capybara/ember/inspector/extension/vendor/ember.js +46943 -0
  38. data/lib/capybara/ember/inspector/extension/vendor/ember.prod.js +46498 -0
  39. data/lib/capybara/ember/inspector/extension/vendor/handlebars.js +2278 -0
  40. data/lib/capybara/ember/inspector/extension/vendor/jquery.js +9555 -0
  41. data/lib/capybara/ember/inspector/extension/vendor/list-view.prod.js +1437 -0
  42. data/lib/capybara/ember/inspector/extension/vendor/loader.js +41 -0
  43. data/lib/capybara/ember/inspector/extension/vendor/resolver.js +188 -0
  44. data/lib/capybara/ember/inspector/version.rb +7 -0
  45. metadata +158 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6eb56fdc8ba70d877c55a6ca542df82c4d12981c
4
+ data.tar.gz: 03605ec8dc77cdbff26360095f22de230429ecde
5
+ SHA512:
6
+ metadata.gz: c1065370242abe2cad2ec6ed41efb5d79a99dcc11609f737f7f7a9a26c293fa37146a6c25c91ef9a3f76f254af1e7f0c8d55a925c25cb1dd4c05c6260f803a46
7
+ data.tar.gz: 7eb4ef24052ce57844d9891464fd21165ea5f2453b015f95421198fd5acb4c6e97c9bd7d15ffaaadae580c8e4777b3f2845c9f146e73f0e9a08207271b7ff175
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capybara-ember-inspector.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Attila Györffy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # Capybara::Ember::Inspector
2
+
3
+ Adds Ember Inspector capable Selenium Driver into your Capybara tests for convenient debugging
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ group :test do
11
+ gem 'capybara-ember-inspector', require: false
12
+ end
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install capybara-ember-inspector
22
+
23
+ ## Usage
24
+
25
+ Require `capybara/ember/inspector` in your test file, for example in `rails_helper.rb` or `spec_helper.rb` to set up Capybara's `:selenium` Driver to run your tests in Chrome with the Ember Inspector extension already enabled. This allows you to pause your tests at any time and activeate the inspector within Chrome, just like you would during development.
26
+
27
+ ## Licensing
28
+
29
+ This gem contains a pre-built version of the [Ember Inspector](https://github.com/emberjs/ember-inspector) source code that is licensed under the [MIT License](https://github.com/emberjs/ember-inspector/blob/master/LICENSE) and is subject to copyrights.
30
+
31
+ ## Contributing
32
+
33
+ 1. Fork it ( https://github.com/[my-github-username]/capybara-ember-inspector/fork )
34
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
35
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
36
+ 4. Push to the branch (`git push origin my-new-feature`)
37
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'capybara/ember/inspector/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "capybara-ember-inspector"
8
+ spec.version = Capybara::Ember::Inspector::VERSION
9
+ spec.authors = ["Attila Györffy"]
10
+ spec.email = ["attila@attilagyorffy.com"]
11
+ spec.summary = %q{Capybara and Ember (Tomster) sitting on a tree.}
12
+ spec.description = %q{Adds Ember Inspector capable Selenium Driver into your Capybara tests for convenient debugging}
13
+ spec.homepage = "https://github.com/liquid/capybara-ember-inspector"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_runtime_dependency "capybara"
24
+ spec.add_runtime_dependency "selenium-webdriver"
25
+ spec.add_runtime_dependency "chromedriver-helper"
26
+ end
@@ -0,0 +1,12 @@
1
+ require "capybara/ember/inspector/version"
2
+
3
+ Capybara.register_driver :selenium do |app|
4
+ extension = File.expand_path('../inspector/extension', __FILE__)
5
+
6
+ Capybara::Selenium::Driver.new(app,
7
+ browser: :chrome,
8
+ switches: [
9
+ "--load-extension=#{extension}"
10
+ ]
11
+ )
12
+ end
@@ -0,0 +1,74 @@
1
+ /*global chrome*/
2
+ (function() {
3
+ "use strict";
4
+
5
+ var activeTabs = {},
6
+ ports = {};
7
+
8
+ function generateVersionsTooltip(versions) {
9
+ return versions.map(function(lib) {
10
+ return lib.name + " " + lib.version;
11
+ }).join("\n");
12
+ }
13
+
14
+ function setActionTitle(tabId){
15
+ chrome.pageAction.setTitle({
16
+ tabId: tabId,
17
+ title: generateVersionsTooltip(activeTabs[tabId])
18
+ });
19
+ }
20
+
21
+ function updateTabAction(tabId){
22
+ chrome.storage.sync.get("options", function(data) {
23
+ if (!data.options.showTomster) { return; }
24
+ chrome.pageAction.show(tabId);
25
+ setActionTitle(tabId);
26
+ });
27
+ }
28
+
29
+ function hideAction(tabId){
30
+ delete activeTabs[tabId];
31
+ chrome.pageAction.hide(tabId);
32
+ }
33
+
34
+ chrome.extension.onMessage.addListener(function(request, sender) {
35
+ if (!sender.tab) {
36
+ // noop
37
+ } else if (request && request.type === 'emberVersion') {
38
+ activeTabs[sender.tab.id] = request.versions;
39
+ updateTabAction(sender.tab.id);
40
+ } else if (request && request.type === 'resetEmberIcon') {
41
+ hideAction(sender.tab.id);
42
+ } else {
43
+ var port = ports[sender.tab.id];
44
+ if (port) { port.postMessage(request); }
45
+ }
46
+ });
47
+
48
+ chrome.extension.onConnect.addListener(function(port) {
49
+ var appId;
50
+
51
+ port.onMessage.addListener(function(message) {
52
+ if (message.appId) {
53
+ appId = message.appId;
54
+
55
+ ports[appId] = port;
56
+
57
+ port.onDisconnect.addListener(function() {
58
+ delete ports[appId];
59
+ });
60
+ } else if (message.from === 'devtools') {
61
+ chrome.tabs.sendMessage(appId, message);
62
+ }
63
+ });
64
+ });
65
+
66
+ chrome.tabs.onUpdated.addListener(function(tabId){
67
+ // Re-render the Tomster when a tab changes.
68
+ if (activeTabs[tabId]) {
69
+ updateTabAction(tabId);
70
+ }
71
+
72
+ });
73
+
74
+ }());
@@ -0,0 +1,58 @@
1
+ (function() {
2
+
3
+ "use strict";
4
+
5
+ window.addEventListener('message', function(event) {
6
+ if (event.data === 'debugger-client') {
7
+ var port = event.ports[0];
8
+ listenToPort(port);
9
+ } else if (event.data.type) {
10
+ chrome.extension.sendMessage(event.data);
11
+ }
12
+ });
13
+
14
+ function listenToPort(port) {
15
+ port.addEventListener('message', function(event) {
16
+ chrome.extension.sendMessage(event.data);
17
+ });
18
+
19
+ chrome.extension.onMessage.addListener(function(message) {
20
+ if (message.from === 'devtools') {
21
+ port.postMessage(message);
22
+ }
23
+ });
24
+
25
+ port.start();
26
+ }
27
+
28
+ // let ember-debug know that content script has executed
29
+ document.documentElement.dataset.emberExtension = 1;
30
+
31
+
32
+ // clear a possible previous Ember icon
33
+ chrome.extension.sendMessage({ type: 'resetEmberIcon' });
34
+
35
+ // inject JS into the page to check for an app on domready
36
+ var script = document.createElement('script');
37
+ script.type = "text/javascript";
38
+ script.src = chrome.extension.getURL("in-page-script.js");
39
+ if (document.body) {
40
+ document.body.appendChild(script);
41
+ script.onload = function() {
42
+ document.body.removeChild(script);
43
+ };
44
+ }
45
+
46
+ var iframes = document.getElementsByTagName('iframe');
47
+ var urls = [];
48
+ for (var i = 0, l = iframes.length; i < l; i ++) {
49
+ urls.push(iframes[i].src);
50
+ }
51
+
52
+ // FIXME
53
+ setTimeout(function() {
54
+ chrome.extension.sendMessage({type: 'iframes', urls: urls});
55
+ }, 500);
56
+
57
+
58
+ }());
@@ -0,0 +1,24 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <style>
5
+ body {
6
+ min-width: 357px;
7
+ overflow-x: hidden;
8
+ }
9
+
10
+ img {
11
+ margin: 5px;
12
+ border: 2px solid black;
13
+ vertical-align: middle;
14
+ width: 75px;
15
+ height: 75px;
16
+ }
17
+ </style>
18
+
19
+ <script src="devtools.js"></script>
20
+ </head>
21
+ <body>
22
+ </body>
23
+ </html>
24
+
@@ -0,0 +1,5 @@
1
+ /*global chrome*/
2
+
3
+ var panelWindow, injectedPanel = false, injectedPage = false, panelVisible = false, savedStack = [];
4
+
5
+ chrome.devtools.panels.create("Ember", "images/ember-icon-final.png", "panes/index.html");
@@ -0,0 +1,3173 @@
1
+ (function(adapter) {
2
+
3
+ if (typeof define !== 'function' && typeof requireModule !== 'function') {
4
+ var define, requireModule;
5
+
6
+ (function() {
7
+ var registry = {}, seen = {};
8
+
9
+ define = function(name, deps, callback) {
10
+ registry[name] = { deps: deps, callback: callback };
11
+ };
12
+
13
+ requireModule = function(name) {
14
+ if (seen[name]) { return seen[name]; }
15
+ seen[name] = {};
16
+
17
+ var mod = registry[name];
18
+
19
+ if (!mod) {
20
+ throw new Error("Module: '" + name + "' not found.");
21
+ }
22
+
23
+ var deps = mod.deps,
24
+ callback = mod.callback,
25
+ reified = [],
26
+ exports;
27
+
28
+ for (var i=0, l=deps.length; i<l; i++) {
29
+ if (deps[i] === 'exports') {
30
+ reified.push(exports = {});
31
+ } else {
32
+ reified.push(requireModule(deps[i]));
33
+ }
34
+ }
35
+
36
+ var value = callback.apply(this, reified);
37
+ return seen[name] = exports || value;
38
+ };
39
+
40
+ define.registry = registry;
41
+ define.seen = seen;
42
+ })();
43
+ }
44
+
45
+ /**
46
+ This is a wrapper for `ember-debug.js`
47
+ Wraps the script in a function,
48
+ and ensures that the script is executed
49
+ only after the dom is ready
50
+ and the application has initialized.
51
+
52
+ Also responsible for sending the first tree.
53
+ **/
54
+
55
+ var currentAdapter = 'basic';
56
+ if (typeof adapter !== 'undefined') {
57
+ currentAdapter = adapter;
58
+ }
59
+
60
+ (function(adapter) {
61
+
62
+ // RSVP promise inspection
63
+ // First thing because of
64
+ var events = [], callbacks = {};
65
+ if (!window.__PROMISE_INSTRUMENTATION__) {
66
+ callbacks = window.__PROMISE_INSTRUMENTATION__ = {};
67
+ var eventNames = ['created', 'fulfilled', 'rejected', 'chained'];
68
+
69
+ for (var i = 0; i < eventNames.length; i++) {
70
+ (function(eventName) {
71
+ callbacks[eventName] = function(options) {
72
+ events.push({
73
+ eventName: eventName,
74
+ options: options
75
+ });
76
+ };
77
+ }(eventNames[i]));
78
+
79
+ }
80
+ }
81
+
82
+
83
+ function inject() {
84
+ window.EmberInspector = Ember.Debug = requireModule('ember_debug')['default'];
85
+ }
86
+
87
+ onEmberReady(function() {
88
+ if (!window.Ember) {
89
+ return;
90
+ }
91
+ // global to prevent injection
92
+ if (window.NO_EMBER_DEBUG) {
93
+ return;
94
+ }
95
+ // prevent from injecting twice
96
+ if (!Ember.Debug) {
97
+ inject();
98
+ Ember.Debug.Adapter = requireModule('adapters/' + adapter)['default'];
99
+
100
+ onApplicationStart(function() {
101
+ Ember.Debug.setProperties({
102
+ existingEvents: events,
103
+ existingCallbacks: callbacks
104
+ });
105
+ Ember.Debug.start();
106
+ });
107
+ }
108
+ });
109
+
110
+ function onEmberReady(callback) {
111
+ onReady(function() {
112
+ if (window.Ember) {
113
+ callback();
114
+ } else {
115
+ window.addEventListener('Ember.Application', callback, false);
116
+ }
117
+ });
118
+ }
119
+
120
+ function onReady(callback) {
121
+ if (document.readyState === 'complete') {
122
+ setTimeout(completed);
123
+ } else {
124
+ document.addEventListener( "DOMContentLoaded", completed, false);
125
+ // For some reason DOMContentLoaded doesn't always work
126
+ window.addEventListener( "load", completed, false );
127
+ }
128
+
129
+ function completed() {
130
+ document.removeEventListener( "DOMContentLoaded", completed, false );
131
+ window.removeEventListener( "load", completed, false );
132
+ callback();
133
+ }
134
+ }
135
+
136
+ // There's probably a better way
137
+ // to determine when the application starts
138
+ // but this definitely works
139
+ function onApplicationStart(callback) {
140
+ if (typeof Ember === 'undefined') {
141
+ return;
142
+ }
143
+ var documentElement = document.documentElement;
144
+ var interval = setInterval(function() {
145
+ if ((documentElement.dataset.emberExtension || (EMBER_INSPECTOR_CONFIG && EMBER_INSPECTOR_CONFIG.remoteDebugSocket)) && Ember.BOOTED) {
146
+ clearInterval(interval);
147
+ callback();
148
+ }
149
+ }, 1);
150
+ }
151
+
152
+ }(currentAdapter));
153
+
154
+ define("adapters/basic",
155
+ ["exports"],
156
+ function(__exports__) {
157
+ "use strict";
158
+ var BasicAdapter = Ember.Object.extend({
159
+ debug: function() {
160
+ console.debug.apply(console, arguments);
161
+ },
162
+ log: function() {
163
+ console.log.apply(console, arguments);
164
+ },
165
+ /**
166
+ Used to send messages to EmberExtension
167
+
168
+ @param {Object} type the message to the send
169
+ */
170
+ sendMessage: function(options) {},
171
+
172
+ /**
173
+ Register functions to be called
174
+ when a message from EmberExtension is received
175
+
176
+ @param {Function} callback
177
+ */
178
+ onMessageReceived: function(callback) {
179
+ this.get('_messageCallbacks').pushObject(callback);
180
+ },
181
+
182
+ /**
183
+ Inspect a specific element. This usually
184
+ means using the current environment's tools
185
+ to inspect the element in the DOM.
186
+
187
+ For example, in chrome, `inspect(elem)`
188
+ will open the Elements tab in dev tools
189
+ and highlight the element.
190
+
191
+ @param {DOM Element} elem
192
+ */
193
+ inspectElement: function(elem) {},
194
+
195
+ _messageCallbacks: Ember.computed(function() { return Ember.A(); }).property(),
196
+
197
+ _messageReceived: function(message) {
198
+ this.get('_messageCallbacks').forEach(function(callback) {
199
+ callback.call(null, message);
200
+ });
201
+ }
202
+ });
203
+
204
+ __exports__["default"] = BasicAdapter;
205
+ });
206
+ define("adapters/bookmarklet",
207
+ ["adapters/basic","exports"],
208
+ function(__dependency1__, __exports__) {
209
+ "use strict";
210
+ var BasicAdapter = __dependency1__["default"];
211
+ var $ = Ember.$;
212
+
213
+ __exports__["default"] = BasicAdapter.extend({
214
+ init: function() {
215
+ this._super();
216
+ this._connect();
217
+ },
218
+
219
+ sendMessage: function(options) {
220
+ options = options || {};
221
+ window.emberInspector.w.postMessage(options, window.emberInspector.url);
222
+ },
223
+
224
+ _connect: function() {
225
+ var self = this;
226
+ window.addEventListener('message', function(e) {
227
+ if (e.origin !== window.emberInspector.url) {
228
+ return;
229
+ }
230
+ var message = e.data;
231
+ if (message.from === 'devtools') {
232
+ self._messageReceived(message);
233
+ }
234
+ });
235
+
236
+ $(window).on('unload', function() {
237
+ self.sendMessage({
238
+ unloading: true
239
+ });
240
+ });
241
+ }
242
+ });
243
+ });
244
+ define("adapters/chrome",
245
+ ["adapters/basic","exports"],
246
+ function(__dependency1__, __exports__) {
247
+ "use strict";
248
+ var BasicAdapter = __dependency1__["default"];
249
+
250
+ var ChromeAdapter = BasicAdapter.extend({
251
+ init: function() {
252
+ this._super();
253
+ this._connect();
254
+ },
255
+
256
+ sendMessage: function(options) {
257
+ options = options || {};
258
+ this.get('_chromePort').postMessage(options);
259
+ },
260
+
261
+ inspectElement: function(elem) {
262
+ inspect(elem);
263
+ },
264
+
265
+ _channel: Ember.computed(function() {
266
+ return new MessageChannel();
267
+ }).property(),
268
+
269
+ _chromePort: Ember.computed(function() {
270
+ return this.get('_channel.port1');
271
+ }).property(),
272
+
273
+ _connect: function() {
274
+ var channel = this.get('_channel'),
275
+ self = this,
276
+ chromePort = this.get('_chromePort');
277
+
278
+ window.postMessage('debugger-client', [channel.port2], '*');
279
+
280
+ chromePort.addEventListener('message', function(event) {
281
+ var message = event.data;
282
+ Ember.run(function() {
283
+ self._messageReceived(message);
284
+ });
285
+ });
286
+
287
+ chromePort.start();
288
+
289
+ }
290
+ });
291
+
292
+ __exports__["default"] = ChromeAdapter;
293
+ });
294
+ define("adapters/firefox",
295
+ ["adapters/basic","exports"],
296
+ function(__dependency1__, __exports__) {
297
+ "use strict";
298
+ var BasicAdapter = __dependency1__["default"];
299
+
300
+ var FirefoxAdapter = BasicAdapter.extend({
301
+ init: function() {
302
+ this._super();
303
+ this._connect();
304
+ },
305
+
306
+ debug: function() {
307
+ // WORKAROUND: temporarily workaround issues with firebug console object:
308
+ // - https://github.com/tildeio/ember-extension/issues/94
309
+ // - https://github.com/firebug/firebug/pull/109
310
+ // - https://code.google.com/p/fbug/issues/detail?id=7045
311
+ try {
312
+ this._super.apply(this, arguments);
313
+ } catch(e) { }
314
+ },
315
+ log: function() {
316
+ // WORKAROUND: temporarily workaround issues with firebug console object:
317
+ // - https://github.com/tildeio/ember-extension/issues/94
318
+ // - https://github.com/firebug/firebug/pull/109
319
+ // - https://code.google.com/p/fbug/issues/detail?id=7045
320
+ try {
321
+ this._super.apply(this, arguments);
322
+ } catch(e) { }
323
+ },
324
+
325
+ sendMessage: function(options) {
326
+ options = options || {};
327
+ var event = document.createEvent("CustomEvent");
328
+ event.initCustomEvent("ember-debug-send", true, true, options);
329
+ document.documentElement.dispatchEvent(event);
330
+ },
331
+
332
+ inspectElement: function(elem) {
333
+ this.sendMessage({
334
+ type: 'view:devtools:inspectDOMElement',
335
+ elementSelector: "#" + elem.getAttribute('id')
336
+ });
337
+ },
338
+
339
+ _connect: function() {
340
+ var self = this;
341
+
342
+ window.addEventListener('ember-debug-receive', function(event) {
343
+ var message = event.detail;
344
+ Ember.run(function() {
345
+ // FIX: needed to fix permission denied exception on Firefox >= 30
346
+ // - https://github.com/emberjs/ember-inspector/issues/147
347
+ // - https://blog.mozilla.org/addons/2014/04/10/changes-to-unsafewindow-for-the-add-on-sdk/
348
+ switch (typeof message) {
349
+ case "string":
350
+ message = JSON.parse(message);
351
+ break;
352
+ case "object":
353
+ break;
354
+ default:
355
+ throw new Error("ember-debug-receive: string or object expected");
356
+ }
357
+ self._messageReceived(message);
358
+ });
359
+ });
360
+ }
361
+
362
+ });
363
+
364
+ __exports__["default"] = FirefoxAdapter;
365
+ });
366
+ define("adapters/websocket",
367
+ ["adapters/basic","exports"],
368
+ function(__dependency1__, __exports__) {
369
+ "use strict";
370
+ var BasicAdapter = __dependency1__["default"];
371
+
372
+ var computed = Ember.computed;
373
+
374
+ var WebsocketAdapter = BasicAdapter.extend({
375
+ init: function() {
376
+ this._super();
377
+ this._connect();
378
+ },
379
+
380
+ sendMessage: function(options) {
381
+ options = options || {};
382
+ this.get('socket').emit('emberInspectorMessage', options);
383
+ },
384
+
385
+ socket: computed(function() {
386
+ return window.EMBER_INSPECTOR_CONFIG.remoteDebugSocket;
387
+ }).property(),
388
+
389
+ _connect: function() {
390
+ var self = this;
391
+ this.get('socket').on('emberInspectorMessage', function(message) {
392
+ Ember.run(function() {
393
+ self._messageReceived(message);
394
+ });
395
+ });
396
+ },
397
+
398
+ _disconnect: function() {
399
+ this.get('socket').removeAllListeners("emberInspectorMessage");
400
+ },
401
+
402
+ willDestroy: function() {
403
+ this._disconnect();
404
+ }
405
+ });
406
+
407
+ __exports__["default"] = WebsocketAdapter;
408
+ });
409
+ define("container_debug",
410
+ ["mixins/port_mixin","exports"],
411
+ function(__dependency1__, __exports__) {
412
+ "use strict";
413
+ var PortMixin = __dependency1__["default"];
414
+
415
+ var EmberObject = Ember.Object;
416
+ var computed = Ember.computed;
417
+ var oneWay = computed.oneWay;
418
+
419
+ __exports__["default"] = EmberObject.extend(PortMixin, {
420
+ namespace: null,
421
+
422
+ port: oneWay('namespace.port').readOnly(),
423
+ application: oneWay('namespace.application').readOnly(),
424
+ objectInspector: oneWay('namespace.objectInspector').readOnly(),
425
+
426
+ container: computed(function() {
427
+ return this.get('application.__container__');
428
+ }).property('application'),
429
+
430
+ portNamespace: 'container',
431
+
432
+ TYPES_TO_SKIP: computed(function() {
433
+ return [
434
+ 'component-lookup',
435
+ 'container-debug-adapter',
436
+ 'resolver-for-debugging',
437
+ 'event_dispatcher'
438
+ ];
439
+ }).property(),
440
+
441
+ typeFromKey: function(key) {
442
+ return key.split(':').shift();
443
+ },
444
+
445
+ nameFromKey: function(key) {
446
+ return key.split(':').pop();
447
+ },
448
+
449
+ shouldHide: function(type) {
450
+ return type[0] === '-' || this.get('TYPES_TO_SKIP').indexOf(type) !== -1;
451
+ },
452
+
453
+ instancesByType: function() {
454
+ var key, instancesByType = {};
455
+ var cache = this.get('container').cache;
456
+ // Detect if InheritingDict (from Ember < 1.8)
457
+ if (typeof cache.dict !== 'undefined' && typeof cache.eachLocal !== 'undefined') {
458
+ cache = cache.dict;
459
+ }
460
+ for (key in cache) {
461
+ var type = this.typeFromKey(key);
462
+ if (this.shouldHide(type) ){ continue; }
463
+ if (instancesByType[type] === undefined) {
464
+ instancesByType[type] = [];
465
+ }
466
+ instancesByType[type].push({
467
+ fullName: key,
468
+ instance: cache[key]
469
+ });
470
+ }
471
+ return instancesByType;
472
+ },
473
+
474
+ getTypes: function() {
475
+ var key, types = [];
476
+ var instancesByType = this.instancesByType();
477
+ for (key in instancesByType) {
478
+ types.push({ name: key, count: instancesByType[key].length });
479
+ }
480
+ return types;
481
+ },
482
+
483
+ getInstances: function(type) {
484
+ var instancesByType = this.instancesByType();
485
+ return instancesByType[type].map(function(item) {
486
+ return {
487
+ name: this.nameFromKey(item.fullName),
488
+ fullName: item.fullName,
489
+ inspectable: this.get('objectInspector').canSend(item.instance)
490
+ };
491
+ }.bind(this));
492
+ },
493
+
494
+ messages: {
495
+ getTypes: function() {
496
+ this.sendMessage('types', {
497
+ types: this.getTypes()
498
+ });
499
+ },
500
+ getInstances: function(message) {
501
+ this.sendMessage('instances', {
502
+ instances: this.getInstances(message.containerType)
503
+ });
504
+ },
505
+ sendInstanceToConsole: function(message) {
506
+ var instance = this.get('container').lookup(message.name);
507
+ this.get('objectToConsole').sendValueToConsole(instance);
508
+ }
509
+ }
510
+ });
511
+ });
512
+ define("data_debug",
513
+ ["mixins/port_mixin","exports"],
514
+ function(__dependency1__, __exports__) {
515
+ "use strict";
516
+ var PortMixin = __dependency1__["default"];
517
+
518
+ var DataDebug = Ember.Object.extend(PortMixin, {
519
+ init: function() {
520
+ this._super();
521
+ this.sentTypes = {};
522
+ this.sentRecords = {};
523
+ },
524
+
525
+ sentTypes: {},
526
+ sentRecords: {},
527
+
528
+ releaseTypesMethod: null,
529
+ releaseRecordsMethod: null,
530
+
531
+ adapter: Ember.computed(function() {
532
+ var container = this.get('application').__container__;
533
+ // dataAdapter:main is deprecated
534
+ return (container.resolve('data-adapter:main') && container.lookup('data-adapter:main')) ||
535
+ (container.resolve('dataAdapter:main') && container.lookup('dataAdapter:main'));
536
+ }).property('application'),
537
+
538
+ namespace: null,
539
+
540
+ port: Ember.computed.alias('namespace.port'),
541
+ application: Ember.computed.alias('namespace.application'),
542
+ objectInspector: Ember.computed.alias('namespace.objectInspector'),
543
+
544
+ portNamespace: 'data',
545
+
546
+ modelTypesAdded: function(types) {
547
+ var self = this, typesToSend;
548
+ typesToSend = types.map(function(type) {
549
+ return self.wrapType(type);
550
+ });
551
+ this.sendMessage('modelTypesAdded', {
552
+ modelTypes: typesToSend
553
+ });
554
+ },
555
+
556
+ modelTypesUpdated: function(types) {
557
+ var self = this;
558
+ var typesToSend = types.map(function(type) {
559
+ return self.wrapType(type);
560
+ });
561
+ self.sendMessage('modelTypesUpdated', {
562
+ modelTypes: typesToSend
563
+ });
564
+ },
565
+
566
+ wrapType: function(type) {
567
+ var objectId = Ember.guidFor(type.object);
568
+ this.sentTypes[objectId] = type;
569
+
570
+ return {
571
+ columns: type.columns,
572
+ count: type.count,
573
+ name: type.name,
574
+ objectId: objectId
575
+ };
576
+ },
577
+
578
+
579
+ recordsAdded: function(recordsReceived) {
580
+ var self = this, records;
581
+ records = recordsReceived.map(function(record) {
582
+ return self.wrapRecord(record);
583
+ });
584
+ self.sendMessage('recordsAdded', {
585
+ records: records
586
+ });
587
+ },
588
+
589
+ recordsUpdated: function(recordsReceived) {
590
+ var self = this;
591
+ var records = recordsReceived.map(function(record) {
592
+ return self.wrapRecord(record);
593
+ });
594
+ self.sendMessage('recordsUpdated', {
595
+ records: records
596
+ });
597
+ },
598
+
599
+ recordsRemoved: function(idx, count) {
600
+ this.sendMessage('recordsRemoved', {
601
+ index: idx,
602
+ count: count
603
+ });
604
+ },
605
+
606
+ wrapRecord: function(record) {
607
+ var objectId = Ember.guidFor(record.object);
608
+ var self = this;
609
+ var columnValues = {};
610
+ var searchKeywords = [];
611
+ this.sentRecords[objectId] = record;
612
+ // make objects clonable
613
+ for (var i in record.columnValues) {
614
+ columnValues[i] = this.get('objectInspector').inspect(record.columnValues[i]);
615
+ }
616
+ // make sure keywords can be searched and clonable
617
+ searchKeywords = Ember.A(record.searchKeywords).filter(function(keyword) {
618
+ return (typeof keyword === 'string' || typeof keyword === 'number');
619
+ });
620
+ return {
621
+ columnValues: columnValues,
622
+ searchKeywords: searchKeywords,
623
+ filterValues: record.filterValues,
624
+ color: record.color,
625
+ objectId: objectId
626
+ };
627
+ },
628
+
629
+ releaseTypes: function() {
630
+ if(this.releaseTypesMethod) {
631
+ this.releaseTypesMethod();
632
+ this.releaseTypesMethod = null;
633
+ this.sentTypes = {};
634
+ }
635
+ },
636
+
637
+ releaseRecords: function(typeObjectId) {
638
+ if (this.releaseRecordsMethod) {
639
+ this.releaseRecordsMethod();
640
+ this.releaseRecordsMethod = null;
641
+ this.sentRecords = {};
642
+ }
643
+ },
644
+
645
+ willDestroy: function() {
646
+ this._super();
647
+ this.releaseRecords();
648
+ this.releaseTypes();
649
+ },
650
+
651
+ messages: {
652
+ checkAdapter: function() {
653
+ this.sendMessage('hasAdapter', { hasAdapter: !!this.get('adapter') });
654
+ },
655
+
656
+ getModelTypes: function() {
657
+ var self = this;
658
+ this.releaseTypes();
659
+ this.releaseTypesMethod = this.get('adapter').watchModelTypes(
660
+ function(types) {
661
+ self.modelTypesAdded(types);
662
+ }, function(types) {
663
+ self.modelTypesUpdated(types);
664
+ });
665
+ },
666
+
667
+ releaseModelTypes: function() {
668
+ this.releaseTypes();
669
+ },
670
+
671
+ getRecords: function(message) {
672
+ var type = this.sentTypes[message.objectId], self = this;
673
+ this.releaseRecords();
674
+
675
+ var releaseMethod = this.get('adapter').watchRecords(type.object,
676
+ function(recordsReceived) {
677
+ self.recordsAdded(recordsReceived);
678
+ },
679
+ function(recordsUpdated) {
680
+ self.recordsUpdated(recordsUpdated);
681
+ },
682
+ function() {
683
+ self.recordsRemoved.apply(self, arguments);
684
+ }
685
+ );
686
+ this.releaseRecordsMethod = releaseMethod;
687
+ },
688
+
689
+ releaseRecords: function() {
690
+ this.releaseRecords();
691
+ },
692
+
693
+ inspectModel: function(message) {
694
+ this.get('objectInspector').sendObject(this.sentRecords[message.objectId].object);
695
+ },
696
+
697
+ getFilters: function() {
698
+ this.sendMessage('filters', {
699
+ filters: this.get('adapter').getFilters()
700
+ });
701
+ }
702
+ }
703
+ });
704
+
705
+ __exports__["default"] = DataDebug;
706
+ });
707
+ define("ember_debug",
708
+ ["adapters/basic","port","object_inspector","general_debug","render_debug","view_debug","route_debug","data_debug","promise_debug","container_debug","exports"],
709
+ function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) {
710
+ "use strict";
711
+ var BasicAdapter = __dependency1__["default"];
712
+ var Port = __dependency2__["default"];
713
+ var ObjectInspector = __dependency3__["default"];
714
+ var GeneralDebug = __dependency4__["default"];
715
+ var RenderDebug = __dependency5__["default"];
716
+ var ViewDebug = __dependency6__["default"];
717
+ var RouteDebug = __dependency7__["default"];
718
+ var DataDebug = __dependency8__["default"];
719
+ var PromiseDebug = __dependency9__["default"];
720
+ var ContainerDebug = __dependency10__["default"];
721
+
722
+ var EmberDebug;
723
+
724
+ EmberDebug = Ember.Namespace.extend({
725
+
726
+ application: null,
727
+ started: false,
728
+
729
+ Port: Port,
730
+ Adapter: BasicAdapter,
731
+
732
+
733
+ // These two are used to make RSVP start instrumentation
734
+ // even before this object is created
735
+ // all events triggered before creation are injected
736
+ // to this object as `existingEvents`
737
+ existingEvents: Ember.computed(function() { return []; }).property(),
738
+ existingCallbacks: Ember.computed(function() { return {}; }).property(),
739
+
740
+ start: function() {
741
+ if (this.get('started')) {
742
+ this.reset();
743
+ return;
744
+ }
745
+ this.set('started', true);
746
+
747
+ this.set('application', getApplication());
748
+
749
+ this.reset();
750
+
751
+ this.get("adapter").debug("Ember Inspector Active");
752
+ },
753
+
754
+ destroyContainer: function() {
755
+ var self = this;
756
+ ['dataDebug',
757
+ 'viewDebug',
758
+ 'routeDebug',
759
+ 'objectInspector',
760
+ 'generalDebug',
761
+ 'renderDebug',
762
+ 'promiseDebug',
763
+ 'containerDebug',
764
+ ].forEach(function(prop) {
765
+ var handler = self.get(prop);
766
+ if (handler) {
767
+ Ember.run(handler, 'destroy');
768
+ self.set(prop, null);
769
+ }
770
+ });
771
+ },
772
+
773
+ startModule: function(prop, Module) {
774
+ this.set(prop, Module.create({ namespace: this }));
775
+ },
776
+
777
+ reset: function() {
778
+ this.destroyContainer();
779
+ Ember.run(this, function() {
780
+
781
+ this.startModule('adapter', this.Adapter);
782
+ this.startModule('port', this.Port);
783
+
784
+ this.startModule('generalDebug', GeneralDebug);
785
+ this.startModule('renderDebug', RenderDebug);
786
+ this.startModule('objectInspector', ObjectInspector);
787
+ this.startModule('routeDebug', RouteDebug);
788
+ this.startModule('viewDebug', ViewDebug);
789
+ this.startModule('dataDebug', DataDebug);
790
+ this.startModule('promiseDebug', PromiseDebug);
791
+ this.startModule('containerDebug', ContainerDebug);
792
+
793
+ this.generalDebug.sendBooted();
794
+ this.viewDebug.sendTree();
795
+ });
796
+ },
797
+
798
+ inspect: function(obj) {
799
+ this.get('objectInspector').sendObject(obj);
800
+ this.get('adapter').log('Sent to the Object Inspector');
801
+ return obj;
802
+ }
803
+
804
+ }).create();
805
+
806
+ function getApplication() {
807
+ var namespaces = Ember.Namespace.NAMESPACES,
808
+ application;
809
+
810
+ namespaces.forEach(function(namespace) {
811
+ if(namespace instanceof Ember.Application) {
812
+ application = namespace;
813
+ return false;
814
+ }
815
+ });
816
+ return application;
817
+ }
818
+
819
+ __exports__["default"] = EmberDebug;
820
+ });
821
+ define("general_debug",
822
+ ["mixins/port_mixin","exports"],
823
+ function(__dependency1__, __exports__) {
824
+ "use strict";
825
+ var PortMixin = __dependency1__["default"];
826
+
827
+ var GeneralDebug = Ember.Object.extend(PortMixin, {
828
+ namespace: null,
829
+
830
+ port: Ember.computed.alias('namespace.port'),
831
+
832
+ application: Ember.computed.alias('namespace.application'),
833
+
834
+ promiseDebug: Ember.computed.alias('namespace.promiseDebug'),
835
+
836
+ portNamespace: 'general',
837
+
838
+ sendBooted: function() {
839
+ this.sendMessage('applicationBooted', {
840
+ booted: Ember.BOOTED
841
+ });
842
+ },
843
+
844
+ messages: {
845
+ applicationBooted: function() {
846
+ this.sendBooted();
847
+ },
848
+ getLibraries: function() {
849
+ var libraries = arrayize(Ember.libraries);
850
+ this.sendMessage('libraries', { libraries: libraries });
851
+ },
852
+ refresh: function() {
853
+ window.location.reload();
854
+ }
855
+ }
856
+ });
857
+
858
+ function arrayize(enumerable) {
859
+ return Ember.A(enumerable).map(function(item) {
860
+ return item;
861
+ });
862
+ }
863
+
864
+ __exports__["default"] = GeneralDebug;
865
+ });
866
+ define("libs/promise_assembler",
867
+ ["models/promise","exports"],
868
+ function(__dependency1__, __exports__) {
869
+ "use strict";
870
+ /**
871
+ Original implementation and the idea behind the `PromiseAssembler`,
872
+ `Promise` model, and other work related to promise inspection was done
873
+ by Stefan Penner (@stefanpenner) thanks to McGraw Hill Education (@mhelabs)
874
+ and Yapp Labs (@yapplabs).
875
+ */
876
+
877
+ var Promise = __dependency1__["default"];
878
+
879
+ var get = Ember.get;
880
+ var alias = Ember.computed.alias;
881
+
882
+ var PromiseAssembler = Ember.Object.extend(Ember.Evented, {
883
+ // RSVP lib to debug
884
+ RSVP: Ember.RSVP,
885
+
886
+ all: Ember.computed(function() { return Ember.A(); }).property(),
887
+
888
+ promiseIndex: Ember.computed(function() { return {}; }).property(),
889
+
890
+ // injected on creation
891
+ promiseDebug: null,
892
+
893
+ existingEvents: alias('promiseDebug.existingEvents'),
894
+ existingCallbacks: alias('promiseDebug.existingCallbacks'),
895
+
896
+ start: function() {
897
+ this.RSVP.configure('instrument', true);
898
+ var self = this;
899
+
900
+ this.promiseChained = function(e) {
901
+ chain.call(self, e);
902
+ };
903
+ this.promiseRejected = function(e) {
904
+ reject.call(self, e);
905
+ };
906
+ this.promiseFulfilled = function(e) {
907
+ fulfill.call(self, e);
908
+ };
909
+ this.promiseCreated = function(e) {
910
+ create.bind(self)(e);
911
+ };
912
+
913
+
914
+ this.RSVP.on('chained', this.promiseChained);
915
+ this.RSVP.on('rejected', this.promiseRejected);
916
+ this.RSVP.on('fulfilled', this.promiseFulfilled);
917
+ this.RSVP.on('created', this.promiseCreated);
918
+
919
+ if (this.get('existingEvents')) {
920
+ var callbacks = this.get('existingCallbacks');
921
+ for (var eventName in callbacks) {
922
+ this.RSVP.off(eventName, callbacks[eventName]);
923
+ }
924
+ var events = Ember.A(this.get('existingEvents'));
925
+ events.forEach(function(e) {
926
+ self['promise' + Ember.String.capitalize(e.eventName)].call(self, e.options);
927
+ });
928
+ }
929
+ },
930
+
931
+ stop: function() {
932
+ this.RSVP.configure('instrument', false);
933
+ this.RSVP.off('chained', this.promiseChained);
934
+ this.RSVP.off('rejected', this.promiseRejected);
935
+ this.RSVP.off('fulfilled', this.promiseFulfilled);
936
+ this.RSVP.off('created', this.promiseCreated);
937
+
938
+ this.get('all').forEach(function(item) {
939
+ item.destroy();
940
+ });
941
+ this.set('all', Ember.A());
942
+ this.set('promiseIndex', {});
943
+
944
+ this.promiseChained = null;
945
+ this.promiseRejected = null;
946
+ this.promiseFulfilled = null;
947
+ this.promiseCreated = null;
948
+ },
949
+
950
+ willDestroy: function() {
951
+ this.stop();
952
+ this._super();
953
+ },
954
+
955
+ createPromise: function(props) {
956
+ var promise = Promise.create(props),
957
+ index = this.get('all.length');
958
+
959
+ this.get('all').pushObject(promise);
960
+ this.get('promiseIndex')[promise.get('guid')] = index;
961
+ return promise;
962
+ },
963
+
964
+ find: function(guid){
965
+ if (guid) {
966
+ var index = this.get('promiseIndex')[guid];
967
+ if (index !== undefined) {
968
+ return this.get('all').objectAt(index);
969
+ }
970
+ } else {
971
+ return this.get('all');
972
+ }
973
+ },
974
+
975
+ findOrCreate: function(guid) {
976
+ return this.find(guid) || this.createPromise({
977
+ guid: guid
978
+ });
979
+ },
980
+
981
+ updateOrCreate: function(guid, properties){
982
+ var entry = this.find(guid);
983
+ if (entry) {
984
+ entry.setProperties(properties);
985
+ } else {
986
+ properties = Ember.copy(properties);
987
+ properties.guid = guid;
988
+ entry = this.createPromise(properties);
989
+ }
990
+
991
+ return entry;
992
+ }
993
+ });
994
+
995
+ __exports__["default"] = PromiseAssembler;
996
+
997
+ PromiseAssembler.reopenClass({
998
+ supported: function() {
999
+ return !!Ember.RSVP.on;
1000
+ }
1001
+ });
1002
+
1003
+ var fulfill = function(event) {
1004
+ var guid = event.guid;
1005
+ var promise = this.updateOrCreate(guid, {
1006
+ label: event.label,
1007
+ settledAt: event.timeStamp,
1008
+ state: 'fulfilled',
1009
+ value: event.detail
1010
+ });
1011
+ this.trigger('fulfilled', {
1012
+ promise: promise
1013
+ });
1014
+ };
1015
+
1016
+
1017
+ var reject = function(event) {
1018
+ var guid = event.guid;
1019
+ var promise = this.updateOrCreate(guid, {
1020
+ label: event.label,
1021
+ settledAt: event.timeStamp,
1022
+ state: 'rejected',
1023
+ reason: event.detail
1024
+ });
1025
+ this.trigger('rejected', {
1026
+ promise: promise
1027
+ });
1028
+ };
1029
+
1030
+ function chain(event) {
1031
+ /*jshint validthis:true */
1032
+ var guid = event.guid,
1033
+ promise = this.updateOrCreate(guid, {
1034
+ label: event.label,
1035
+ chainedAt: event.timeStamp
1036
+ }),
1037
+ children = promise.get('children'),
1038
+ child = this.findOrCreate(event.childGuid);
1039
+
1040
+ child.set('parent', promise);
1041
+ children.pushObject(child);
1042
+
1043
+ this.trigger('chained', {
1044
+ promise: promise,
1045
+ child: child
1046
+ });
1047
+ }
1048
+
1049
+ function create(event) {
1050
+ /*jshint validthis:true */
1051
+ var guid = event.guid;
1052
+
1053
+ var promise = this.updateOrCreate(guid, {
1054
+ label: event.label,
1055
+ createdAt: event.timeStamp,
1056
+ stack: event.stack
1057
+ });
1058
+
1059
+ // todo fix ordering
1060
+ if (Ember.isNone(promise.get('state'))) {
1061
+ promise.set('state', 'created');
1062
+ }
1063
+ this.trigger('created', {
1064
+ promise: promise
1065
+ });
1066
+ }
1067
+ });
1068
+ define("mixins/port_mixin",
1069
+ ["exports"],
1070
+ function(__exports__) {
1071
+ "use strict";
1072
+ __exports__["default"] = Ember.Mixin.create({
1073
+ port: null,
1074
+ messages: {},
1075
+
1076
+ portNamespace: null,
1077
+
1078
+ init: function() {
1079
+ this.setupPortListeners();
1080
+ },
1081
+
1082
+ willDestroy: function() {
1083
+ this.removePortListeners();
1084
+ },
1085
+
1086
+ sendMessage: function(name, message) {
1087
+ this.get('port').send(this.messageName(name), message);
1088
+ },
1089
+
1090
+ setupPortListeners: function() {
1091
+ var port = this.get('port'),
1092
+ self = this,
1093
+ messages = this.get('messages');
1094
+
1095
+ for (var name in messages) {
1096
+ if(messages.hasOwnProperty(name)) {
1097
+ port.on(this.messageName(name), this, messages[name]);
1098
+ }
1099
+ }
1100
+ },
1101
+
1102
+ removePortListeners: function() {
1103
+ var port = this.get('port'),
1104
+ self = this,
1105
+ messages = this.get('messages');
1106
+
1107
+ for (var name in messages) {
1108
+ if(messages.hasOwnProperty(name)) {
1109
+ port.off(this.messageName(name), this, messages[name]);
1110
+ }
1111
+ }
1112
+ },
1113
+
1114
+ messageName: function(name) {
1115
+ var messageName = name;
1116
+ if (this.get('portNamespace')) {
1117
+ messageName = this.get('portNamespace') + ':' + messageName;
1118
+ }
1119
+ return messageName;
1120
+ }
1121
+ });
1122
+ });
1123
+ define("models/profile_manager",
1124
+ ["models/profile_node","exports"],
1125
+ function(__dependency1__, __exports__) {
1126
+ "use strict";
1127
+ var ProfileNode = __dependency1__["default"];
1128
+ var scheduleOnce = Ember.run.scheduleOnce;
1129
+
1130
+ /**
1131
+ * A class for keeping track of active rendering profiles as a list.
1132
+ */
1133
+ var ProfileManager = function() {
1134
+ this.profiles = [];
1135
+ this.current = null;
1136
+ this.currentSet = [];
1137
+ this._profilesAddedCallbacks = [];
1138
+ };
1139
+
1140
+ ProfileManager.prototype = {
1141
+ began: function(timestamp, payload, now) {
1142
+ this.current = new ProfileNode(timestamp, payload, this.current, now);
1143
+ return this.current;
1144
+ },
1145
+
1146
+ ended: function(timestamp, payload, profileNode) {
1147
+ if (payload.exception) { throw payload.exception; }
1148
+
1149
+ this.current = profileNode.parent;
1150
+ profileNode.finish(timestamp);
1151
+
1152
+ // Are we done profiling an entire tree?
1153
+ if (!this.current) {
1154
+ this.currentSet.push(profileNode);
1155
+ // If so, schedule an update of the profile list
1156
+ scheduleOnce('afterRender', this, this._profilesFinished);
1157
+ }
1158
+ },
1159
+
1160
+ clearProfiles: function() {
1161
+ this.profiles.length = 0;
1162
+ },
1163
+
1164
+ _profilesFinished: function() {
1165
+ var firstNode = this.currentSet[0],
1166
+ parentNode = new ProfileNode(firstNode.start, {template: 'View Rendering'});
1167
+
1168
+ parentNode.time = 0;
1169
+ this.currentSet.forEach(function(n) {
1170
+ parentNode.time += n.time;
1171
+ parentNode.children.push(n);
1172
+ });
1173
+ parentNode.calcDuration();
1174
+
1175
+ this.profiles.push(parentNode);
1176
+ this._triggerProfilesAdded([parentNode]);
1177
+ this.currentSet = [];
1178
+ },
1179
+
1180
+ _profilesAddedCallbacks: undefined, // set to array on init
1181
+
1182
+ onProfilesAdded: function(context, callback) {
1183
+ this._profilesAddedCallbacks.push({
1184
+ context: context,
1185
+ callback: callback
1186
+ });
1187
+ },
1188
+
1189
+ offProfilesAdded: function(context, callback) {
1190
+ var index = -1, item;
1191
+ for (var i = 0, l = this._profilesAddedCallbacks.length; i < l; i++) {
1192
+ item = this._profilesAddedCallbacks[i];
1193
+ if (item.context === context && item.callback === callback) {
1194
+ index = i;
1195
+ }
1196
+ }
1197
+ if (index > -1) {
1198
+ this._profilesAddedCallbacks.splice(index, 1);
1199
+ }
1200
+ },
1201
+
1202
+ _triggerProfilesAdded: function(profiles) {
1203
+ this._profilesAddedCallbacks.forEach(function(item) {
1204
+ item.callback.call(item.context, profiles);
1205
+ });
1206
+ }
1207
+ };
1208
+
1209
+ __exports__["default"] = ProfileManager;
1210
+ });
1211
+ define("models/profile_node",
1212
+ ["exports"],
1213
+ function(__exports__) {
1214
+ "use strict";
1215
+ /**
1216
+ A tree structure for assembling a list of render calls so they can be grouped and displayed nicely afterwards.
1217
+
1218
+ @class ProfileNode
1219
+ **/
1220
+ var get = Ember.get;
1221
+ var guidFor = Ember.guidFor;
1222
+
1223
+ var ProfileNode = function(start, payload, parent, now) {
1224
+ var name;
1225
+ this.start = start;
1226
+ this.timestamp = now || Date.now();
1227
+
1228
+ if (payload) {
1229
+ if (payload.template) {
1230
+ name = payload.template;
1231
+ } else if (payload.view) {
1232
+ var view = payload.view;
1233
+ name = get(view, 'instrumentDisplay') || get(view, '_debugContainerKey');
1234
+ if (name) {
1235
+ name = name.replace(/^view:/, '');
1236
+ }
1237
+ this.viewGuid = guidFor(view);
1238
+ }
1239
+
1240
+ if (!name && payload.object) {
1241
+ name = payload.object.toString().replace(/:?:ember\d+>$/, '').replace(/^</, '');
1242
+ if (!this.viewGuid) {
1243
+ var match = name.match(/:(ember\d+)>$/);
1244
+ if (match && match.length > 1) {
1245
+ this.viewGuid = match[1];
1246
+ }
1247
+ }
1248
+ }
1249
+ }
1250
+
1251
+ this.name = name || 'Unknown view';
1252
+
1253
+ if (parent) { this.parent = parent; }
1254
+ this.children = [];
1255
+ };
1256
+
1257
+ ProfileNode.prototype = {
1258
+ finish: function(timestamp) {
1259
+ this.time = (timestamp - this.start);
1260
+ this.calcDuration();
1261
+
1262
+ // Once we attach to our parent, we remove that reference
1263
+ // to avoid a graph cycle when serializing:
1264
+ if (this.parent) {
1265
+ this.parent.children.push(this);
1266
+ this.parent = null;
1267
+ }
1268
+ },
1269
+
1270
+ calcDuration: function() {
1271
+ this.duration = Math.round(this.time * 100) / 100;
1272
+ }
1273
+ };
1274
+
1275
+ __exports__["default"] = ProfileNode;
1276
+ });
1277
+ define("models/promise",
1278
+ ["exports"],
1279
+ function(__exports__) {
1280
+ "use strict";
1281
+ var dateComputed = function() {
1282
+ return Ember.computed(
1283
+ function(key, date) {
1284
+ if (date !== undefined) {
1285
+ if (date instanceof Date) {
1286
+ return date;
1287
+ } else if (typeof date === 'number' || typeof date === 'string') {
1288
+ return new Date(date);
1289
+ }
1290
+ }
1291
+ return null;
1292
+ }).property();
1293
+ };
1294
+
1295
+ __exports__["default"] = Ember.Object.extend({
1296
+ createdAt: dateComputed(),
1297
+ settledAt: dateComputed(),
1298
+ chainedAt: dateComputed(),
1299
+
1300
+ parent: null,
1301
+
1302
+ children: Ember.computed(function() {
1303
+ return Ember.A();
1304
+ }).property(),
1305
+
1306
+ level: Ember.computed(function() {
1307
+ var parent = this.get('parent');
1308
+ if (!parent) {
1309
+ return 0;
1310
+ }
1311
+ return parent.get('level') + 1;
1312
+ }).property('parent.level'),
1313
+
1314
+ isSettled: Ember.computed(function() {
1315
+ return this.get('isFulfilled') || this.get('isRejected');
1316
+ }).property('state'),
1317
+
1318
+ isFulfilled: Ember.computed(function() {
1319
+ return this.get('state') === 'fulfilled';
1320
+ }).property('state'),
1321
+
1322
+ isRejected: Ember.computed(function() {
1323
+ return this.get('state') === 'rejected';
1324
+ }).property('state')
1325
+
1326
+ });
1327
+ });
1328
+ define("object_inspector",
1329
+ ["mixins/port_mixin","exports"],
1330
+ function(__dependency1__, __exports__) {
1331
+ "use strict";
1332
+ var PortMixin = __dependency1__["default"];
1333
+ var EmberObject = Ember.Object;
1334
+ var typeOf = Ember.typeOf;
1335
+ var Descriptor = Ember.Descriptor;
1336
+ var emberInspect = Ember.inspect;
1337
+ var computed = Ember.computed;
1338
+ var oneWay = computed.oneWay;
1339
+ var ComputedProperty = Ember.ComputedProperty;
1340
+ var get = Ember.get;
1341
+ var set = Ember.set;
1342
+ var guidFor = Ember.guidFor;
1343
+ var emberMeta = Ember.meta;
1344
+ var isNone = Ember.isNone;
1345
+
1346
+ function inspectValue(value) {
1347
+ var string;
1348
+ if (value instanceof EmberObject) {
1349
+ return { type: "type-ember-object", inspect: value.toString() };
1350
+ } else if (isComputed(value)) {
1351
+ string = "<computed>";
1352
+ return { type: "type-descriptor", inspect: string, computed: true };
1353
+ } else if (value instanceof Descriptor) {
1354
+ return { type: "type-descriptor", inspect: value.toString(), computed: true };
1355
+ } else {
1356
+ return { type: "type-" + typeOf(value), inspect: inspect(value) };
1357
+ }
1358
+ }
1359
+
1360
+ function inspect(value) {
1361
+ if (typeof value === 'function') {
1362
+ return "function() { ... }";
1363
+ } else if (value instanceof EmberObject) {
1364
+ return value.toString();
1365
+ } else if (typeOf(value) === 'array') {
1366
+ if (value.length === 0) { return '[]'; }
1367
+ else if (value.length === 1) { return '[ ' + inspect(value[0]) + ' ]'; }
1368
+ else { return '[ ' + inspect(value[0]) + ', ... ]'; }
1369
+ } else if (value instanceof Error) {
1370
+ return 'Error: ' + value.message;
1371
+ } else if (value === null) {
1372
+ return 'null';
1373
+ } else if(typeOf(value) === 'date') {
1374
+ return value.toString();
1375
+ } else if (typeof value === 'object') {
1376
+ // `Ember.inspect` is able to handle this use case,
1377
+ // but it is very slow as it loops over all props,
1378
+ // so summarize to just first 2 props
1379
+ var ret = [], v, count = 0, broken = false;
1380
+ for (var key in value) {
1381
+ if (value.hasOwnProperty(key)) {
1382
+ if (count++ > 1) {
1383
+ broken = true;
1384
+ break;
1385
+ }
1386
+ v = value[key];
1387
+ if (v === 'toString') { continue; } // ignore useless items
1388
+ if (typeOf(v) === 'function') { v = "function() { ... }"; }
1389
+ if (typeOf(v) === 'array') { v = '[Array : ' + v.length + ']'; }
1390
+ if (typeOf(v) === 'object') { v = '[Object]'; }
1391
+ ret.push(key + ": " + v);
1392
+ }
1393
+ }
1394
+ var suffix = ' }';
1395
+ if (broken) {
1396
+ suffix = ' ...}';
1397
+ }
1398
+ return '{ ' + ret.join(', ') + suffix;
1399
+ } else {
1400
+ return emberInspect(value);
1401
+ }
1402
+ }
1403
+
1404
+ var ObjectInspector = EmberObject.extend(PortMixin, {
1405
+ namespace: null,
1406
+
1407
+ adapter: oneWay('namespace.adapter'),
1408
+
1409
+ port: oneWay('namespace.port'),
1410
+
1411
+ application: oneWay('namespace.application'),
1412
+
1413
+ init: function() {
1414
+ this._super();
1415
+ this.set('sentObjects', {});
1416
+ this.set('boundObservers', {});
1417
+ },
1418
+
1419
+ willDestroy: function() {
1420
+ this._super();
1421
+ for (var objectId in this.sentObjects) {
1422
+ this.releaseObject(objectId);
1423
+ }
1424
+ },
1425
+
1426
+ sentObjects: {},
1427
+
1428
+ boundObservers: {},
1429
+
1430
+ portNamespace: 'objectInspector',
1431
+
1432
+ messages: {
1433
+ digDeeper: function(message) {
1434
+ this.digIntoObject(message.objectId, message.property);
1435
+ },
1436
+ releaseObject: function(message) {
1437
+ this.releaseObject(message.objectId);
1438
+ },
1439
+ calculate: function(message) {
1440
+ var value;
1441
+ value = this.valueForObjectProperty(message.objectId, message.property, message.mixinIndex);
1442
+ this.sendMessage('updateProperty', value);
1443
+ message.computed = true;
1444
+ this.bindPropertyToDebugger(message);
1445
+ },
1446
+ saveProperty: function(message) {
1447
+ this.saveProperty(message.objectId, message.mixinIndex, message.property, message.value);
1448
+ },
1449
+ sendToConsole: function(message) {
1450
+ this.sendToConsole(message.objectId, message.property);
1451
+ },
1452
+ sendControllerToConsole: function(message) {
1453
+ var container = this.get('application.__container__');
1454
+ this.sendValueToConsole(container.lookup('controller:' + message.name));
1455
+ },
1456
+ sendRouteHandlerToConsole: function(message) {
1457
+ var container = this.get('application.__container__');
1458
+ this.sendValueToConsole(container.lookup('route:' + message.name));
1459
+ },
1460
+ inspectRoute: function(message) {
1461
+ var container = this.get('application.__container__');
1462
+ this.sendObject(container.lookup('router:main').router.getHandler(message.name));
1463
+ },
1464
+ inspectController: function(message) {
1465
+ var container = this.get('application.__container__');
1466
+ this.sendObject(container.lookup('controller:' + message.name));
1467
+ },
1468
+ inspectById: function(message) {
1469
+ var obj = this.sentObjects[message.objectId];
1470
+ this.sendObject(obj);
1471
+ },
1472
+ inspectByContainerLookup: function(message) {
1473
+ var container = this.get('application.__container__');
1474
+ this.sendObject(container.lookup(message.name));
1475
+ }
1476
+ },
1477
+
1478
+ canSend: function(val) {
1479
+ return (val instanceof EmberObject) || typeOf(val) === 'array';
1480
+ },
1481
+
1482
+ saveProperty: function(objectId, mixinIndex, prop, val) {
1483
+ var object = this.sentObjects[objectId];
1484
+ set(object, prop, val);
1485
+ },
1486
+
1487
+ sendToConsole: function(objectId, prop) {
1488
+ var object = this.sentObjects[objectId];
1489
+ var value;
1490
+
1491
+ if (isNone(prop)) {
1492
+ value = this.sentObjects[objectId];
1493
+ } else {
1494
+ value = get(object, prop);
1495
+ }
1496
+
1497
+ this.sendValueToConsole(value);
1498
+ },
1499
+
1500
+ sendValueToConsole: function(value) {
1501
+ window.$E = value;
1502
+ if (value instanceof Error) {
1503
+ value = value.stack;
1504
+ }
1505
+ this.get("adapter").log('Ember Inspector ($E): ', value);
1506
+ },
1507
+
1508
+ digIntoObject: function(objectId, property) {
1509
+ var parentObject = this.sentObjects[objectId],
1510
+ object = get(parentObject, property);
1511
+
1512
+ if (this.canSend(object)) {
1513
+ var details = this.mixinsForObject(object);
1514
+
1515
+ this.sendMessage('updateObject', {
1516
+ parentObject: objectId,
1517
+ property: property,
1518
+ objectId: details.objectId,
1519
+ name: object.toString(),
1520
+ details: details.mixins
1521
+ });
1522
+ }
1523
+ },
1524
+
1525
+ sendObject: function(object) {
1526
+ if (!this.canSend(object)) {
1527
+ throw new Error("Can't inspect " + object + ". Only Ember objects and arrays are supported.");
1528
+ }
1529
+ var details = this.mixinsForObject(object);
1530
+ this.sendMessage('updateObject', {
1531
+ objectId: details.objectId,
1532
+ name: object.toString(),
1533
+ details: details.mixins
1534
+ });
1535
+
1536
+ },
1537
+
1538
+
1539
+ retainObject: function(object) {
1540
+ var meta = emberMeta(object),
1541
+ guid = guidFor(object),
1542
+ self = this;
1543
+
1544
+ meta._debugReferences = meta._debugReferences || 0;
1545
+ meta._debugReferences++;
1546
+
1547
+ this.sentObjects[guid] = object;
1548
+
1549
+ if (meta._debugReferences === 1 && object.reopen) {
1550
+ // drop object on destruction
1551
+ var _oldWillDestroy = object._oldWillDestroy = object.willDestroy;
1552
+ object.reopen({
1553
+ willDestroy: function() {
1554
+ self.dropObject(guid);
1555
+ return _oldWillDestroy.apply(this, arguments);
1556
+ }
1557
+ });
1558
+ }
1559
+
1560
+ return guid;
1561
+ },
1562
+
1563
+ releaseObject: function(objectId) {
1564
+ var object = this.sentObjects[objectId];
1565
+ if(!object) {
1566
+ return;
1567
+ }
1568
+ var meta = emberMeta(object),
1569
+ guid = guidFor(object);
1570
+
1571
+ meta._debugReferences--;
1572
+
1573
+ if (meta._debugReferences === 0) {
1574
+ this.dropObject(guid);
1575
+ }
1576
+
1577
+ },
1578
+
1579
+ dropObject: function(objectId) {
1580
+ var object = this.sentObjects[objectId];
1581
+
1582
+ if (object.reopen) {
1583
+ object.reopen({ willDestroy: object._oldWillDestroy });
1584
+ delete object._oldWillDestroy;
1585
+ }
1586
+
1587
+ this.removeObservers(objectId);
1588
+ delete this.sentObjects[objectId];
1589
+
1590
+ this.sendMessage('droppedObject', { objectId: objectId });
1591
+ },
1592
+
1593
+ removeObservers: function(objectId) {
1594
+ var observers = this.boundObservers[objectId],
1595
+ object = this.sentObjects[objectId];
1596
+
1597
+ if (observers) {
1598
+ observers.forEach(function(observer) {
1599
+ Ember.removeObserver(object, observer.property, observer.handler);
1600
+ });
1601
+ }
1602
+
1603
+ delete this.boundObservers[objectId];
1604
+ },
1605
+
1606
+ mixinsForObject: function(object) {
1607
+ var mixins = Ember.Mixin.mixins(object),
1608
+ mixinDetails = [],
1609
+ self = this;
1610
+
1611
+ var ownProps = propertiesForMixin({ mixins: [{ properties: object }] });
1612
+ mixinDetails.push({ name: "Own Properties", properties: ownProps, expand: true });
1613
+
1614
+ mixins.forEach(function(mixin) {
1615
+ var name = mixin[Ember.NAME_KEY] || mixin.ownerConstructor;
1616
+ if (!name) {
1617
+ name = 'Unknown mixin';
1618
+ }
1619
+ mixinDetails.push({ name: name.toString(), properties: propertiesForMixin(mixin) });
1620
+ });
1621
+
1622
+ fixMandatorySetters(mixinDetails);
1623
+ applyMixinOverrides(mixinDetails);
1624
+
1625
+ var propertyInfo = null;
1626
+ var debugInfo = getDebugInfo(object);
1627
+ if (debugInfo) {
1628
+ propertyInfo = getDebugInfo(object).propertyInfo;
1629
+ mixinDetails = customizeProperties(mixinDetails, propertyInfo);
1630
+ }
1631
+
1632
+ var expensiveProperties = null;
1633
+ if (propertyInfo) {
1634
+ expensiveProperties = propertyInfo.expensiveProperties;
1635
+ }
1636
+ calculateCPs(object, mixinDetails, expensiveProperties);
1637
+
1638
+ var objectId = this.retainObject(object);
1639
+
1640
+ this.bindProperties(objectId, mixinDetails);
1641
+
1642
+ return { objectId: objectId, mixins: mixinDetails };
1643
+ },
1644
+
1645
+ valueForObjectProperty: function(objectId, property, mixinIndex) {
1646
+ var object = this.sentObjects[objectId], value;
1647
+
1648
+ if (object.isDestroying) {
1649
+ value = '<DESTROYED>';
1650
+ } else {
1651
+ value = object.get(property);
1652
+ }
1653
+
1654
+ value = inspectValue(value);
1655
+ value.computed = true;
1656
+
1657
+ return {
1658
+ objectId: objectId,
1659
+ property: property,
1660
+ value: value,
1661
+ mixinIndex: mixinIndex
1662
+ };
1663
+ },
1664
+
1665
+ bindPropertyToDebugger: function(message) {
1666
+ var objectId = message.objectId,
1667
+ property = message.property,
1668
+ mixinIndex = message.mixinIndex,
1669
+ computed = message.computed,
1670
+ self = this;
1671
+
1672
+ var object = this.sentObjects[objectId];
1673
+
1674
+ function handler() {
1675
+ var value = get(object, property);
1676
+ value = inspectValue(value);
1677
+ value.computed = computed;
1678
+
1679
+ self.sendMessage('updateProperty', {
1680
+ objectId: objectId,
1681
+ property: property,
1682
+ value: value,
1683
+ mixinIndex: mixinIndex
1684
+ });
1685
+ }
1686
+
1687
+ Ember.addObserver(object, property, handler);
1688
+ this.boundObservers[objectId] = this.boundObservers[objectId] || [];
1689
+ this.boundObservers[objectId].push({ property: property, handler: handler });
1690
+
1691
+ },
1692
+
1693
+ bindProperties: function(objectId, mixinDetails) {
1694
+ var self = this;
1695
+ mixinDetails.forEach(function(mixin, mixinIndex) {
1696
+ mixin.properties.forEach(function(item) {
1697
+ if (item.overridden) {
1698
+ return true;
1699
+ }
1700
+ if (item.value.type !== 'type-descriptor' && item.value.type !== 'type-function') {
1701
+ var computed = !!item.value.computed;
1702
+ self.bindPropertyToDebugger({
1703
+ objectId: objectId,
1704
+ property: item.name,
1705
+ mixinIndex: mixinIndex,
1706
+ computed: computed
1707
+ });
1708
+ }
1709
+ });
1710
+ });
1711
+ },
1712
+
1713
+ inspect: inspect,
1714
+ inspectValue: inspectValue
1715
+ });
1716
+
1717
+
1718
+ function propertiesForMixin(mixin) {
1719
+ var seen = {}, properties = [];
1720
+
1721
+ mixin.mixins.forEach(function(mixin) {
1722
+ if (mixin.properties) {
1723
+ addProperties(properties, mixin.properties);
1724
+ }
1725
+ });
1726
+
1727
+ return properties;
1728
+ }
1729
+
1730
+ function addProperties(properties, hash) {
1731
+ for (var prop in hash) {
1732
+ if (!hash.hasOwnProperty(prop)) { continue; }
1733
+ if (prop.charAt(0) === '_') { continue; }
1734
+
1735
+ // remove `fooBinding` type props
1736
+ if (prop.match(/Binding$/)) { continue; }
1737
+
1738
+ // when mandatory setter is removed, an `undefined` value may be set
1739
+ if (hash[prop] === undefined) { continue; }
1740
+ var options = { isMandatorySetter: isMandatorySetter(hash, prop) };
1741
+ if (isComputed(hash[prop])) {
1742
+ options.readOnly = hash[prop]._readOnly;
1743
+ }
1744
+ replaceProperty(properties, prop, hash[prop], options);
1745
+ }
1746
+ }
1747
+
1748
+ function replaceProperty(properties, name, value, options) {
1749
+ var found, type;
1750
+
1751
+ for (var i=0, l=properties.length; i<l; i++) {
1752
+ if (properties[i].name === name) {
1753
+ found = i;
1754
+ break;
1755
+ }
1756
+ }
1757
+
1758
+ if (found) { properties.splice(i, 1); }
1759
+
1760
+ if (name) {
1761
+ type = name.PrototypeMixin ? 'ember-class' : 'ember-mixin';
1762
+ }
1763
+ var prop = { name: name, value: inspectValue(value) };
1764
+ prop.isMandatorySetter = options.isMandatorySetter;
1765
+ prop.readOnly = options.readOnly;
1766
+ properties.push(prop);
1767
+ }
1768
+
1769
+ function fixMandatorySetters(mixinDetails) {
1770
+ var seen = {};
1771
+ var propertiesToRemove = [];
1772
+
1773
+ mixinDetails.forEach(function(detail, detailIdx) {
1774
+ detail.properties.forEach(function(property, propertyIdx) {
1775
+ if(property.isMandatorySetter) {
1776
+ seen[property.name] = {
1777
+ name: property.name,
1778
+ value: property.value.inspect,
1779
+ detailIdx: detailIdx,
1780
+ property: property
1781
+ };
1782
+ } else if(seen.hasOwnProperty(property.name) && seen[property.name] === property.value.inspect) {
1783
+ propertiesToRemove.push(seen[property.name]);
1784
+ delete seen[property.name];
1785
+ }
1786
+ });
1787
+ });
1788
+
1789
+ propertiesToRemove.forEach(function(prop) {
1790
+ var detail = mixinDetails[prop.detailIdx];
1791
+ var index = detail.properties.indexOf(prop.property);
1792
+ if (index !== -1) {
1793
+ detail.properties.splice(index, 1);
1794
+ }
1795
+ });
1796
+
1797
+ }
1798
+
1799
+ function applyMixinOverrides(mixinDetails) {
1800
+ var seen = {};
1801
+ mixinDetails.forEach(function(detail) {
1802
+ detail.properties.forEach(function(property) {
1803
+ if (Object.prototype.hasOwnProperty(property.name)) { return; }
1804
+
1805
+ if (seen[property.name]) {
1806
+ property.overridden = seen[property.name];
1807
+ delete property.value.computed;
1808
+ }
1809
+
1810
+ seen[property.name] = detail.name;
1811
+
1812
+ });
1813
+ });
1814
+ }
1815
+
1816
+ function isMandatorySetter(object, prop) {
1817
+ var descriptor = Object.getOwnPropertyDescriptor(object, prop);
1818
+ if (descriptor.set && descriptor.set === Ember.MANDATORY_SETTER_FUNCTION) {
1819
+ return true;
1820
+ }
1821
+ return false;
1822
+ }
1823
+
1824
+
1825
+
1826
+
1827
+
1828
+
1829
+ function calculateCPs(object, mixinDetails, expensiveProperties) {
1830
+ expensiveProperties = expensiveProperties || [];
1831
+
1832
+ mixinDetails.forEach(function(mixin) {
1833
+ mixin.properties.forEach(function(item) {
1834
+ if (item.overridden) {
1835
+ return true;
1836
+ }
1837
+ if (item.value.computed) {
1838
+ var cache = Ember.cacheFor(object, item.name);
1839
+ if (cache !== undefined || expensiveProperties.indexOf(item.name) === -1) {
1840
+ item.value = inspectValue(get(object, item.name));
1841
+ item.value.computed = true;
1842
+ }
1843
+ }
1844
+ });
1845
+ });
1846
+ }
1847
+
1848
+ /**
1849
+ Customizes an object's properties
1850
+ based on the property `propertyInfo` of
1851
+ the object's `_debugInfo` method.
1852
+
1853
+ Possible options:
1854
+ - `groups` An array of groups that contains the properties for each group
1855
+ For example:
1856
+ ```javascript
1857
+ groups: [
1858
+ { name: 'Attributes', properties: ['firstName', 'lastName'] },
1859
+ { name: 'Belongs To', properties: ['country'] }
1860
+ ]
1861
+ ```
1862
+ - `includeOtherProperties` Boolean,
1863
+ - `true` to include other non-listed properties,
1864
+ - `false` to only include given properties
1865
+ - `skipProperties` Array containing list of properties *not* to include
1866
+ - `skipMixins` Array containing list of mixins *not* to include
1867
+ - `expensiveProperties` An array of computed properties that are too expensive.
1868
+ Adding a property to this array makes sure the CP is not calculated automatically.
1869
+
1870
+ Example:
1871
+ ```javascript
1872
+ {
1873
+ propertyInfo: {
1874
+ includeOtherProperties: true,
1875
+ skipProperties: ['toString', 'send', 'withTransaction'],
1876
+ skipMixins: [ 'Ember.Evented'],
1877
+ calculate: ['firstName', 'lastName'],
1878
+ groups: [
1879
+ {
1880
+ name: 'Attributes',
1881
+ properties: [ 'id', 'firstName', 'lastName' ],
1882
+ expand: true // open by default
1883
+ },
1884
+ {
1885
+ name: 'Belongs To',
1886
+ properties: [ 'maritalStatus', 'avatar' ],
1887
+ expand: true
1888
+ },
1889
+ {
1890
+ name: 'Has Many',
1891
+ properties: [ 'phoneNumbers' ],
1892
+ expand: true
1893
+ },
1894
+ {
1895
+ name: 'Flags',
1896
+ properties: ['isLoaded', 'isLoading', 'isNew', 'isDirty']
1897
+ }
1898
+ ]
1899
+ }
1900
+ }
1901
+ ```
1902
+ */
1903
+ function customizeProperties(mixinDetails, propertyInfo) {
1904
+ var newMixinDetails = [],
1905
+ neededProperties = {},
1906
+ groups = propertyInfo.groups || [],
1907
+ skipProperties = propertyInfo.skipProperties || [],
1908
+ skipMixins = propertyInfo.skipMixins || [];
1909
+
1910
+ if(groups.length) {
1911
+ mixinDetails[0].expand = false;
1912
+ }
1913
+
1914
+ groups.forEach(function(group) {
1915
+ group.properties.forEach(function(prop) {
1916
+ neededProperties[prop] = true;
1917
+ });
1918
+ });
1919
+
1920
+ mixinDetails.forEach(function(mixin) {
1921
+ var newProperties = [];
1922
+ mixin.properties.forEach(function(item) {
1923
+ if (skipProperties.indexOf(item.name) !== -1) {
1924
+ return true;
1925
+ }
1926
+ if (!item.overridden && neededProperties.hasOwnProperty(item.name) && neededProperties[item.name]) {
1927
+ neededProperties[item.name] = item;
1928
+ } else {
1929
+ newProperties.push(item);
1930
+ }
1931
+ });
1932
+ mixin.properties = newProperties;
1933
+ if (skipMixins.indexOf(mixin.name) === -1) {
1934
+ newMixinDetails.push(mixin);
1935
+ }
1936
+ });
1937
+
1938
+ groups.slice().reverse().forEach(function(group) {
1939
+ var newMixin = { name: group.name, expand: group.expand, properties: [] };
1940
+ group.properties.forEach(function(prop) {
1941
+ // make sure it's not `true` which means property wasn't found
1942
+ if (neededProperties[prop] !== true) {
1943
+ newMixin.properties.push(neededProperties[prop]);
1944
+ }
1945
+ });
1946
+ newMixinDetails.unshift(newMixin);
1947
+ });
1948
+
1949
+ return newMixinDetails;
1950
+ }
1951
+
1952
+
1953
+ function getDebugInfo(object) {
1954
+ var debugInfo = null;
1955
+ if (object._debugInfo && typeof object._debugInfo === 'function') {
1956
+ debugInfo = object._debugInfo();
1957
+ }
1958
+ debugInfo = debugInfo || {};
1959
+ var propertyInfo = debugInfo.propertyInfo || (debugInfo.propertyInfo = {});
1960
+ var skipProperties = propertyInfo.skipProperties = propertyInfo.skipProperties || (propertyInfo.skipProperties = []);
1961
+
1962
+ skipProperties.push('isDestroyed', 'isDestroying', 'container');
1963
+ // 'currentState' and 'state' are un-observable private properties.
1964
+ // The rest are skipped to reduce noise in the inspector.
1965
+ if (object instanceof Ember.View) {
1966
+ skipProperties.push(
1967
+ 'currentState',
1968
+ 'state',
1969
+ 'buffer',
1970
+ 'outletSource',
1971
+ 'lengthBeforeRender',
1972
+ 'lengthAfterRender',
1973
+ 'template',
1974
+ 'layout',
1975
+ 'templateData',
1976
+ 'domManager',
1977
+ 'states'
1978
+ );
1979
+ }
1980
+
1981
+
1982
+ for (var prop in object) {
1983
+ // remove methods
1984
+ if (typeof object[prop] === 'function') {
1985
+ skipProperties.push(prop);
1986
+ }
1987
+
1988
+ }
1989
+ return debugInfo;
1990
+ }
1991
+
1992
+ function isComputed(value) {
1993
+ return value instanceof ComputedProperty;
1994
+ }
1995
+
1996
+ // Not used
1997
+ function inspectController(controller) {
1998
+ return controller.get('_debugContainerKey') || controller.toString();
1999
+ }
2000
+
2001
+ __exports__["default"] = ObjectInspector;
2002
+ });
2003
+ define("port",
2004
+ ["exports"],
2005
+ function(__exports__) {
2006
+ "use strict";
2007
+ var oneWay = Ember.computed.oneWay;
2008
+ var guidFor = Ember.guidFor;
2009
+
2010
+ __exports__["default"] = Ember.Object.extend(Ember.Evented, {
2011
+ adapter: oneWay('namespace.adapter').readOnly(),
2012
+
2013
+ application: oneWay('namespace.application').readOnly(),
2014
+
2015
+ uniqueId: Ember.computed(function() {
2016
+ return guidFor(this.get('application')) + '__' + window.location.href + '__' + Date.now();
2017
+ }).property(),
2018
+
2019
+ init: function() {
2020
+ var self = this;
2021
+ this.get('adapter').onMessageReceived(function(message) {
2022
+ if(self.get('uniqueId') === message.applicationId || !message.applicationId) {
2023
+ self.trigger(message.type, message);
2024
+ }
2025
+ });
2026
+ },
2027
+ send: function(messageType, options) {
2028
+ options.type = messageType;
2029
+ options.from = 'inspectedWindow';
2030
+ options.applicationId = this.get('uniqueId');
2031
+ this.get('adapter').sendMessage(options);
2032
+ }
2033
+ });
2034
+ });
2035
+ define("promise_debug",
2036
+ ["mixins/port_mixin","libs/promise_assembler","exports"],
2037
+ function(__dependency1__, __dependency2__, __exports__) {
2038
+ "use strict";
2039
+ var PortMixin = __dependency1__["default"];
2040
+ var PromiseAssembler = __dependency2__["default"];
2041
+
2042
+ var PromiseDebug = Ember.Object.extend(PortMixin, {
2043
+ namespace: null,
2044
+ port: Ember.computed.alias('namespace.port'),
2045
+ objectInspector: Ember.computed.alias('namespace.objectInspector'),
2046
+ adapter: Ember.computed.alias('namespace.adapter'),
2047
+ portNamespace: 'promise',
2048
+
2049
+
2050
+ existingEvents: Ember.computed.alias('namespace.existingEvents'),
2051
+ existingCallbacks: Ember.computed.alias('namespace.existingCallbacks'),
2052
+
2053
+ // created on init
2054
+ promiseAssembler: null,
2055
+
2056
+ releaseMethods: Ember.computed(function() { return Ember.A(); }),
2057
+
2058
+ init: function() {
2059
+ this._super();
2060
+ if (PromiseAssembler.supported()) {
2061
+ this.set('promiseAssembler', PromiseAssembler.create());
2062
+ this.get('promiseAssembler').set('promiseDebug', this);
2063
+ this.get('promiseAssembler').start();
2064
+ }
2065
+ },
2066
+
2067
+ delay: 100,
2068
+
2069
+ willDestroy: function() {
2070
+ this.releaseAll();
2071
+ this.get('promiseAssembler').destroy();
2072
+ this.set('promiseAssembler', null);
2073
+ this._super();
2074
+ },
2075
+
2076
+ messages: {
2077
+ getAndObservePromises: function() {
2078
+ this.getAndObservePromises();
2079
+ },
2080
+
2081
+ supported: function() {
2082
+ this.sendMessage('supported', {
2083
+ supported: PromiseAssembler.supported()
2084
+ });
2085
+ },
2086
+
2087
+ releasePromises: function() {
2088
+ this.releaseAll();
2089
+ },
2090
+
2091
+ sendValueToConsole: function(message) {
2092
+ var promiseId = message.promiseId;
2093
+ var promise = this.get('promiseAssembler').find(promiseId);
2094
+ var value = promise.get('value');
2095
+ if (value === undefined) {
2096
+ value = promise.get('reason');
2097
+ }
2098
+ this.get('objectInspector').sendValueToConsole(value);
2099
+ },
2100
+
2101
+ tracePromise: function(message) {
2102
+ var id = message.promiseId;
2103
+ var promise = this.get('promiseAssembler').find(id);
2104
+ // Remove first two lines and add label
2105
+ var stack = promise.get('stack');
2106
+ if (stack) {
2107
+ stack = stack.split("\n");
2108
+ stack.splice(0, 2, ['Ember Inspector (Promise Trace): ' + (promise.get('label') || '')]);
2109
+ this.get("adapter").log(stack.join("\n"));
2110
+ }
2111
+ },
2112
+
2113
+ setInstrumentWithStack: function(message) {
2114
+ Ember.RSVP.configure('instrument-with-stack', message.instrumentWithStack);
2115
+ }
2116
+ },
2117
+
2118
+ releaseAll: function() {
2119
+ this.get('releaseMethods').forEach(function(fn) {
2120
+ fn();
2121
+ });
2122
+ this.set('releaseMethods', Ember.A());
2123
+ },
2124
+
2125
+ getAndObservePromises: function() {
2126
+ this.get('promiseAssembler').on('created', this, this.promiseUpdated);
2127
+ this.get('promiseAssembler').on('fulfilled', this, this.promiseUpdated);
2128
+ this.get('promiseAssembler').on('rejected', this, this.promiseUpdated);
2129
+ this.get('promiseAssembler').on('chained', this, this.promiseChained);
2130
+
2131
+ this.get('releaseMethods').pushObject(function() {
2132
+
2133
+ this.get('promiseAssembler').off('created', this, this.promiseUpdated);
2134
+ this.get('promiseAssembler').off('fulfilled', this, this.promiseUpdated);
2135
+ this.get('promiseAssembler').off('rejected', this, this.promiseUpdated);
2136
+ this.get('promiseAssembler').off('fulfilled', this, this.promiseChained);
2137
+
2138
+ }.bind(this));
2139
+
2140
+ this.promisesUpdated(this.get('promiseAssembler').find());
2141
+ },
2142
+
2143
+ updatedPromises: Ember.computed(function() { return Ember.A(); }),
2144
+
2145
+ promisesUpdated: function(uniquePromises) {
2146
+ if (!uniquePromises) {
2147
+ uniquePromises = Ember.A();
2148
+ this.get('updatedPromises').forEach(function(promise) {
2149
+ uniquePromises.addObject(promise);
2150
+ });
2151
+ }
2152
+ var serialized = this.serializeArray(uniquePromises);
2153
+ this.sendMessage('promisesUpdated', {
2154
+ promises: serialized
2155
+ });
2156
+ this.set('updatedPromises', Ember.A());
2157
+ },
2158
+
2159
+ promiseUpdated: function(event) {
2160
+ this.get('updatedPromises').pushObject(event.promise);
2161
+ Ember.run.debounce(this, 'promisesUpdated', this.delay);
2162
+ },
2163
+
2164
+ promiseChained: function(event) {
2165
+ this.get('updatedPromises').pushObject(event.promise);
2166
+ this.get('updatedPromises').pushObject(event.child);
2167
+ Ember.run.debounce(this, 'promisesUpdated', this.delay);
2168
+ },
2169
+
2170
+ serializeArray: function(promises) {
2171
+ return promises.map(function(item) {
2172
+ return this.serialize(item);
2173
+ }.bind(this));
2174
+ },
2175
+
2176
+ serialize: function(promise) {
2177
+ var serialized = {};
2178
+ serialized.guid = promise.get('guid');
2179
+ serialized.state = promise.get('state');
2180
+ serialized.label = promise.get('label');
2181
+ if (promise.get('children')) {
2182
+ serialized.children = this.promiseIds(promise.get('children'));
2183
+ }
2184
+ serialized.parent = promise.get('parent.guid');
2185
+ serialized.value = this.inspectValue(promise.get('value'));
2186
+ serialized.reason = this.inspectValue(promise.get('reason'));
2187
+ if (promise.get('createdAt')) {
2188
+ serialized.createdAt = promise.get('createdAt').getTime();
2189
+ }
2190
+ if (promise.get('settledAt')) {
2191
+ serialized.settledAt = promise.get('settledAt').getTime();
2192
+ }
2193
+ serialized.hasStack = !!promise.get('stack');
2194
+ return serialized;
2195
+ },
2196
+
2197
+ promiseIds: function(promises) {
2198
+ return promises.map(function(promise) {
2199
+ return promise.get('guid');
2200
+ });
2201
+ },
2202
+
2203
+ inspectValue: function(value) {
2204
+ var objectInspector = this.get('objectInspector'),
2205
+ inspected = objectInspector.inspectValue(value);
2206
+
2207
+ if (inspected.type === 'type-ember-object' || inspected.type === "type-array") {
2208
+ inspected.objectId = objectInspector.retainObject(value);
2209
+ this.get('releaseMethods').pushObject(function() {
2210
+ objectInspector.releaseObject(inspected.objectId);
2211
+ });
2212
+ }
2213
+ return inspected;
2214
+ }
2215
+
2216
+ });
2217
+
2218
+ __exports__["default"] = PromiseDebug;
2219
+ });
2220
+ define("render_debug",
2221
+ ["mixins/port_mixin","models/profile_manager","exports"],
2222
+ function(__dependency1__, __dependency2__, __exports__) {
2223
+ "use strict";
2224
+ var PortMixin = __dependency1__["default"];
2225
+ var ProfileManager = __dependency2__["default"];
2226
+
2227
+ var K = Ember.K;
2228
+ var addArrayObserver = Ember.addArrayObserver;
2229
+ var computed = Ember.computed;
2230
+ var oneWay = computed.oneWay;
2231
+ var later = Ember.run.later;
2232
+
2233
+ var profileManager = new ProfileManager();
2234
+
2235
+ var queue = [];
2236
+
2237
+ function push(info) {
2238
+ var index = queue.push(info);
2239
+ if (1 === index) {
2240
+ later(flush, 50);
2241
+ }
2242
+ return index - 1;
2243
+ }
2244
+
2245
+ function flush() {
2246
+ var entry, ended, i;
2247
+ for (i = 0; i < queue.length; i++) {
2248
+ entry = queue[i];
2249
+ if (entry.type === 'began') {
2250
+ queue[entry.endedIndex].profileNode = profileManager.began(entry.timestamp, entry.payload, entry.now);
2251
+ } else {
2252
+ profileManager.ended(entry.timestamp, entry.payload, entry.profileNode);
2253
+ }
2254
+
2255
+ }
2256
+ queue.length = 0;
2257
+ }
2258
+
2259
+ Ember.subscribe("render", {
2260
+ before: function(name, timestamp, payload) {
2261
+ var info = {
2262
+ type: 'began',
2263
+ timestamp: timestamp,
2264
+ payload: payload,
2265
+ now: Date.now()
2266
+ };
2267
+ return push(info);
2268
+ },
2269
+
2270
+ after: function(name, timestamp, payload, beganIndex) {
2271
+ var endedInfo = {
2272
+ type: 'ended',
2273
+ timestamp: timestamp,
2274
+ payload: payload
2275
+ };
2276
+
2277
+ var index = push(endedInfo);
2278
+ queue[beganIndex].endedIndex = index;
2279
+ }
2280
+ });
2281
+
2282
+ __exports__["default"] = Ember.Object.extend(PortMixin, {
2283
+ namespace: null,
2284
+ port: oneWay('namespace.port').readOnly(),
2285
+ application: oneWay('namespace.application').readOnly(),
2286
+ viewDebug: oneWay('namespace.viewDebug').readOnly(),
2287
+ portNamespace: 'render',
2288
+
2289
+ profileManager: profileManager,
2290
+
2291
+ init: function() {
2292
+ this._super();
2293
+ this._subscribeForViewTrees();
2294
+ },
2295
+
2296
+ willDestroy: function() {
2297
+ this._super();
2298
+ this.profileManager.offProfilesAdded(this, this.sendAdded);
2299
+ this.profileManager.offProfilesAdded(this, this._updateViewTree);
2300
+ },
2301
+
2302
+ _subscribeForViewTrees: function() {
2303
+ this.profileManager.onProfilesAdded(this, this._updateViewTree);
2304
+ },
2305
+
2306
+ _updateViewTree: function(profiles) {
2307
+ var viewDurations = {};
2308
+ this._flatten(profiles).forEach(function(node) {
2309
+ if (node.viewGuid) {
2310
+ viewDurations[node.viewGuid] = node.duration;
2311
+ }
2312
+ });
2313
+ this.get('viewDebug').updateDurations(viewDurations);
2314
+ },
2315
+
2316
+ _flatten: function(profiles, array) {
2317
+ var self = this;
2318
+ array = array || [];
2319
+ profiles.forEach(function(profile) {
2320
+ array.push(profile);
2321
+ self._flatten(profile.children, array);
2322
+ });
2323
+ return array;
2324
+ },
2325
+
2326
+ sendAdded: function(profiles) {
2327
+ this.sendMessage('profilesAdded', { profiles: profiles });
2328
+ },
2329
+
2330
+ messages: {
2331
+ watchProfiles: function() {
2332
+ this.sendMessage('profilesAdded', { profiles: this.profileManager.profiles });
2333
+ this.profileManager.onProfilesAdded(this, this.sendAdded);
2334
+ },
2335
+
2336
+ releaseProfiles: function() {
2337
+ this.profileManager.offProfilesAdded(this, this.sendAdded);
2338
+ },
2339
+
2340
+ clear: function() {
2341
+ this.profileManager.clearProfiles();
2342
+ this.sendMessage('profilesUpdated', {profiles: []});
2343
+ }
2344
+ }
2345
+ });
2346
+ });
2347
+ define("route_debug",
2348
+ ["mixins/port_mixin","exports"],
2349
+ function(__dependency1__, __exports__) {
2350
+ "use strict";
2351
+ var PortMixin = __dependency1__["default"];
2352
+
2353
+ var classify = Ember.String.classify;
2354
+ var computed = Ember.computed;
2355
+ var oneWay = computed.oneWay;
2356
+ var observer = Ember.observer;
2357
+ var later = Ember.run.later;
2358
+
2359
+ var RouteDebug = Ember.Object.extend(PortMixin, {
2360
+ namespace: null,
2361
+ port: oneWay('namespace.port').readOnly(),
2362
+
2363
+ application: oneWay('namespace.application').readOnly(),
2364
+
2365
+ router: computed(function() {
2366
+ return this.get('application.__container__').lookup('router:main');
2367
+ }).property('application'),
2368
+
2369
+ applicationController: computed(function() {
2370
+ var container = this.get('application.__container__');
2371
+ return container.lookup('controller:application');
2372
+ }).property('application'),
2373
+
2374
+ currentPath: oneWay('applicationController.currentPath').readOnly(),
2375
+
2376
+ portNamespace: 'route',
2377
+
2378
+ messages: {
2379
+ getTree: function() {
2380
+ this.sendTree();
2381
+ },
2382
+ getCurrentRoute: function() {
2383
+ this.sendCurrentRoute();
2384
+ }
2385
+ },
2386
+
2387
+ sendCurrentRoute: observer(function() {
2388
+ var self = this;
2389
+ later(function() {
2390
+ self.sendMessage('currentRoute', { name: self.get('currentPath') });
2391
+ }, 50);
2392
+ }, 'currentPath'),
2393
+
2394
+ routeTree: computed(function() {
2395
+ var routeNames = this.get('router.router.recognizer.names');
2396
+ var routeTree = {};
2397
+
2398
+ for(var routeName in routeNames) {
2399
+ if (!routeNames.hasOwnProperty(routeName)) {
2400
+ continue;
2401
+ }
2402
+ var route = routeNames[routeName];
2403
+ var handlers = Ember.A(route.handlers);
2404
+ buildSubTree.call(this, routeTree, route);
2405
+ }
2406
+
2407
+ return arrayizeChildren({ children: routeTree }).children[0];
2408
+ }).property('router'),
2409
+
2410
+ sendTree: function() {
2411
+ var routeTree = this.get('routeTree');
2412
+ this.sendMessage('routeTree', { tree: routeTree });
2413
+ }
2414
+ });
2415
+
2416
+ var buildSubTree = function(routeTree, route) {
2417
+ var handlers = route.handlers;
2418
+ var subTree = routeTree, item,
2419
+ routeClassName, routeHandler, controllerName,
2420
+ controllerClassName, container, templateName,
2421
+ controllerFactory;
2422
+ for (var i = 0; i < handlers.length; i++) {
2423
+ item = handlers[i];
2424
+ var handler = item.handler;
2425
+ if (subTree[handler] === undefined) {
2426
+ routeClassName = classify(handler.replace(/\./g, '_')) + 'Route';
2427
+ container = this.get('application.__container__');
2428
+ routeHandler = container.lookup('router:main').router.getHandler(handler);
2429
+ controllerName = routeHandler.get('controllerName') || routeHandler.get('routeName');
2430
+ controllerClassName = classify(controllerName.replace(/\./g, '_')) + 'Controller';
2431
+ controllerFactory = container.lookupFactory('controller:' + controllerName);
2432
+ templateName = handler.replace(/\./g, '/');
2433
+
2434
+ subTree[handler] = {
2435
+ value: {
2436
+ name: handler,
2437
+ routeHandler: {
2438
+ className: routeClassName,
2439
+ name: handler
2440
+ },
2441
+ controller: {
2442
+ className: controllerClassName,
2443
+ name: controllerName,
2444
+ exists: controllerFactory ? true : false
2445
+ },
2446
+ template: {
2447
+ name: templateName
2448
+ }
2449
+ }
2450
+ };
2451
+
2452
+ if (i === handlers.length - 1) {
2453
+ // it is a route, get url
2454
+ subTree[handler].value.url = getURL(container, route.segments);
2455
+ subTree[handler].value.type = 'route';
2456
+ } else {
2457
+ // it is a resource, set children object
2458
+ subTree[handler].children = {};
2459
+ subTree[handler].value.type = 'resource';
2460
+ }
2461
+
2462
+ }
2463
+ subTree = subTree[handler].children;
2464
+ }
2465
+ };
2466
+
2467
+ function arrayizeChildren(routeTree) {
2468
+ var obj = { value: routeTree.value };
2469
+
2470
+ if (routeTree.children) {
2471
+ var childrenArray = [];
2472
+ for(var i in routeTree.children) {
2473
+ var route = routeTree.children[i];
2474
+ childrenArray.push(arrayizeChildren(route));
2475
+ }
2476
+ obj.children = childrenArray;
2477
+ }
2478
+
2479
+ return obj;
2480
+ }
2481
+
2482
+ function getURL(container, segments) {
2483
+ var locationImplementation = container.lookup('router:main').location;
2484
+ var url = [];
2485
+ for (var i = 0; i < segments.length; i++) {
2486
+ var name = null;
2487
+
2488
+ try {
2489
+ name = segments[i].generate();
2490
+ } catch (e) {
2491
+ // is dynamic
2492
+ name = ':' + segments[i].name;
2493
+ }
2494
+ if (name) {
2495
+ url.push(name);
2496
+ }
2497
+ }
2498
+
2499
+ url = url.join('/');
2500
+
2501
+ if (url.match(/_unused_dummy_/)) {
2502
+ url = '';
2503
+ } else {
2504
+ url = '/' + url;
2505
+ url = locationImplementation.formatURL(url);
2506
+ }
2507
+
2508
+ return url;
2509
+ }
2510
+
2511
+ __exports__["default"] = RouteDebug;
2512
+ });
2513
+ define("view_debug",
2514
+ ["mixins/port_mixin","exports"],
2515
+ function(__dependency1__, __exports__) {
2516
+ "use strict";
2517
+ var PortMixin = __dependency1__["default"];
2518
+
2519
+ var layerDiv,
2520
+ previewDiv,
2521
+ highlightedElement,
2522
+ previewedElement,
2523
+ $ = Ember.$,
2524
+ later = Ember.run.later,
2525
+ computed = Ember.computed,
2526
+ oneWay = computed.oneWay;
2527
+
2528
+ var ViewDebug = Ember.Object.extend(PortMixin, {
2529
+
2530
+ namespace: null,
2531
+
2532
+ application: oneWay('namespace.application').readOnly(),
2533
+ adapter: oneWay('namespace.adapter').readOnly(),
2534
+ port: oneWay('namespace.port').readOnly(),
2535
+ objectInspector: oneWay('namespace.objectInspector').readOnly(),
2536
+
2537
+ retainedObjects: [],
2538
+
2539
+ _durations: {},
2540
+
2541
+ options: {},
2542
+
2543
+ portNamespace: 'view',
2544
+
2545
+ messages: {
2546
+ getTree: function() {
2547
+ this.sendTree();
2548
+ },
2549
+ hideLayer: function() {
2550
+ this.hideLayer();
2551
+ },
2552
+ showLayer: function(message) {
2553
+ this.showLayer(message.objectId);
2554
+ },
2555
+ previewLayer: function(message) {
2556
+ this.previewLayer(message.objectId);
2557
+ },
2558
+ hidePreview: function(message) {
2559
+ this.hidePreview(message.objectId);
2560
+ },
2561
+ inspectViews: function(message) {
2562
+ if (message.inspect) {
2563
+ this.startInspecting();
2564
+ } else {
2565
+ this.stopInspecting();
2566
+ }
2567
+ },
2568
+ inspectElement: function(message) {
2569
+ this.inspectElement(message.objectId);
2570
+ },
2571
+ setOptions: function(message) {
2572
+ this.set('options', message.options);
2573
+ this.sendTree();
2574
+ },
2575
+ sendModelToConsole: function(message) {
2576
+ var view = this.get('objectInspector').sentObjects[message.viewId];
2577
+ var model = this.modelForView(view);
2578
+ if (model) {
2579
+ this.get('objectInspector').sendValueToConsole(model);
2580
+ }
2581
+ }
2582
+ },
2583
+
2584
+ init: function() {
2585
+ this._super();
2586
+ var self = this;
2587
+
2588
+ this.viewListener();
2589
+ this.retainedObjects = [];
2590
+ this.options = {};
2591
+
2592
+ layerDiv = $('<div>').appendTo('body').get(0);
2593
+ layerDiv.style.display = 'none';
2594
+ layerDiv.setAttribute('data-label', 'layer-div');
2595
+
2596
+ previewDiv = $('<div>').appendTo('body').css('pointer-events', 'none').get(0);
2597
+ previewDiv.style.display = 'none';
2598
+ previewDiv.setAttribute('data-label', 'preview-div');
2599
+
2600
+ $(window).on('resize.' + this.get('eventNamespace'), function() {
2601
+ if (highlightedElement) {
2602
+ self.highlightView(highlightedElement);
2603
+ }
2604
+ });
2605
+ },
2606
+
2607
+
2608
+ updateDurations: function(durations) {
2609
+ for (var guid in durations) {
2610
+ if (!durations.hasOwnProperty(guid)) {
2611
+ continue;
2612
+ }
2613
+ this._durations[guid] = durations[guid];
2614
+ }
2615
+ this.sendTree();
2616
+ },
2617
+
2618
+ retainObject: function(object) {
2619
+ this.retainedObjects.push(object);
2620
+ return this.get('objectInspector').retainObject(object);
2621
+ },
2622
+
2623
+ releaseCurrentObjects: function() {
2624
+ var self = this;
2625
+ this.retainedObjects.forEach(function(item) {
2626
+ self.get('objectInspector').releaseObject(Ember.guidFor(item));
2627
+ });
2628
+ this.retainedObjects = [];
2629
+ },
2630
+
2631
+ eventNamespace: Ember.computed(function() {
2632
+ return 'view_debug_' + Ember.guidFor(this);
2633
+ }).property(),
2634
+
2635
+ willDestroy: function() {
2636
+ this._super();
2637
+ $(window).off(this.get('eventNamespace'));
2638
+ $(layerDiv).remove();
2639
+ $(previewDiv).remove();
2640
+ Ember.View.removeMutationListener(this.viewTreeChanged);
2641
+ this.releaseCurrentObjects();
2642
+ this.stopInspecting();
2643
+ },
2644
+
2645
+ inspectElement: function(objectId) {
2646
+ var view = this.get('objectInspector').sentObjects[objectId];
2647
+ if (view && view.get('element')) {
2648
+ this.get('adapter').inspectElement(view.get('element'));
2649
+ }
2650
+ },
2651
+
2652
+ sendTree: function() {
2653
+ Ember.run.scheduleOnce('afterRender', this, this.scheduledSendTree);
2654
+ },
2655
+
2656
+ startInspecting: function() {
2657
+ var self = this, viewElem = null;
2658
+ this.sendMessage('startInspecting', {});
2659
+
2660
+ // we don't want the preview div to intercept the mousemove event
2661
+ $(previewDiv).css('pointer-events', 'none');
2662
+
2663
+ $('body').on('mousemove.inspect-' + this.get('eventNamespace'), function(e) {
2664
+ var originalTarget = $(e.target), oldViewElem = viewElem;
2665
+ viewElem = self.findNearestView(originalTarget);
2666
+ if (viewElem) {
2667
+ self.highlightView(viewElem, true);
2668
+ }
2669
+ })
2670
+ .on('mousedown.inspect-' + this.get('eventNamespace'), function() {
2671
+ // prevent app-defined clicks from being fired
2672
+ $(previewDiv).css('pointer-events', '')
2673
+ .one('mouseup', function() {
2674
+ // chrome
2675
+ return pinView();
2676
+ });
2677
+ })
2678
+ .on('mouseup.inspect-' + this.get('eventNamespace'), function() {
2679
+ // firefox
2680
+ return pinView();
2681
+ })
2682
+ .css('cursor', '-webkit-zoom-in');
2683
+
2684
+ function pinView() {
2685
+ if (viewElem) {
2686
+ self.highlightView(viewElem);
2687
+ var view = self.get('objectInspector').sentObjects[viewElem.id];
2688
+ if (view instanceof Ember.Component) {
2689
+ self.get('objectInspector').sendObject(view);
2690
+ }
2691
+ }
2692
+ self.stopInspecting();
2693
+ return false;
2694
+ }
2695
+ },
2696
+
2697
+ findNearestView: function(elem) {
2698
+ var viewElem, view;
2699
+ if (!elem || elem.length === 0) { return null; }
2700
+ if (elem.hasClass('ember-view')) {
2701
+ viewElem = elem.get(0);
2702
+ view = this.get('objectInspector').sentObjects[viewElem.id];
2703
+ if (view && this.shouldShowView(view)) {
2704
+ return viewElem;
2705
+ }
2706
+ }
2707
+ return this.findNearestView($(elem).parents('.ember-view:first'));
2708
+ },
2709
+
2710
+ stopInspecting: function() {
2711
+ $('body')
2712
+ .off('mousemove.inspect-' + this.get('eventNamespace'))
2713
+ .off('mousedown.inspect-' + this.get('eventNamespace'))
2714
+ .off('mouseup.inspect-' + this.get('eventNamespace'))
2715
+ .off('click.inspect-' + this.get('eventNamespace'))
2716
+ .css('cursor', '');
2717
+
2718
+ this.hidePreview();
2719
+ this.sendMessage('stopInspecting', {});
2720
+ },
2721
+
2722
+ scheduledSendTree: function() {
2723
+ var self = this;
2724
+ // Send out of band
2725
+ later(function() {
2726
+ if (self.isDestroying) {
2727
+ return;
2728
+ }
2729
+ self.releaseCurrentObjects();
2730
+ var tree = self.viewTree();
2731
+ if (tree) {
2732
+ self.sendMessage('viewTree', {
2733
+ tree: tree
2734
+ });
2735
+ }
2736
+ }, 50);
2737
+ },
2738
+
2739
+ viewListener: function() {
2740
+ var self = this;
2741
+
2742
+ this.viewTreeChanged = function() {
2743
+ self.sendTree();
2744
+ self.hideLayer();
2745
+ };
2746
+
2747
+ Ember.View.addMutationListener(this.viewTreeChanged);
2748
+ },
2749
+
2750
+ viewTree: function() {
2751
+ var emberApp = this.get('application');
2752
+ if (!emberApp) {
2753
+ return false;
2754
+ }
2755
+
2756
+ var applicationViewId = $(emberApp.rootElement).find('> .ember-view').attr('id');
2757
+ var rootView = Ember.View.views[applicationViewId];
2758
+ // In case of App.reset view is destroyed
2759
+ if (!rootView) {
2760
+ return false;
2761
+ }
2762
+ var retained = [];
2763
+
2764
+ var children = [];
2765
+ var treeId = this.retainObject(retained);
2766
+
2767
+ var tree = { value: this.inspectView(rootView, retained), children: children, treeId: treeId };
2768
+
2769
+ this.appendChildren(rootView, children, retained);
2770
+
2771
+ return tree;
2772
+ },
2773
+
2774
+ modelForView: function(view) {
2775
+ var controller = view.get('controller');
2776
+ var model = controller.get('model');
2777
+ if (view.get('context') !== controller) {
2778
+ model = view.get('context');
2779
+ }
2780
+ return model;
2781
+ },
2782
+
2783
+ inspectView: function(view, retained) {
2784
+ var templateName = view.get('templateName') || view.get('_debugTemplateName'),
2785
+ viewClass = shortViewName(view), name;
2786
+
2787
+ var tagName = view.get('tagName');
2788
+ if (tagName === '') {
2789
+ tagName = '(virtual)';
2790
+ }
2791
+
2792
+ tagName = tagName || 'div';
2793
+
2794
+ var controller = view.get('controller');
2795
+
2796
+ name = viewDescription(view);
2797
+
2798
+
2799
+ var viewId = this.retainObject(view);
2800
+ retained.push(viewId);
2801
+
2802
+ var timeToRender = this._durations[viewId];
2803
+
2804
+ var value = {
2805
+ viewClass: viewClass,
2806
+ completeViewClass: viewName(view),
2807
+ objectId: viewId,
2808
+ duration: timeToRender,
2809
+ name: name,
2810
+ template: templateName || '(inline)',
2811
+ tagName: tagName,
2812
+ isVirtual: view.get('isVirtual'),
2813
+ isComponent: (view instanceof Ember.Component)
2814
+ };
2815
+
2816
+ if (controller && !(view instanceof Ember.Component)) {
2817
+ value.controller = {
2818
+ name: shortControllerName(controller),
2819
+ completeName: controllerName(controller),
2820
+ objectId: this.retainObject(controller)
2821
+ };
2822
+
2823
+ var model = this.modelForView(view);
2824
+ if (model) {
2825
+ if(Ember.Object.detectInstance(model) || Ember.typeOf(model) === 'array') {
2826
+ value.model = {
2827
+ name: shortModelName(model),
2828
+ completeName: modelName(model),
2829
+ objectId: this.retainObject(model),
2830
+ type: 'type-ember-object'
2831
+ };
2832
+ } else {
2833
+ value.model = {
2834
+ name: this.get('objectInspector').inspect(model),
2835
+ type: 'type-' + Ember.typeOf(model)
2836
+ };
2837
+ }
2838
+ }
2839
+ }
2840
+
2841
+ return value;
2842
+ },
2843
+
2844
+ appendChildren: function(view, children, retained) {
2845
+ var self = this;
2846
+ var childViews = view.get('_childViews'),
2847
+ controller = view.get('controller');
2848
+
2849
+ childViews.forEach(function(childView) {
2850
+ if (!(childView instanceof Ember.Object)) { return; }
2851
+
2852
+ if (self.shouldShowView(childView)) {
2853
+ var grandChildren = [];
2854
+ children.push({ value: self.inspectView(childView, retained), children: grandChildren });
2855
+ self.appendChildren(childView, grandChildren, retained);
2856
+ } else {
2857
+ self.appendChildren(childView, children, retained);
2858
+ }
2859
+ });
2860
+ },
2861
+
2862
+ shouldShowView: function(view) {
2863
+ return (this.options.allViews || this.hasOwnController(view) || this.hasOwnContext(view)) &&
2864
+ (this.options.components || !(view instanceof Ember.Component)) &&
2865
+ (!view.get('isVirtual') || this.hasOwnController(view) || this.hasOwnContext(view));
2866
+ },
2867
+
2868
+ hasOwnController: function(view) {
2869
+ return view.get('controller') !== view.get('_parentView.controller') &&
2870
+ ((view instanceof Ember.Component) || !(view.get('_parentView.controller') instanceof Ember.Component));
2871
+ },
2872
+
2873
+ hasOwnContext: function(view) {
2874
+ return view.get('context') !== view.get('_parentView.context') && !(view.get('_parentView') instanceof Ember.Component);
2875
+ },
2876
+
2877
+ highlightView: function(element, preview) {
2878
+ var self = this;
2879
+ var range, view, rect, div;
2880
+
2881
+ if (!element) { return; }
2882
+
2883
+ if (preview) {
2884
+ previewedElement = element;
2885
+ div = previewDiv;
2886
+ } else {
2887
+ this.hideLayer();
2888
+ highlightedElement = element;
2889
+ div = layerDiv;
2890
+ this.hidePreview();
2891
+ }
2892
+
2893
+ if (element instanceof Ember.View && element.get('isVirtual')) {
2894
+ view = element;
2895
+ if (view.get('isVirtual')) {
2896
+ range = virtualRange(view);
2897
+ rect = range.getBoundingClientRect();
2898
+ }
2899
+ } else if (element instanceof Ember.View) {
2900
+ view = element;
2901
+ element = view.get('element');
2902
+ if (!element) { return; }
2903
+ rect = element.getBoundingClientRect();
2904
+ } else {
2905
+ view = Ember.View.views[element.id];
2906
+ rect = element.getBoundingClientRect();
2907
+ }
2908
+
2909
+ // take into account the scrolling position as mentioned in docs
2910
+ // https://developer.mozilla.org/en-US/docs/Web/API/element.getBoundingClientRect
2911
+ rect = $().extend({}, rect);
2912
+ rect.top = rect.top + window.scrollY;
2913
+ rect.left = rect.left + window.scrollX;
2914
+
2915
+ var templateName = view.get('templateName') || view.get('_debugTemplateName'),
2916
+ controller = view.get('controller'),
2917
+ model = controller && controller.get('model');
2918
+
2919
+ $(div).css(rect);
2920
+ $(div).css({
2921
+ display: "block",
2922
+ position: "absolute",
2923
+ backgroundColor: "rgba(255, 255, 255, 0.7)",
2924
+ border: "2px solid rgb(102, 102, 102)",
2925
+ padding: "0",
2926
+ right: "auto",
2927
+ direction: "ltr",
2928
+ boxSizing: "border-box",
2929
+ color: "rgb(51, 51, 255)",
2930
+ fontFamily: "Menlo, sans-serif",
2931
+ minHeight: 63,
2932
+ zIndex: 10000
2933
+ });
2934
+
2935
+ var output = "";
2936
+
2937
+ if (!preview) {
2938
+ output = "<span class='close' data-label='layer-close'>&times;</span>";
2939
+ }
2940
+
2941
+ if (templateName) {
2942
+ output += "<p class='template'><span>template</span>=<span data-label='layer-template'>" + escapeHTML(templateName) + "</span></p>";
2943
+ }
2944
+
2945
+ if (!(view instanceof Ember.Component)) {
2946
+ if (controller) {
2947
+ output += "<p class='controller'><span>controller</span>=<span data-label='layer-controller'>" + escapeHTML(controllerName(controller)) + "</span></p>";
2948
+ }
2949
+ output += "<p class='view'><span>view</span>=<span data-label='layer-view'>" + escapeHTML(viewName(view)) + "</span></p>";
2950
+ } else {
2951
+ output += "<p class='component'><span>component</span>=<span data-label='layer-component'>" + escapeHTML(viewName(view)) + "</span></p>";
2952
+ }
2953
+
2954
+ if (model) {
2955
+ var modelName = this.get('objectInspector').inspect(model);
2956
+ output += "<p class='model'><span>model</span>=<span data-label='layer-model'>" + escapeHTML(modelName) + "</span></p>";
2957
+ }
2958
+
2959
+ $(div).html(output);
2960
+
2961
+ $('p', div).css({ float: 'left', margin: 0, backgroundColor: 'rgba(255, 255, 255, 0.9)', padding: '5px', color: 'rgb(0, 0, 153)' });
2962
+ $('p.model', div).css({ clear: 'left' });
2963
+ $('p span:first-child', div).css({ color: 'rgb(153, 153, 0)' });
2964
+ $('p span:last-child', div).css({ color: 'rgb(153, 0, 153)' });
2965
+
2966
+ if (!preview) {
2967
+ $('span.close', div).css({
2968
+ float: 'right',
2969
+ margin: '5px',
2970
+ background: '#666',
2971
+ color: '#eee',
2972
+ fontFamily: 'helvetica, sans-serif',
2973
+ fontSize: '12px',
2974
+ width: 16,
2975
+ height: 16,
2976
+ lineHeight: '14px',
2977
+ borderRadius: 16,
2978
+ textAlign: 'center',
2979
+ cursor: 'pointer'
2980
+ }).on('click', function() {
2981
+ self.hideLayer();
2982
+ return false;
2983
+ }).on('mouseup mousedown', function() {
2984
+ // prevent re-pinning
2985
+ return false;
2986
+ });
2987
+ }
2988
+
2989
+ $('p.view span:last-child', div).css({ cursor: 'pointer' }).click(function() {
2990
+ self.get('objectInspector').sendObject(view);
2991
+ });
2992
+
2993
+ $('p.controller span:last-child', div).css({ cursor: 'pointer' }).click(function() {
2994
+ self.get('objectInspector').sendObject(controller);
2995
+ });
2996
+
2997
+ $('p.component span:last-child', div).css({ cursor: 'pointer' }).click(function() {
2998
+ self.get('objectInspector').sendObject(view);
2999
+ });
3000
+
3001
+ $('p.template span:last-child', div).css({ cursor: 'pointer' }).click(function() {
3002
+ self.inspectElement(Ember.guidFor(view));
3003
+ });
3004
+
3005
+ if (model && ((model instanceof Ember.Object) || Ember.typeOf(model) === 'array')) {
3006
+ $('p.model span:last-child', div).css({ cursor: 'pointer' }).click(function() {
3007
+ self.get('objectInspector').sendObject(controller.get('model'));
3008
+ });
3009
+ }
3010
+
3011
+ if (!preview) {
3012
+ this.sendMessage('pinView', { objectId: Ember.guidFor(view) });
3013
+ }
3014
+ },
3015
+
3016
+ showLayer: function(objectId) {
3017
+ this.highlightView(this.get('objectInspector').sentObjects[objectId]);
3018
+ },
3019
+
3020
+ previewLayer: function(objectId) {
3021
+ this.highlightView(this.get('objectInspector').sentObjects[objectId], true);
3022
+ },
3023
+
3024
+ hideLayer: function() {
3025
+ this.sendMessage('unpinView', {});
3026
+ layerDiv.style.display = 'none';
3027
+ highlightedElement = null;
3028
+ },
3029
+
3030
+ hidePreview: function() {
3031
+ previewDiv.style.display = 'none';
3032
+ previewedElement = null;
3033
+ }
3034
+ });
3035
+
3036
+ function viewName(view) {
3037
+ var name = view.constructor.toString(), match;
3038
+ if (name.match(/\._/)) {
3039
+ name = "virtual";
3040
+ } else if (match = name.match(/\(subclass of (.*)\)/)) {
3041
+ name = match[1];
3042
+ }
3043
+ return name;
3044
+ }
3045
+
3046
+ function shortViewName(view) {
3047
+ var name = viewName(view);
3048
+ // jj-abrams-resolver adds `app@view:` and `app@component:`
3049
+ return name.replace(/.+(view|component):/, '').replace(/:$/, '');
3050
+ }
3051
+
3052
+ function modelName(model) {
3053
+ var name = '<Unknown model>';
3054
+ if (model.toString) {
3055
+ name = model.toString();
3056
+ }
3057
+
3058
+
3059
+ if (name.length > 50) {
3060
+ name = name.substr(0, 50) + '...';
3061
+ }
3062
+ return name;
3063
+ }
3064
+
3065
+ function shortModelName(model) {
3066
+ var name = modelName(model);
3067
+ // jj-abrams-resolver adds `app@model:`
3068
+ return name.replace(/<[^>]+@model:/g, '<');
3069
+ }
3070
+
3071
+ function controllerName(controller) {
3072
+ var key = controller.get('_debugContainerKey'),
3073
+ className = controller.constructor.toString(),
3074
+ name, match;
3075
+
3076
+ if (match = className.match(/^\(subclass of (.*)\)/)) {
3077
+ className = match[1];
3078
+ }
3079
+
3080
+ return className;
3081
+ }
3082
+
3083
+ function shortControllerName(controller) {
3084
+ var name = controllerName(controller);
3085
+ // jj-abrams-resolver adds `app@controller:` at the begining and `:` at the end
3086
+ return name.replace(/^.+@controller:/, '').replace(/:$/, '');
3087
+ }
3088
+
3089
+ function escapeHTML(string) {
3090
+ var div = document.createElement('div');
3091
+ div.appendChild(document.createTextNode(string));
3092
+ return div.innerHTML;
3093
+ }
3094
+
3095
+ function virtualRange(view) {
3096
+ var start, end;
3097
+ var morph = view.get('morph');
3098
+
3099
+ if (morph) {
3100
+ start = $('#' + morph.start)[0];
3101
+ end = $('#' + morph.end)[0];
3102
+ } else {
3103
+ // Support for metal-views
3104
+ morph = view.get('_morph');
3105
+ start = morph.start;
3106
+ end = morph.end;
3107
+ }
3108
+
3109
+ var range = document.createRange();
3110
+ range.setStartAfter(start);
3111
+ range.setEndBefore(end);
3112
+
3113
+ return range;
3114
+ }
3115
+
3116
+ function viewDescription(view) {
3117
+ var templateName = view.get('templateName') || view.get('_debugTemplateName'),
3118
+ name, viewClass = shortViewName(view), controller = view.get('controller'),
3119
+ parentClassName;
3120
+
3121
+ if (templateName) {
3122
+ name = templateName;
3123
+ } else if (view instanceof Ember.LinkView) {
3124
+ name = 'link';
3125
+ } else if (view.get('_parentView.controller') === controller || view instanceof Ember.Component) {
3126
+ var viewClassName = view.get('_debugContainerKey');
3127
+ if (viewClassName) {
3128
+ viewClassName = viewClassName.match(/\:(.*)/);
3129
+ if (viewClassName) {
3130
+ viewClassName = viewClassName[1];
3131
+ }
3132
+ }
3133
+ if (!viewClassName && viewClass) {
3134
+ viewClassName = viewClass.match(/\.(.*)/);
3135
+ if (viewClassName) {
3136
+ viewClassName = viewClassName[1];
3137
+ } else {
3138
+ viewClassName = viewClass;
3139
+ }
3140
+
3141
+ var shortName = viewClassName.match(/(.*)(View|Component)$/);
3142
+ if (shortName) {
3143
+ viewClassName = shortName[1];
3144
+ }
3145
+ }
3146
+ if (viewClassName) {
3147
+ name = Ember.String.camelize(viewClassName);
3148
+ }
3149
+ } else if (view.get('_parentView.controller') !== controller) {
3150
+ var key = controller.get('_debugContainerKey'),
3151
+ className = controller.constructor.toString();
3152
+
3153
+ if (key) {
3154
+ name = key.split(':')[1];
3155
+ } else {
3156
+ if (parentClassName = className.match(/^\(subclass of (.*)\)/)) {
3157
+ className = parentClassName[1];
3158
+ }
3159
+ name = className.split('.').pop();
3160
+ name = Ember.String.camelize(name);
3161
+ }
3162
+ }
3163
+
3164
+ if (!name) {
3165
+ name = '(inline view)';
3166
+ }
3167
+ return name;
3168
+ }
3169
+
3170
+ __exports__["default"] = ViewDebug;
3171
+ });
3172
+
3173
+ }("chrome"))