web-console 2.1.3 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +45 -0
  3. data/README.markdown +26 -6
  4. data/Rakefile +37 -0
  5. data/lib/web_console/extensions.rb +2 -1
  6. data/lib/web_console/integration/cruby.rb +2 -1
  7. data/lib/web_console/integration/rubinius.rb +2 -1
  8. data/lib/web_console/railtie.rb +19 -1
  9. data/lib/web_console/session.rb +4 -3
  10. data/lib/web_console/templates/_inner_console_markup.html.erb +8 -3
  11. data/lib/web_console/templates/console.js.erb +169 -46
  12. data/lib/web_console/templates/error_page.js.erb +2 -15
  13. data/lib/web_console/templates/main.js.erb +1 -24
  14. data/lib/web_console/templates/style.css.erb +22 -9
  15. data/lib/web_console/tracer.rb +11 -0
  16. data/lib/web_console/version.rb +1 -1
  17. metadata +5 -155
  18. data/test/dummy/README.rdoc +0 -28
  19. data/test/dummy/Rakefile +0 -6
  20. data/test/dummy/app/assets/javascripts/application.js +0 -13
  21. data/test/dummy/app/assets/stylesheets/application.css +0 -13
  22. data/test/dummy/app/controllers/application_controller.rb +0 -5
  23. data/test/dummy/app/controllers/controller_helper_test_controller.rb +0 -7
  24. data/test/dummy/app/controllers/exception_test_controller.rb +0 -15
  25. data/test/dummy/app/controllers/helper_error_controller.rb +0 -4
  26. data/test/dummy/app/controllers/helper_test_controller.rb +0 -5
  27. data/test/dummy/app/controllers/tests_controller.rb +0 -16
  28. data/test/dummy/app/helpers/application_helper.rb +0 -2
  29. data/test/dummy/app/views/controller_helper_test/index.html.erb +0 -1
  30. data/test/dummy/app/views/exception_test/xhr.html.erb +0 -1
  31. data/test/dummy/app/views/helper_error/index.html.erb +0 -2
  32. data/test/dummy/app/views/helper_test/index.html.erb +0 -220
  33. data/test/dummy/app/views/layouts/application.html.erb +0 -16
  34. data/test/dummy/bin/bundle +0 -3
  35. data/test/dummy/bin/rails +0 -4
  36. data/test/dummy/bin/rake +0 -4
  37. data/test/dummy/config.ru +0 -4
  38. data/test/dummy/config/application.rb +0 -19
  39. data/test/dummy/config/boot.rb +0 -5
  40. data/test/dummy/config/database.yml +0 -25
  41. data/test/dummy/config/environment.rb +0 -5
  42. data/test/dummy/config/environments/development.rb +0 -29
  43. data/test/dummy/config/environments/production.rb +0 -80
  44. data/test/dummy/config/environments/test.rb +0 -34
  45. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  46. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  47. data/test/dummy/config/initializers/inflections.rb +0 -16
  48. data/test/dummy/config/initializers/mime_types.rb +0 -5
  49. data/test/dummy/config/initializers/secret_token.rb +0 -12
  50. data/test/dummy/config/initializers/session_store.rb +0 -3
  51. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  52. data/test/dummy/config/locales/en.yml +0 -23
  53. data/test/dummy/config/routes.rb +0 -15
  54. data/test/dummy/db/schema.rb +0 -16
  55. data/test/dummy/db/test.sqlite3 +0 -0
  56. data/test/dummy/log/test.log +0 -808
  57. data/test/dummy/public/404.html +0 -58
  58. data/test/dummy/public/422.html +0 -58
  59. data/test/dummy/public/500.html +0 -57
  60. data/test/dummy/public/favicon.ico +0 -0
  61. data/test/dummy/tmp/cache/assets/test/sprockets/0c9b99b1b975b36a5b686845ae729db3 +0 -0
  62. data/test/dummy/tmp/cache/assets/test/sprockets/12e9f58adcf819cf65fd68b6859a438f +0 -0
  63. data/test/dummy/tmp/cache/assets/test/sprockets/1fd6abead3df36a4e4a2cb042a551b39 +0 -0
  64. data/test/dummy/tmp/cache/assets/test/sprockets/33b5eb81b5aaaa1e6dd5dcb6517792b4 +0 -0
  65. data/test/dummy/tmp/cache/assets/test/sprockets/3e460b2e021085f88b5597b38d194932 +0 -0
  66. data/test/dummy/tmp/cache/assets/test/sprockets/52f04b2ea6e461f4661b6d0be393fa94 +0 -0
  67. data/test/dummy/tmp/cache/assets/test/sprockets/688c344c2919f882338f06c5daaea209 +0 -0
  68. data/test/dummy/tmp/cache/assets/test/sprockets/7f079298e19bbef40a5d6a37dc03033a +0 -0
  69. data/test/dummy/tmp/cache/assets/test/sprockets/91aa709f89e465f58056fabe5f75eef4 +0 -0
  70. data/test/dummy/tmp/cache/assets/test/sprockets/95f4e4e5217aec9f71b2c1a65a9a9231 +0 -0
  71. data/test/dummy/tmp/cache/assets/test/sprockets/9c41be9b6625756fbb6d05b7665dd911 +0 -0
  72. data/test/dummy/tmp/cache/assets/test/sprockets/a95f64d41fcf8244b8f5b84a55f07822 +0 -0
  73. data/test/dummy/tmp/cache/assets/test/sprockets/c5e6bf1efd5929bee63e28ad7c9f6f83 +0 -0
  74. data/test/dummy/tmp/cache/assets/test/sprockets/d863259e9eeca657a1624135cfe24446 +0 -0
  75. data/test/dummy/tmp/cache/assets/test/sprockets/e1d2fc4601b6423ec8a42415ee05dd14 +0 -0
  76. data/test/dummy/tmp/cache/assets/test/sprockets/e82616536a759c2e87d703adc77d65da +0 -0
  77. data/test/support/scenarios/bad_custom_error_scenario.rb +0 -17
  78. data/test/support/scenarios/basic_nested_scenario.rb +0 -15
  79. data/test/support/scenarios/custom_error_scenario.rb +0 -11
  80. data/test/support/scenarios/eval_nested_scenario.rb +0 -15
  81. data/test/support/scenarios/flat_scenario.rb +0 -9
  82. data/test/support/scenarios/reraised_scenario.rb +0 -21
  83. data/test/test_helper.rb +0 -78
  84. data/test/web_console/evaluator_test.rb +0 -73
  85. data/test/web_console/extensions_test.rb +0 -28
  86. data/test/web_console/helper_test.rb +0 -76
  87. data/test/web_console/integration_test.rb +0 -47
  88. data/test/web_console/middleware_test.rb +0 -116
  89. data/test/web_console/railtie_test.rb +0 -99
  90. data/test/web_console/request_test.rb +0 -82
  91. data/test/web_console/session_test.rb +0 -59
  92. data/test/web_console/whiny_request_test.rb +0 -33
  93. data/test/web_console/whitelist_test.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cf0cbd5310d3c232a6dc3f3ffac02155928afaf
4
- data.tar.gz: df79c6d5af175c9987a6b4e5361b6ad4bbb99761
3
+ metadata.gz: bde2832a1ef7a0ace010d61011afb4c74a116a93
4
+ data.tar.gz: c0e5de96dab453f1a3e233d969bf5ada72ba848a
5
5
  SHA512:
6
- metadata.gz: 4cb26884dfa66837135c89f632aaed9a2643d816a8955a3967005f5884c95f35f65597569b82431bc8027f3de35125e7282f6a8803fd329d2356538c44436816
7
- data.tar.gz: 51ee3fcdfa8f4a37f2607d48a9c4e1019c706937d074c74946e25f7d064136be67a7b492bafc23170b4963303f465d844942fc5c28ba2f024ece111b17a82648
6
+ metadata.gz: eb74d0994835ccc223df24cb3a5ee1e034ca2456580f99962724864994438f04a14c67aa05f9425263f1c36773623969abdc7bca5a2b255535e90449b6394ac3
7
+ data.tar.gz: 31f90bb5c32ed53a95f43cb1a0f25cf89765847c92010255a9df5c0235423203711be37e09eda9af4f435616772d247502b682a2ef367f5409cbbbcc23cca963
@@ -0,0 +1,45 @@
1
+ # CHANGELOG
2
+
3
+ ## master (unreleased)
4
+
5
+ ## 2.2.0
6
+
7
+ * [#140](https://github.com/rails/web-console/pull/140) Add the ability to close the console on each page ([@sh19910711])
8
+ * [#135](https://github.com/rails/web-console/pull/135) Run the console only in development mode and raise warning in tests ([@frenesim])
9
+
10
+ ## 2.1.3
11
+
12
+ * Fix remote code execution vulnerability in Web Console. CVE-2015-3224.
13
+ * [#123](https://github.com/rails/web-console/pull/123) Replace deprecated `alias_method_chain` with `alias_method` ([@jonatack])
14
+
15
+ ## 2.1.2
16
+
17
+ * [#115](https://github.com/rails/web-console/pull/115) Show proper binding when raising an error in a template ([@gsamokovarov])
18
+ * [#114](https://github.com/rails/web-console/pull/114) Fix templates non rendering, because of missing template suffix ([@gsamokovarov])
19
+
20
+ ## 2.1.1
21
+
22
+ * [#112](https://github.com/rails/web-console/pull/112) Always allow application/x-www-form-urlencoded content type ([@gsamokovarov])
23
+
24
+ ## 2.1.0
25
+
26
+ * [#109](https://github.com/rails/web-console/pull/109) Revamp unavailable session response message ([@gsamokovarov])
27
+ * [#107](https://github.com/rails/web-console/pull/107) Fix pasting regression for all browsers ([@parterburn])
28
+ * [#105](https://github.com/rails/web-console/pull/105) Lock scroll bottom on console window resize ([@noahpatterson])
29
+ * [#104](https://github.com/rails/web-console/pull/104) Always whitelist localhost and inform users why no console is displayed ([@gsamokovarov])
30
+ * [#100](https://github.com/rails/web-console/pull/100) Accept text/plain as acceptable content type for Puma ([@gsamokovarov])
31
+ * [#98](https://github.com/rails/web-console/pull/98) Add arbitrary big z-index to the console ([@bglbruno])
32
+ * [#88](https://github.com/rails/web-console/pull/88) Spelling fixes ([@jeffnv])
33
+ * [#86](https://github.com/rails/web-console/pull/86) Disable autofocus when initializing the console ([@ryandao])
34
+ * [#84](https://github.com/rails/web-console/pull/84) Allow Rails 5 as dependency in gemspec ([@jonatack])
35
+ * [#69](https://github.com/rails/web-console/pull/69) Introduce middleware for request dispatch and console rendering ([@gsamokovarov])
36
+
37
+ [@jonatack]: https://github.com/jonatack
38
+ [@ryandao]: https://github.com/ryandao
39
+ [@jeffnv]: https://github.com/jeffnv
40
+ [@gsamokovarov]: https://github.com/gsamokovarov
41
+ [@bglbruno]: https://github.com/bglbruno
42
+ [@noahpatterson]: https://github.com/noahpatterson
43
+ [@parterburn]: https://github.com/parterburn
44
+ [@sh19910711]: https://github.com/sh19910711
45
+ [@frenesim]: https://github.com/frenesim
@@ -1,6 +1,10 @@
1
1
  <p align=right>
2
2
  Documentation for:
3
3
  <a href=https://github.com/rails/web-console/tree/v2.0.0>v2.0.0</a>
4
+ <a href=https://github.com/rails/web-console/tree/v2.1.0>v2.1.0</a>
5
+ <a href=https://github.com/rails/web-console/tree/v2.1.1>v2.1.1</a>
6
+ <a href=https://github.com/rails/web-console/tree/v2.1.2>v2.1.2</a>
7
+ <a href=https://github.com/rails/web-console/tree/v2.1.3>v2.1.3</a>
4
8
  </p>
5
9
 
6
10
  # Web Console [![Build Status](https://travis-ci.org/rails/web-console.svg?branch=master)](https://travis-ci.org/rails/web-console)
@@ -119,7 +123,7 @@ end
119
123
  If you want to whitelist the whole private network, you can do:
120
124
 
121
125
  ```ruby
122
- class Application < Rails::Application
126
+ Rails.application.configure do
123
127
  config.web_console.whitelisted_ips = '192.168.0.0/16'
124
128
  end
125
129
  ```
@@ -138,19 +142,19 @@ messages like the following is printed in the server logs:
138
142
  If you don't wanna see this message anymore, set this option to `false`:
139
143
 
140
144
  ```ruby
141
- class Application < Rails::Application
145
+ Rails.application.configure do
142
146
  config.web_console.whiny_requests = false
143
147
  end
144
148
  ```
145
149
 
146
- ### config.web_console.templates_path
150
+ ### config.web_console.template_paths
147
151
 
148
152
  If you wanna style the console yourself, you can place `style.css` at a
149
- directory pointed by `config.web_console.templates_path`:
153
+ directory pointed by `config.web_console.template_paths`:
150
154
 
151
155
  ```ruby
152
- class Application < Rails::Application
153
- config.web_console.templates_path = 'app/views/web_console'
156
+ Rails.application.configure do
157
+ config.web_console.template_paths = 'app/views/web_console'
154
158
  end
155
159
  ```
156
160
 
@@ -181,6 +185,22 @@ server requests only out of one process.
181
185
  The interactive console executes Ruby code. Invoking `instance_variables` and
182
186
  `local_variables` will give you what you want.
183
187
 
188
+ ### Why does console only appear on error pages but not when I call it?
189
+
190
+ This can be happening if you are using `Rack::Deflater`. Be sure that
191
+ `WebConsole::Middleware` is used after `Rack::Deflater`. The easiest way to do
192
+ this is to insert `Rack::Deflater` as early as possible
193
+
194
+ ```ruby
195
+ Rails.application.configure do
196
+ config.middleware.insert(0, Rack::Deflater)
197
+ end
198
+ ```
199
+
200
+ ### Why I'm getting an undefined method `web_console`?
201
+
202
+ Make sure you configuration lives in `config/environments/development.rb`.
203
+
184
204
  ## Credits
185
205
 
186
206
  * Shoutout to [Charlie Somerville] for [better_errors] and [this] code.
data/Rakefile CHANGED
@@ -6,6 +6,8 @@ end
6
6
 
7
7
  require 'socket'
8
8
  require 'rake/testtask'
9
+ require 'tmpdir'
10
+ require 'securerandom'
9
11
 
10
12
  EXPANDED_CWD = File.expand_path(File.dirname(__FILE__))
11
13
 
@@ -16,6 +18,41 @@ Rake::TestTask.new(:test) do |t|
16
18
  t.verbose = false
17
19
  end
18
20
 
21
+ namespace :test do
22
+ desc "Run tests for templates"
23
+ task :templates => "templates:all"
24
+
25
+ namespace :templates do
26
+ task :all => [:daemonize, :npm, :rackup, :mocha, :kill]
27
+ task :serve => [:npm, :rackup]
28
+
29
+ work_dir = Pathname(__FILE__).dirname.join("test/templates")
30
+ pid_file = Pathname(Dir.tmpdir).join("web_console.#{SecureRandom.uuid}.pid")
31
+ server_port = 29292
32
+ rackup_opts = "-p #{server_port}"
33
+
34
+ task :daemonize do
35
+ rackup_opts += " -D -P #{pid_file}"
36
+ end
37
+
38
+ task :npm do
39
+ Dir.chdir(work_dir) { system "npm install --silent" }
40
+ end
41
+
42
+ task :rackup do
43
+ Dir.chdir(work_dir) { system "bundle exec rackup #{rackup_opts}" }
44
+ end
45
+
46
+ task :mocha do
47
+ Dir.chdir(work_dir) { system "$(npm bin)/mocha-phantomjs http://localhost:#{server_port}/html/spec_runner.html" }
48
+ end
49
+
50
+ task :kill do
51
+ system "kill #{File.read pid_file}"
52
+ end
53
+ end
54
+ end
55
+
19
56
  Bundler::GemHelper.install_tasks
20
57
 
21
58
  task default: :test
@@ -15,5 +15,6 @@ ActionDispatch::DebugExceptions.class_eval do
15
15
  end
16
16
  end
17
17
 
18
- alias_method_chain :render_exception, :web_console
18
+ alias_method :render_exception_without_web_console, :render_exception
19
+ alias_method :render_exception, :render_exception_with_web_console
19
20
  end
@@ -34,6 +34,7 @@ class Exception
34
34
  set_backtrace_without_binding_of_caller(*args)
35
35
  end
36
36
 
37
- alias_method_chain :set_backtrace, :binding_of_caller
37
+ alias_method :set_backtrace_without_binding_of_caller, :set_backtrace
38
+ alias_method :set_backtrace, :set_backtrace_with_binding_of_caller
38
39
  end
39
40
  end
@@ -62,5 +62,6 @@ end
62
62
  raise_exception_without_current_bindings(exc)
63
63
  end
64
64
 
65
- alias_method_chain :raise_exception, :current_bindings
65
+ alias_method :raise_exception_without_current_bindings, :raise_exception
66
+ alias_method :raise_exception, :raise_exception_with_current_bindings
66
67
  end
@@ -17,11 +17,29 @@ module WebConsole
17
17
  end
18
18
  end
19
19
 
20
+ initializer 'web_console.development_only' do
21
+ unless (config.web_console.development_only == false) || Rails.env.development?
22
+ abort <<-END.strip_heredoc
23
+ Web Console is activated in the #{Rails.env} environment, which is
24
+ usually a mistake. To ensure it's only activated in development
25
+ mode, move it to the development group of your Gemfile:
26
+
27
+ gem 'web-console', group: :development
28
+
29
+ If you still want to run it the #{Rails.env} environment (and know
30
+ what you are doing), put this in your Rails application
31
+ configuration:
32
+
33
+ config.web_console.development_only = false
34
+ END
35
+ end
36
+ end
37
+
20
38
  initializer 'web_console.insert_middleware' do |app|
21
39
  app.middleware.insert_before ActionDispatch::DebugExceptions, Middleware
22
40
  end
23
41
 
24
- initializer 'web_console.templates_path' do
42
+ initializer 'web_console.template_paths' do
25
43
  if template_paths = config.web_console.template_paths
26
44
  Template.template_paths.unshift(*Array(template_paths))
27
45
  end
@@ -9,7 +9,8 @@ module WebConsole
9
9
  # error pages only, as currently, this is the only client that needs to do
10
10
  # that.
11
11
  class Session
12
- INMEMORY_STORAGE = {}
12
+ cattr_reader :inmemory_storage
13
+ @@inmemory_storage = {}
13
14
 
14
15
  class << self
15
16
  # Finds a persisted session in memory by its id.
@@ -17,7 +18,7 @@ module WebConsole
17
18
  # Returns a persisted session if found in memory.
18
19
  # Raises NotFound error unless found in memory.
19
20
  def find(id)
20
- INMEMORY_STORAGE[id]
21
+ inmemory_storage[id]
21
22
  end
22
23
 
23
24
  # Create a Session from an exception.
@@ -59,7 +60,7 @@ module WebConsole
59
60
  private
60
61
 
61
62
  def store_into_memory
62
- INMEMORY_STORAGE[id] = self
63
+ inmemory_storage[id] = self
63
64
  end
64
65
  end
65
66
  end
@@ -1,3 +1,8 @@
1
- <div id='resizer'></div>
2
- <div class='console-inner'></div>
3
- <input id='clipboard' type='text'>
1
+ <div class='resizer layer'></div>
2
+ <div class='console-outer layer'>
3
+ <div class='console-actions'>
4
+ <div class='close-button button' title='close'>x</div>
5
+ </div>
6
+ <div class='console-inner'></div>
7
+ </div>
8
+ <input class='clipboard' type='text'>
@@ -1,40 +1,3 @@
1
- // DOM helpers
2
- function hasClass(el, className) {
3
- var regex = new RegExp('(?:^|\\s)' + className + '(?!\\S)', 'g');
4
- return el.className.match(regex);
5
- }
6
-
7
- function addClass(el, className) {
8
- el.className += " " + className;
9
- }
10
-
11
- function removeClass(el, className) {
12
- var regex = new RegExp('(?:^|\\s)' + className + '(?!\\S)', 'g');
13
- el.className = el.className.replace(regex, '');
14
- }
15
-
16
- function removeAllChildren(el) {
17
- while (el.firstChild) {
18
- el.removeChild(el.firstChild);
19
- }
20
- }
21
-
22
- function escapeHTML(html) {
23
- return html
24
- .replace(/&/g, '&amp;')
25
- .replace(/</g, '&lt;')
26
- .replace(/>/g, '&gt;')
27
- .replace(/"/g, '&quot;')
28
- .replace(/'/g, '&#x27;')
29
- .replace(/`/g, '&#x60;');
30
- }
31
-
32
- // Add CSS styles dynamically. This probably doesnt work for IE <8.
33
- var style = document.createElement('style');
34
- style.type = 'text/css';
35
- style.innerHTML = <%= render_inlined_string 'style.css' %>;
36
- document.getElementsByTagName('head')[0].appendChild(style);
37
-
38
1
  /**
39
2
  * Constructor for command storage.
40
3
  * It uses localStorage if available. Otherwise fallback to normal JS array.
@@ -84,6 +47,10 @@ function CommandStorage() {
84
47
  // HTML strings for dynamic elements.
85
48
  var consoleInnerHtml = <%= render_inlined_string '_inner_console_markup.html' %>;
86
49
  var promptBoxHtml = <%= render_inlined_string '_prompt_box_markup.html' %>;
50
+ // CSS
51
+ var consoleStyleCss = <%= render_inlined_string 'style.css' %>;
52
+ // Insert a style element with the unique ID
53
+ var styleElementId = 'sr02459pvbvrmhco';
87
54
 
88
55
  // REPLConsole Constructor
89
56
  function REPLConsole(config) {
@@ -122,17 +89,25 @@ REPLConsole.prototype.install = function(container) {
122
89
  // Render the console.
123
90
  container.innerHTML = consoleInnerHtml;
124
91
 
92
+ var consoleOuter = findChild(container, 'console-outer');
93
+ var consoleActions = findChild(consoleOuter, 'console-actions');
94
+
95
+ addClass(container, 'console');
96
+ addClass(container.getElementsByClassName('layer'), 'pos-absolute border-box');
97
+ addClass(container.getElementsByClassName('button'), 'border-box');
98
+ addClass(consoleActions, 'pos-fixed pos-right');
99
+
125
100
  // Make the console resizable.
126
- document.getElementById('resizer').addEventListener('mousedown', function(ev) {
101
+ function resizeContainer(ev) {
127
102
  var startY = ev.clientY;
128
103
  var startHeight = parseInt(document.defaultView.getComputedStyle(container).height, 10);
129
- var consoleInner = document.getElementsByClassName('console-inner')[0];
130
- var innerScrollTopStart = consoleInner.scrollTop;
131
- var innerClientHeightStart = consoleInner.clientHeight;
104
+ var scrollTopStart = consoleOuter.scrollTop;
105
+ var clientHeightStart = consoleOuter.clientHeight;
132
106
 
133
107
  var doDrag = function(e) {
134
108
  container.style.height = (startHeight + startY - e.clientY) + 'px';
135
- consoleInner.scrollTop = innerScrollTopStart + (innerClientHeightStart - consoleInner.clientHeight);
109
+ consoleOuter.scrollTop = scrollTopStart + (clientHeightStart - consoleOuter.clientHeight);
110
+ shiftConsoleActions();
136
111
  };
137
112
 
138
113
  var stopDrag = function(e) {
@@ -142,12 +117,50 @@ REPLConsole.prototype.install = function(container) {
142
117
 
143
118
  document.documentElement.addEventListener('mousemove', doDrag, false);
144
119
  document.documentElement.addEventListener('mouseup', stopDrag, false);
145
- });
120
+ }
121
+
122
+ function closeContainer(ev) {
123
+ container.parentNode.removeChild(container);
124
+ }
125
+
126
+ var shifted = false;
127
+ function shiftConsoleActions() {
128
+ if (consoleOuter.scrollHeight > consoleOuter.clientHeight) {
129
+ var widthDiff = document.documentElement.clientWidth - consoleOuter.clientWidth;
130
+ if (shifted || ! widthDiff) return;
131
+ shifted = true;
132
+ consoleActions.style.marginRight = widthDiff + 'px';
133
+ } else if (shifted) {
134
+ shifted = false;
135
+ consoleActions.style.marginRight = '0px';
136
+ }
137
+ }
146
138
 
147
139
  // Initialize
148
- this.inner = container.getElementsByClassName('console-inner')[0];
149
- this.clipboard = document.getElementById('clipboard');
140
+ this.outer = consoleOuter;
141
+ this.inner = findChild(this.outer, 'console-inner');
142
+ this.clipboard = findChild(container, 'clipboard');
143
+ this.remotePath = container.dataset.remotePath;
150
144
  this.newPromptBox();
145
+ this.insertCss();
146
+
147
+ findChild(container, 'resizer').addEventListener('mousedown', resizeContainer);
148
+ findChild(consoleActions, 'close-button').addEventListener('click', closeContainer);
149
+ consoleOuter.addEventListener('DOMNodeInserted', shiftConsoleActions);
150
+
151
+ REPLConsole.currentSession = this;
152
+ };
153
+
154
+ // Add CSS styles dynamically. This probably doesnt work for IE <8.
155
+ REPLConsole.prototype.insertCss = function() {
156
+ if (document.getElementById(styleElementId)) {
157
+ return; // already inserted
158
+ }
159
+ var style = document.createElement('style');
160
+ style.type = 'text/css';
161
+ style.innerHTML = consoleStyleCss;
162
+ style.id = styleElementId;
163
+ document.getElementsByTagName('head')[0].appendChild(style);
151
164
  };
152
165
 
153
166
  REPLConsole.prototype.focus = function() {
@@ -367,7 +380,117 @@ REPLConsole.prototype.insertAtCurrent = function(char) {
367
380
  };
368
381
 
369
382
  REPLConsole.prototype.scrollToBottom = function() {
370
- this.inner.scrollTop = this.inner.scrollHeight;
383
+ this.outer.scrollTop = this.outer.scrollHeight;
371
384
  };
372
385
 
386
+ // Change the binding of the console
387
+ REPLConsole.prototype.switchBindingTo = function(frameId, callback) {
388
+ var url = this.remotePath + "/trace";
389
+ var params = "frame_id=" + encodeURIComponent(frameId);
390
+ postRequest(url, params, callback);
391
+ };
392
+
393
+ /**
394
+ * Install the console into the element with a specific ID.
395
+ * Example: REPLConsole.installInto("target-id")
396
+ */
397
+ REPLConsole.installInto = function(id) {
398
+ var consoleElement = document.getElementById(id);
399
+ var remotePath = consoleElement.dataset.remotePath;
400
+ var replConsole = new REPLConsole({
401
+ promptLabel: consoleElement.dataset.initialPrompt,
402
+ commandHandle: function(line) {
403
+ var _this = this;
404
+ var url = remotePath;
405
+ var params = "input=" + encodeURIComponent(line);
406
+ putRequest(url, params, function(xhr) {
407
+ var response = JSON.parse(xhr.responseText);
408
+ _this.writeOutput(response.output);
409
+ });
410
+ }
411
+ });
412
+
413
+ replConsole.install(consoleElement);
414
+ return replConsole;
415
+ };
416
+
417
+ // This is to store the latest single session, and the stored session
418
+ // is updated by the REPLConsole#install() method.
419
+ // It allows to operate the current session from the other scripts.
420
+ REPLConsole.currentSession = null;
421
+
422
+ // DOM helpers
423
+ function hasClass(el, className) {
424
+ var regex = new RegExp('(?:^|\\s)' + className + '(?!\\S)', 'g');
425
+ return el.className && el.className.match(regex);
426
+ }
427
+
428
+ function isNodeList(el) {
429
+ return typeof el.length === 'number' &&
430
+ typeof el.item === 'function';
431
+ }
432
+
433
+ function addClass(el, className) {
434
+ if (isNodeList(el)) {
435
+ for (var i = 0; i < el.length; ++ i) {
436
+ addClass(el[i], className);
437
+ }
438
+ } else {
439
+ el.className += " " + className;
440
+ }
441
+ }
442
+
443
+ function removeClass(el, className) {
444
+ var regex = new RegExp('(?:^|\\s)' + className + '(?!\\S)', 'g');
445
+ el.className = el.className.replace(regex, '');
446
+ }
447
+
448
+ function removeAllChildren(el) {
449
+ while (el.firstChild) {
450
+ el.removeChild(el.firstChild);
451
+ }
452
+ }
453
+
454
+ function findChild(el, className) {
455
+ for (var i = 0; i < el.childNodes.length; ++ i) {
456
+ if (hasClass(el.childNodes[i], className)) {
457
+ return el.childNodes[i];
458
+ }
459
+ }
460
+ }
461
+
462
+ function escapeHTML(html) {
463
+ return html
464
+ .replace(/&/g, '&amp;')
465
+ .replace(/</g, '&lt;')
466
+ .replace(/>/g, '&gt;')
467
+ .replace(/"/g, '&quot;')
468
+ .replace(/'/g, '&#x27;')
469
+ .replace(/`/g, '&#x60;');
470
+ }
471
+
472
+ // XHR helpers
473
+ function request(method, url, params, callback) {
474
+ var xhr = new XMLHttpRequest();
475
+
476
+ xhr.open(method, url, true);
477
+ xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
478
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
479
+ xhr.send(params);
480
+
481
+ xhr.onreadystatechange = function() {
482
+ if (xhr.readyState === 4) {
483
+ callback(xhr);
484
+ }
485
+ }
486
+ }
487
+
488
+ function postRequest(url, params, callback) {
489
+ request("POST", url, params, callback);
490
+ }
491
+
492
+ function putRequest(url, params, callback) {
493
+ request("PUT", url, params, callback);
494
+ }
495
+
373
496
  window.REPLConsole = REPLConsole;