web-console-rails3 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.markdown +2 -2
- data/app/assets/javascripts/web_console/application.js +1 -3
- data/app/assets/javascripts/web_console/console_sessions.js +3 -24
- data/app/assets/stylesheets/web_console/application.css +1 -0
- data/app/assets/stylesheets/web_console/console_sessions.css +0 -8
- data/app/controllers/web_console/application_controller.rb +1 -0
- data/app/controllers/web_console/console_sessions_controller.rb +24 -4
- data/app/models/web_console/console_session.rb +32 -62
- data/app/views/web_console/console_sessions/index.html.erb +9 -4
- data/config/routes.rb +7 -1
- data/lib/assets/javascripts/web-console.js +1 -0
- data/lib/assets/javascripts/web_console.js +202 -0
- data/lib/web_console.rb +1 -1
- data/lib/web_console/engine.rb +17 -7
- data/lib/web_console/slave.rb +112 -0
- data/lib/web_console/version.rb +1 -1
- data/test/controllers/web_console/console_sessions_controller_test.rb +29 -11
- data/test/dummy/config/application.rb +17 -1
- data/test/dummy/config/application.rb.orig +58 -0
- data/test/dummy/log/development.log +28962 -0
- data/test/dummy/log/test.log +329 -0
- data/test/dummy/tmp/cache/assets/CBD/6E0/sprockets%2F3293dfc0984076f0e8371a9e7640f4a8 +0 -0
- data/test/dummy/tmp/cache/assets/CD0/FC0/sprockets%2Fbb2777627d42a216f3d9ced4322040b3 +0 -0
- data/test/dummy/tmp/cache/assets/CFA/E30/sprockets%2F35be1d26565dc0310c29f1a5e2f62f10 +0 -0
- data/test/dummy/tmp/cache/assets/D1D/FD0/sprockets%2Fa4a5ffe670666ce3d8d59179905201ef +0 -0
- data/test/dummy/tmp/cache/assets/D21/6B0/sprockets%2F9e242803fe56d6305274ff7e6487deda +0 -0
- data/test/dummy/tmp/cache/assets/D22/980/sprockets%2Fce6aa94ad2bc107104c0540f62c5128c +0 -0
- data/test/dummy/tmp/cache/assets/D3E/380/sprockets%2F434d98c8380bb9daf43810155aaf68ba +0 -0
- data/test/dummy/tmp/cache/assets/D66/940/sprockets%2F6151175b6ad4f9bab0c7e2b508e7b70f +0 -0
- data/test/dummy/tmp/cache/assets/D69/710/sprockets%2Ff67078d4b979a58c97feede196f6b385 +0 -0
- data/test/dummy/tmp/cache/assets/D95/C40/sprockets%2F09cb0a274209abf0391cbfce6ee67b82 +0 -0
- data/test/dummy/tmp/cache/assets/D9B/A30/sprockets%2Fc3436b3fe5da7c2456f26e2ae36da6c5 +0 -0
- data/test/dummy/tmp/cache/assets/D9F/400/sprockets%2F7f60332f86073dc8ed80b4c2a9dfcbe1 +0 -0
- data/test/dummy/tmp/cache/assets/DAE/8C0/sprockets%2Fa9b8f7bc5ca2efe658a13d7f4609c729 +0 -0
- data/test/dummy/tmp/cache/assets/DB3/0C0/sprockets%2F689fb998e2a7add3e00db88df254c87a +0 -0
- data/test/dummy/tmp/cache/assets/DD4/440/sprockets%2Fa33d646ac00d8bc87a4a496af6eed96f +0 -0
- data/test/dummy/tmp/cache/assets/DDB/890/sprockets%2F5ed566ca9fafd1b82373ffea2a8d8681 +0 -0
- data/test/models/console_session_test.rb +16 -75
- data/test/web_console/slave_test.rb +53 -0
- data/test/web_console_test.rb +51 -11
- data/vendor/assets/javascripts/vt100.js +4408 -0
- data/vendor/assets/stylesheets/vt100.css +272 -0
- metadata +23 -42
- data/lib/web_console/fiber.rb +0 -48
- data/lib/web_console/repl.rb +0 -59
- data/lib/web_console/repl/dummy.rb +0 -38
- data/lib/web_console/repl/irb.rb +0 -62
- data/lib/web_console/stream.rb +0 -30
- data/test/web_console/repl/dummy_test.rb +0 -54
- data/test/web_console/repl/irb_test.rb +0 -156
- data/test/web_console/repl_test.rb +0 -15
- data/vendor/assets/javascripts/jquery.console.js +0 -727
data/lib/web_console/repl.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/string/inflections'
|
2
|
-
|
3
|
-
module WebConsole
|
4
|
-
module REPL
|
5
|
-
extend self
|
6
|
-
|
7
|
-
# Registry of REPL implementations mapped to their correspondent adapter
|
8
|
-
# classes.
|
9
|
-
#
|
10
|
-
# Don't manually alter the registry. Use WebConsole::REPL.register_adapter
|
11
|
-
# for adding entries.
|
12
|
-
def adapters
|
13
|
-
@adapters ||= {}
|
14
|
-
end
|
15
|
-
|
16
|
-
# Register an adapter into the adapters registry.
|
17
|
-
#
|
18
|
-
# Registration maps and adapter class to an existing REPL implementation,
|
19
|
-
# that we call an adaptee constant. If the adaptee constant is not given,
|
20
|
-
# it is automatically derived from the adapter class name.
|
21
|
-
#
|
22
|
-
# For example, adapter named +WebConsole::REPL::IRB+ will derive the
|
23
|
-
# adaptee constant to +::IRB+.
|
24
|
-
#
|
25
|
-
# If a block is given, it would be evaluated right after the adapter
|
26
|
-
# registration.
|
27
|
-
def register_adapter(adapter_class, adaptee_constant = nil, options = {})
|
28
|
-
if adaptee_constant.is_a?(Hash)
|
29
|
-
options = adaptee_constant
|
30
|
-
adaptee_constant = nil
|
31
|
-
end
|
32
|
-
adaptee_constant = adapter_class if options[:standalone]
|
33
|
-
adaptee_constant ||= derive_adaptee_constant_from(adapter_class)
|
34
|
-
adapters[adaptee_constant] = adapter_class
|
35
|
-
yield if block_given?
|
36
|
-
end
|
37
|
-
|
38
|
-
# Get the default adapter for the given application.
|
39
|
-
#
|
40
|
-
# By default the application will be Rails.application and the adapter
|
41
|
-
# will be chosen from Rails.application.config.console.
|
42
|
-
#
|
43
|
-
# If no suitible adapter is found for the configured Rails console, a dummy
|
44
|
-
# adapter will be used. You can evaluate code in it, but it won't support
|
45
|
-
# any advanced features, like multiline code evaluation.
|
46
|
-
def default(app = Rails.application)
|
47
|
-
adapters[(app.config.console || ::IRB rescue ::IRB)] || adapters[Dummy]
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
def derive_adaptee_constant_from(cls, suffix = 'REPL')
|
52
|
-
"::#{cls.name.split('::').last.gsub(/#{suffix}$/i, '')}".constantize
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Require the builtin adapters.
|
58
|
-
require 'web_console/repl/irb'
|
59
|
-
require 'web_console/repl/dummy'
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'web_console/stream'
|
2
|
-
|
3
|
-
module WebConsole
|
4
|
-
module REPL
|
5
|
-
# == Dummy\ Adapter
|
6
|
-
#
|
7
|
-
# Dummy adapter that is used as a fallback for REPL with no adapters.
|
8
|
-
#
|
9
|
-
# It provides only the most basic code evaluation with no multiline code
|
10
|
-
# support.
|
11
|
-
class Dummy
|
12
|
-
def initialize(binding = TOPLEVEL_BINDING)
|
13
|
-
@binding = binding
|
14
|
-
end
|
15
|
-
|
16
|
-
def prompt
|
17
|
-
'>> '
|
18
|
-
end
|
19
|
-
|
20
|
-
def send_input(input)
|
21
|
-
eval_result = nil
|
22
|
-
streams_output = Stream.threadsafe_capture! do
|
23
|
-
eval_result = @binding.eval(input).inspect
|
24
|
-
end
|
25
|
-
"#{streams_output}=> #{eval_result}\n"
|
26
|
-
rescue Exception => exc
|
27
|
-
exc.backtrace.join("\n")
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
register_adapter Dummy, standalone: true do
|
32
|
-
require 'rails/console/app'
|
33
|
-
require 'rails/console/helpers'
|
34
|
-
|
35
|
-
TOPLEVEL_BINDING.eval('self').send(:include, Rails::ConsoleMethods)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/web_console/repl/irb.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'irb'
|
2
|
-
require 'web_console/fiber'
|
3
|
-
require 'web_console/stream'
|
4
|
-
|
5
|
-
module WebConsole
|
6
|
-
module REPL
|
7
|
-
# == IRB\ Adapter
|
8
|
-
#
|
9
|
-
# Adapter for the IRB REPL, which is the default Ruby on Rails console.
|
10
|
-
class IRB
|
11
|
-
# For some reason™ we have to be ::IRB::StdioInputMethod subclass to get
|
12
|
-
# #prompt populated.
|
13
|
-
#
|
14
|
-
# Not a pretty OOP, but for now, we just have to deal with it.
|
15
|
-
class FiberInputMethod < ::IRB::StdioInputMethod
|
16
|
-
def initialize; end
|
17
|
-
|
18
|
-
def gets
|
19
|
-
@previous = Fiber.yield
|
20
|
-
end
|
21
|
-
|
22
|
-
def encoding
|
23
|
-
(@previous || '').encoding
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(binding = TOPLEVEL_BINDING)
|
28
|
-
initialize_irb_session!
|
29
|
-
@input = FiberInputMethod.new
|
30
|
-
@irb = ::IRB::Irb.new(::IRB::WorkSpace.new(binding), @input)
|
31
|
-
@fiber = Fiber.new { @irb.eval_input }.tap(&:resume)
|
32
|
-
finalize_irb_session!
|
33
|
-
end
|
34
|
-
|
35
|
-
def prompt
|
36
|
-
@input.prompt
|
37
|
-
end
|
38
|
-
|
39
|
-
def send_input(input)
|
40
|
-
Stream.threadsafe_capture! { @fiber.resume("#{input}\n") }
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def initialize_irb_session!(ap_path = nil)
|
45
|
-
::IRB.init_config(ap_path)
|
46
|
-
::IRB.run_config unless WebConsole.config.prevent_irbrc_execution
|
47
|
-
end
|
48
|
-
|
49
|
-
def finalize_irb_session!
|
50
|
-
::IRB.conf[:MAIN_CONTEXT] = @irb.context
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
register_adapter IRB do
|
55
|
-
require 'rails/console/app'
|
56
|
-
require 'rails/console/helpers'
|
57
|
-
|
58
|
-
# Include all of the rails console helpers in the IRB session.
|
59
|
-
::IRB::ExtendCommandBundle.send(:include, Rails::ConsoleMethods)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/lib/web_console/stream.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'mutex_m'
|
2
|
-
|
3
|
-
module WebConsole
|
4
|
-
module Stream
|
5
|
-
extend Mutex_m
|
6
|
-
|
7
|
-
def self.threadsafe_capture!(*streams)
|
8
|
-
streams = [$stdout, $stderr] if streams.empty?
|
9
|
-
synchronize do
|
10
|
-
begin
|
11
|
-
streams_copy = streams.collect(&:dup)
|
12
|
-
replacement = Tempfile.new(name)
|
13
|
-
streams.each do |stream|
|
14
|
-
stream.reopen(replacement)
|
15
|
-
stream.sync = true
|
16
|
-
end
|
17
|
-
yield
|
18
|
-
streams.each(&:rewind)
|
19
|
-
replacement.read
|
20
|
-
ensure
|
21
|
-
replacement.close
|
22
|
-
replacement.unlink
|
23
|
-
streams.each_with_index do |stream, i|
|
24
|
-
stream.reopen(streams_copy[i])
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class REPLTest < ActiveSupport::TestCase
|
4
|
-
setup do
|
5
|
-
@dummy1 = @dummy = WebConsole::REPL::Dummy.new
|
6
|
-
@dummy2 = WebConsole::REPL::Dummy.new
|
7
|
-
end
|
8
|
-
|
9
|
-
test 'sending input returns the result as output' do
|
10
|
-
assert_equal "=> 42\n", @dummy.send_input('foo = 42')
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'preserves the session in the binding' do
|
14
|
-
assert_equal "=> 42\n", @dummy.send_input('foo = 42')
|
15
|
-
assert_equal "=> 50\n", @dummy.send_input('foo + 8')
|
16
|
-
end
|
17
|
-
|
18
|
-
test 'session isolation requires own bindings' do
|
19
|
-
dummy1 = WebConsole::REPL::IRB.new(Object.new.instance_eval('binding'))
|
20
|
-
dummy2 = WebConsole::REPL::IRB.new(Object.new.instance_eval('binding'))
|
21
|
-
assert_equal "=> 42\n", dummy1.send_input('foo = 42')
|
22
|
-
assert_match %r{NameError}, dummy2.send_input('foo')
|
23
|
-
end
|
24
|
-
|
25
|
-
test 'session preservation requires same bindings' do
|
26
|
-
assert_equal "=> 42\n", @dummy1.send_input('foo = 42')
|
27
|
-
assert_equal "=> 42\n", @dummy2.send_input('foo')
|
28
|
-
end
|
29
|
-
|
30
|
-
test 'captures stdout output' do
|
31
|
-
assert_equal "42\n=> nil\n", @dummy.send_input('puts 42')
|
32
|
-
end
|
33
|
-
|
34
|
-
test 'captures stderr output' do
|
35
|
-
assert_equal "42\n=> 3\n", @dummy.send_input('$stderr.write("42\n")')
|
36
|
-
end
|
37
|
-
|
38
|
-
test 'prompt is present' do
|
39
|
-
assert_not_nil @dummy.prompt
|
40
|
-
end
|
41
|
-
|
42
|
-
test 'rails helpers are available in the session' do
|
43
|
-
each_rails_console_method do |meth|
|
44
|
-
assert_equal "=> true\n", @dummy.send_input("respond_to? :#{meth}")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
def each_rails_console_method(&block)
|
50
|
-
require 'rails/console/app'
|
51
|
-
require 'rails/console/helpers'
|
52
|
-
Rails::ConsoleMethods.public_instance_methods.each(&block)
|
53
|
-
end
|
54
|
-
end
|
@@ -1,156 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class IRBTest < ActiveSupport::TestCase
|
4
|
-
setup do
|
5
|
-
@irb1 = @irb = WebConsole::REPL::IRB.new
|
6
|
-
@irb2 = WebConsole::REPL::IRB.new
|
7
|
-
|
8
|
-
# Flag to signalize that the .irbrc was read.
|
9
|
-
$IRBRC_EXECUTED = false
|
10
|
-
|
11
|
-
# Since IRB is kinda funky, it reads the .irbrc in $HOME/.irbrc earlier
|
12
|
-
# that the one in the current working directory, we have to lie to it.
|
13
|
-
@preserved_home, ENV['HOME'] = ENV['HOME'], nil
|
14
|
-
|
15
|
-
# It also caches the procedure used to generate the .irbrc location.
|
16
|
-
IRB.conf[:RC_NAME_GENERATOR] = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
teardown do
|
20
|
-
# Now, bring the working place as we have found it.
|
21
|
-
ENV['HOME'] = @preserved_home
|
22
|
-
WebConsole::Engine.config.web_console.prevent_irbrc_execution = false
|
23
|
-
end
|
24
|
-
|
25
|
-
test 'sending input returns the result as output' do
|
26
|
-
assert_equal return_prompt(42), @irb.send_input('foo = 42')
|
27
|
-
end
|
28
|
-
|
29
|
-
test 'preserves the session in the binding' do
|
30
|
-
assert_equal return_prompt(42), @irb.send_input('foo = 42')
|
31
|
-
assert_equal return_prompt(50), @irb.send_input('foo + 8')
|
32
|
-
end
|
33
|
-
|
34
|
-
test 'session isolation requires own bindings' do
|
35
|
-
irb1 = WebConsole::REPL::IRB.new(Object.new.instance_eval('binding'))
|
36
|
-
irb2 = WebConsole::REPL::IRB.new(Object.new.instance_eval('binding'))
|
37
|
-
assert_equal return_prompt(42), irb1.send_input('foo = 42')
|
38
|
-
assert_match %r{NameError}, irb2.send_input('foo')
|
39
|
-
end
|
40
|
-
|
41
|
-
test 'session preservation requires same bindings' do
|
42
|
-
assert_equal return_prompt(42), @irb1.send_input('foo = 42')
|
43
|
-
assert_equal return_prompt(42), @irb2.send_input('foo')
|
44
|
-
end
|
45
|
-
|
46
|
-
test 'multiline sessions' do
|
47
|
-
irb = WebConsole::REPL::IRB.new(Object.new.instance_eval('binding'))
|
48
|
-
assert_equal "", irb.send_input('class A')
|
49
|
-
assert_equal return_prompt('nil'), irb.send_input('end')
|
50
|
-
assert_no_match %r{NameError}, irb.send_input('A')
|
51
|
-
end
|
52
|
-
|
53
|
-
test 'captures direct stdout output' do
|
54
|
-
assert_equal "42\n#{return_prompt('nil')}", @irb.send_input('puts 42')
|
55
|
-
end
|
56
|
-
|
57
|
-
test 'captures direct stderr output' do
|
58
|
-
assert_equal "42\n#{return_prompt(3)}", @irb.send_input('$stderr.write("42\n")')
|
59
|
-
end
|
60
|
-
|
61
|
-
test 'captures direct output from subprocesses' do
|
62
|
-
assert_equal "42\n#{return_prompt(true)}", @irb.send_input('system "echo 42"')
|
63
|
-
end
|
64
|
-
|
65
|
-
test 'captures direct output from forks' do
|
66
|
-
# This is a bummer, but currently I don't see how we can work around it,
|
67
|
-
# without monkey patching fork and the crew to be blocking calls. This
|
68
|
-
# won't scale well, but at least fork will show results. Otherwise, we can
|
69
|
-
# document the behaviour and expect the user to wait themselves, if they
|
70
|
-
# care about the output.
|
71
|
-
assert_match %r{42\n}, @irb.send_input('Process.wait(fork { puts 42 })')
|
72
|
-
end
|
73
|
-
|
74
|
-
test 'multiline support between threads' do
|
75
|
-
assert_equal "", @irb.send_input('class A')
|
76
|
-
Thread.new do
|
77
|
-
assert_equal return_prompt('nil'), @irb.send_input('end')
|
78
|
-
assert_no_match %r{NameError}, @irb.send_input('A')
|
79
|
-
end.join
|
80
|
-
end
|
81
|
-
|
82
|
-
test 'prompt is present' do
|
83
|
-
assert_not_nil @irb.prompt
|
84
|
-
end
|
85
|
-
|
86
|
-
test 'prompt is determined by ::IRB.conf' do
|
87
|
-
with_simple_prompt do
|
88
|
-
assert '>> ', WebConsole::REPL::IRB.new.prompt
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
test 'closest .irbrc is executed by default' do
|
93
|
-
skip "I'm special. Travis is special. Who knows?"
|
94
|
-
Dir.chdir(File.expand_path('../../../fixtures', __FILE__)) do
|
95
|
-
WebConsole::REPL::IRB.new.tap { assert $IRBRC_EXECUTED }
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
test 'closest .irbrc execution can be prevented' do
|
100
|
-
WebConsole::Engine.config.web_console.prevent_irbrc_execution = true
|
101
|
-
Dir.chdir(File.expand_path('../../../fixtures', __FILE__)) do
|
102
|
-
WebConsole::REPL::IRB.new.tap { refute $IRBRC_EXECUTED }
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
test 'rails helpers are available in the session' do
|
107
|
-
each_rails_console_method do |meth|
|
108
|
-
assert_equal return_prompt(true), @irb.send_input("respond_to? :#{meth}")
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
def currently_selected_prompt
|
114
|
-
::IRB.conf[:PROMPT][::IRB.conf[:PROMPT_MODE]]
|
115
|
-
end
|
116
|
-
|
117
|
-
def return_prompt(*args)
|
118
|
-
sprintf(currently_selected_prompt[:RETURN], *args)
|
119
|
-
end
|
120
|
-
|
121
|
-
def input_prompt
|
122
|
-
currently_selected_prompt[:PROMPT_I]
|
123
|
-
end
|
124
|
-
|
125
|
-
def with_simple_prompt
|
126
|
-
previous_prompt = ::IRB.conf[:PROMPT]
|
127
|
-
::IRB.conf[:PROMPT] = :simple
|
128
|
-
yield
|
129
|
-
ensure
|
130
|
-
::IRB.conf[:PROMPT] = previous_prompt
|
131
|
-
end
|
132
|
-
|
133
|
-
def each_rails_console_method(&block)
|
134
|
-
require 'rails/console/app'
|
135
|
-
require 'rails/console/helpers'
|
136
|
-
Rails::ConsoleMethods.public_instance_methods.each(&block)
|
137
|
-
end
|
138
|
-
|
139
|
-
def new_uninitialized_app(root = File.expand_path('../../../dummy', __FILE__))
|
140
|
-
FileUtils.mkdir_p root
|
141
|
-
Dir.chdir root
|
142
|
-
|
143
|
-
old_app = Rails.application
|
144
|
-
Rails.application = nil
|
145
|
-
|
146
|
-
app = Class.new(Rails::Application)
|
147
|
-
app.config.eager_load = false
|
148
|
-
app.config.time_zone = 'UTC'
|
149
|
-
app.config.middleware ||= Rails::Configuration::MiddlewareStackProxy.new
|
150
|
-
app.config.active_support.deprecation = :notify
|
151
|
-
|
152
|
-
yield app
|
153
|
-
ensure
|
154
|
-
Rails.application = old_app
|
155
|
-
end
|
156
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class REPLTest < ActiveSupport::TestCase
|
4
|
-
test 'standalone adapter registration' do
|
5
|
-
WebConsole::REPL::register_adapter adapter = Class.new, standalone: true
|
6
|
-
assert_equal adapter, WebConsole::REPL::adapters[adapter]
|
7
|
-
end
|
8
|
-
|
9
|
-
test 'fallback for unsupported config.console' do
|
10
|
-
app_mock = Class.new do
|
11
|
-
define_singleton_method(:config) { OpenStruct.new(console: Class.new) }
|
12
|
-
end
|
13
|
-
assert_equal WebConsole::REPL::Dummy, WebConsole::REPL.default(app_mock)
|
14
|
-
end
|
15
|
-
end
|
@@ -1,727 +0,0 @@
|
|
1
|
-
// JQuery Console 1.0
|
2
|
-
// Sun Feb 21 20:28:47 GMT 2010
|
3
|
-
//
|
4
|
-
// Copyright 2010 Chris Done, Simon David Pratt. All rights reserved.
|
5
|
-
//
|
6
|
-
// Redistribution and use in source and binary forms, with or without
|
7
|
-
// modification, are permitted provided that the following conditions
|
8
|
-
// are met:
|
9
|
-
//
|
10
|
-
// 1. Redistributions of source code must retain the above
|
11
|
-
// copyright notice, this list of conditions and the following
|
12
|
-
// disclaimer.
|
13
|
-
//
|
14
|
-
// 2. Redistributions in binary form must reproduce the above
|
15
|
-
// copyright notice, this list of conditions and the following
|
16
|
-
// disclaimer in the documentation and/or other materials
|
17
|
-
// provided with the distribution.
|
18
|
-
//
|
19
|
-
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
20
|
-
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
21
|
-
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
22
|
-
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
23
|
-
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
24
|
-
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
25
|
-
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
26
|
-
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
-
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
28
|
-
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
29
|
-
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
-
// POSSIBILITY OF SUCH DAMAGE.
|
31
|
-
|
32
|
-
// TESTED ON
|
33
|
-
// Internet Explorer 6
|
34
|
-
// Opera 10.01
|
35
|
-
// Chromium 4.0.237.0 (Ubuntu build 31094)
|
36
|
-
// Firefox 3.5.8, 3.6.2 (Mac)
|
37
|
-
// Safari 4.0.5 (6531.22.7) (Mac)
|
38
|
-
// Google Chrome 5.0.375.55 (Mac)
|
39
|
-
|
40
|
-
(function($){
|
41
|
-
var isWebkit = !!~navigator.userAgent.indexOf(' AppleWebKit/');
|
42
|
-
|
43
|
-
$.fn.console = function(config){
|
44
|
-
////////////////////////////////////////////////////////////////////////
|
45
|
-
// Constants
|
46
|
-
// Some are enums, data types, others just for optimisation
|
47
|
-
var keyCodes = {
|
48
|
-
// left
|
49
|
-
37: moveBackward,
|
50
|
-
// right
|
51
|
-
39: moveForward,
|
52
|
-
// up
|
53
|
-
38: previousHistory,
|
54
|
-
// down
|
55
|
-
40: nextHistory,
|
56
|
-
// backspace
|
57
|
-
8: backDelete,
|
58
|
-
// delete
|
59
|
-
46: forwardDelete,
|
60
|
-
// end
|
61
|
-
35: moveToEnd,
|
62
|
-
// start
|
63
|
-
36: moveToStart,
|
64
|
-
// return
|
65
|
-
13: commandTrigger,
|
66
|
-
// tab
|
67
|
-
18: doNothing,
|
68
|
-
// tab
|
69
|
-
9: doComplete
|
70
|
-
};
|
71
|
-
var ctrlCodes = {
|
72
|
-
// C-a
|
73
|
-
65: moveToStart,
|
74
|
-
// C-e
|
75
|
-
69: moveToEnd,
|
76
|
-
// C-d
|
77
|
-
68: forwardDelete,
|
78
|
-
// C-n
|
79
|
-
78: nextHistory,
|
80
|
-
// C-p
|
81
|
-
80: previousHistory,
|
82
|
-
// C-b
|
83
|
-
66: moveBackward,
|
84
|
-
// C-f
|
85
|
-
70: moveForward,
|
86
|
-
// C-k
|
87
|
-
75: deleteUntilEnd
|
88
|
-
};
|
89
|
-
if(config.ctrlCodes) {
|
90
|
-
$.extend(ctrlCodes, config.ctrlCodes);
|
91
|
-
}
|
92
|
-
var altCodes = {
|
93
|
-
// M-f
|
94
|
-
70: moveToNextWord,
|
95
|
-
// M-b
|
96
|
-
66: moveToPreviousWord,
|
97
|
-
// M-d
|
98
|
-
68: deleteNextWord
|
99
|
-
};
|
100
|
-
var cursor = '<span class="jquery-console-cursor"> </span>';
|
101
|
-
|
102
|
-
////////////////////////////////////////////////////////////////////////
|
103
|
-
// Globals
|
104
|
-
var container = $(this);
|
105
|
-
var inner = $('<div class="jquery-console-inner"></div>');
|
106
|
-
// erjiang: changed this from a text input to a textarea so we
|
107
|
-
// can get pasted newlines
|
108
|
-
var typer = $('<textarea class="jquery-console-typer"></textarea>');
|
109
|
-
// Prompt
|
110
|
-
var promptBox;
|
111
|
-
var prompt;
|
112
|
-
var promptLabel = config && config.promptLabel? config.promptLabel : "> ";
|
113
|
-
var continuedPromptLabel = config && config.continuedPromptLabel?
|
114
|
-
config.continuedPromptLabel : "> ";
|
115
|
-
var column = 0;
|
116
|
-
var promptText = '';
|
117
|
-
var restoreText = '';
|
118
|
-
var continuedText = '';
|
119
|
-
// Prompt history stack
|
120
|
-
var history = [];
|
121
|
-
var ringn = 0;
|
122
|
-
// For reasons unknown to The Sword of Michael himself, Opera
|
123
|
-
// triggers and sends a key character when you hit various
|
124
|
-
// keys like PgUp, End, etc. So there is no way of knowing
|
125
|
-
// when a user has typed '#' or End. My solution is in the
|
126
|
-
// typer.keydown and typer.keypress functions; I use the
|
127
|
-
// variable below to ignore the keypress event if the keydown
|
128
|
-
// event succeeds.
|
129
|
-
var cancelKeyPress = 0;
|
130
|
-
// When this value is false, the prompt will not respond to input
|
131
|
-
var acceptInput = true;
|
132
|
-
// When this value is true, the command has been canceled
|
133
|
-
var cancelCommand = false;
|
134
|
-
|
135
|
-
// External exports object
|
136
|
-
var extern = {};
|
137
|
-
|
138
|
-
////////////////////////////////////////////////////////////////////////
|
139
|
-
// Main entry point
|
140
|
-
(function(){
|
141
|
-
container.append(inner);
|
142
|
-
inner.append(typer);
|
143
|
-
typer.css({position:'absolute',top:0,left:'-9999px'});
|
144
|
-
if (config.welcomeMessage)
|
145
|
-
message(config.welcomeMessage,'jquery-console-welcome');
|
146
|
-
newPromptBox();
|
147
|
-
if (config.autofocus) {
|
148
|
-
inner.addClass('jquery-console-focus');
|
149
|
-
typer.focus();
|
150
|
-
setTimeout(function(){
|
151
|
-
inner.addClass('jquery-console-focus');
|
152
|
-
typer.focus();
|
153
|
-
},100);
|
154
|
-
}
|
155
|
-
extern.inner = inner;
|
156
|
-
extern.typer = typer;
|
157
|
-
extern.scrollToBottom = scrollToBottom;
|
158
|
-
})();
|
159
|
-
|
160
|
-
////////////////////////////////////////////////////////////////////////
|
161
|
-
// Reset terminal
|
162
|
-
extern.reset = function(){
|
163
|
-
var welcome = (typeof config.welcomeMessage != 'undefined');
|
164
|
-
inner.parent().fadeOut(function(){
|
165
|
-
inner.find('div').each(function(){
|
166
|
-
if (!welcome) {
|
167
|
-
$(this).remove();
|
168
|
-
} else {
|
169
|
-
welcome = false;
|
170
|
-
}
|
171
|
-
});
|
172
|
-
newPromptBox();
|
173
|
-
inner.parent().fadeIn(function(){
|
174
|
-
inner.addClass('jquery-console-focus');
|
175
|
-
typer.focus();
|
176
|
-
});
|
177
|
-
});
|
178
|
-
};
|
179
|
-
|
180
|
-
////////////////////////////////////////////////////////////////////////
|
181
|
-
// Reset terminal
|
182
|
-
extern.notice = function(msg,style){
|
183
|
-
var n = $('<div class="notice"></div>').append($('<div></div>').text(msg))
|
184
|
-
.css({visibility:'hidden'});
|
185
|
-
container.append(n);
|
186
|
-
var focused = true;
|
187
|
-
if (style=='fadeout')
|
188
|
-
setTimeout(function(){
|
189
|
-
n.fadeOut(function(){
|
190
|
-
n.remove();
|
191
|
-
});
|
192
|
-
},4000);
|
193
|
-
else if (style=='prompt') {
|
194
|
-
var a = $('<br/><div class="action"><a href="javascript:">OK</a><div class="clear"></div></div>');
|
195
|
-
n.append(a);
|
196
|
-
focused = false;
|
197
|
-
a.click(function(){ n.fadeOut(function(){ n.remove();inner.css({opacity:1}) }); });
|
198
|
-
}
|
199
|
-
var h = n.height();
|
200
|
-
n.css({height:'0px',visibility:'visible'})
|
201
|
-
.animate({height:h+'px'},function(){
|
202
|
-
if (!focused) inner.css({opacity:0.5});
|
203
|
-
});
|
204
|
-
n.css('cursor','default');
|
205
|
-
return n;
|
206
|
-
};
|
207
|
-
|
208
|
-
extern.promptLabel = function(text) {
|
209
|
-
if (typeof text === 'string') {
|
210
|
-
promptLabel = text;
|
211
|
-
}
|
212
|
-
};
|
213
|
-
|
214
|
-
////////////////////////////////////////////////////////////////////////
|
215
|
-
// Make a new prompt box
|
216
|
-
function newPromptBox() {
|
217
|
-
column = 0;
|
218
|
-
promptText = '';
|
219
|
-
ringn = 0; // Reset the position of the history ring
|
220
|
-
enableInput();
|
221
|
-
promptBox = $('<div class="jquery-console-prompt-box"></div>');
|
222
|
-
var label = $('<span class="jquery-console-prompt-label"></span>');
|
223
|
-
var labelText = extern.continuedPrompt? continuedPromptLabel : promptLabel;
|
224
|
-
promptBox.append(label.text(labelText).show());
|
225
|
-
label.html(label.html().replace(' ',' '));
|
226
|
-
prompt = $('<span class="jquery-console-prompt"></span>');
|
227
|
-
promptBox.append(prompt);
|
228
|
-
inner.append(promptBox);
|
229
|
-
updatePromptDisplay();
|
230
|
-
};
|
231
|
-
|
232
|
-
////////////////////////////////////////////////////////////////////////
|
233
|
-
// Handle setting focus
|
234
|
-
container.click(function(){
|
235
|
-
inner.addClass('jquery-console-focus');
|
236
|
-
inner.removeClass('jquery-console-nofocus');
|
237
|
-
if (isWebkit) {
|
238
|
-
typer.focusWithoutScrolling();
|
239
|
-
} else {
|
240
|
-
typer.css('position', 'fixed').focus();
|
241
|
-
}
|
242
|
-
scrollToBottom();
|
243
|
-
return false;
|
244
|
-
});
|
245
|
-
|
246
|
-
////////////////////////////////////////////////////////////////////////
|
247
|
-
// Handle losing focus
|
248
|
-
typer.blur(function(){
|
249
|
-
inner.removeClass('jquery-console-focus');
|
250
|
-
inner.addClass('jquery-console-nofocus');
|
251
|
-
});
|
252
|
-
|
253
|
-
////////////////////////////////////////////////////////////////////////
|
254
|
-
// Bind to the paste event of the input box so we know when we
|
255
|
-
// get pasted data
|
256
|
-
typer.bind('paste', function(e) {
|
257
|
-
// wipe typer input clean just in case
|
258
|
-
typer.val("");
|
259
|
-
// this timeout is required because the onpaste event is
|
260
|
-
// fired *before* the text is actually pasted
|
261
|
-
setTimeout(function() {
|
262
|
-
typer.consoleInsert(typer.val());
|
263
|
-
typer.val("");
|
264
|
-
}, 0);
|
265
|
-
});
|
266
|
-
|
267
|
-
////////////////////////////////////////////////////////////////////////
|
268
|
-
// Handle key hit before translation
|
269
|
-
// For picking up control characters like up/left/down/right
|
270
|
-
|
271
|
-
typer.keydown(function(e){
|
272
|
-
cancelKeyPress = 0;
|
273
|
-
var keyCode = e.keyCode;
|
274
|
-
// C-c: cancel the execution
|
275
|
-
if(e.ctrlKey && keyCode == 67) {
|
276
|
-
cancelKeyPress = keyCode;
|
277
|
-
cancelExecution();
|
278
|
-
return false;
|
279
|
-
}
|
280
|
-
if (acceptInput) {
|
281
|
-
if (keyCode in keyCodes) {
|
282
|
-
cancelKeyPress = keyCode;
|
283
|
-
(keyCodes[keyCode])();
|
284
|
-
return false;
|
285
|
-
} else if (e.ctrlKey && keyCode in ctrlCodes) {
|
286
|
-
cancelKeyPress = keyCode;
|
287
|
-
(ctrlCodes[keyCode])();
|
288
|
-
return false;
|
289
|
-
} else if (e.altKey && keyCode in altCodes) {
|
290
|
-
cancelKeyPress = keyCode;
|
291
|
-
(altCodes[keyCode])();
|
292
|
-
return false;
|
293
|
-
}
|
294
|
-
}
|
295
|
-
});
|
296
|
-
|
297
|
-
////////////////////////////////////////////////////////////////////////
|
298
|
-
// Handle key press
|
299
|
-
typer.keypress(function(e){
|
300
|
-
var keyCode = e.keyCode || e.which;
|
301
|
-
if (isIgnorableKey(e)) {
|
302
|
-
return false;
|
303
|
-
}
|
304
|
-
// C-v: don't insert on paste event
|
305
|
-
if ((e.ctrlKey || e.metaKey) && String.fromCharCode(keyCode).toLowerCase() == 'v') {
|
306
|
-
return true;
|
307
|
-
}
|
308
|
-
if (acceptInput && cancelKeyPress != keyCode && keyCode >= 32){
|
309
|
-
if (cancelKeyPress) return false;
|
310
|
-
if (
|
311
|
-
typeof config.charInsertTrigger == 'undefined' || (
|
312
|
-
typeof config.charInsertTrigger == 'function' &&
|
313
|
-
config.charInsertTrigger(keyCode,promptText)
|
314
|
-
)
|
315
|
-
){
|
316
|
-
typer.consoleInsert(keyCode);
|
317
|
-
}
|
318
|
-
}
|
319
|
-
if (isWebkit) return false;
|
320
|
-
});
|
321
|
-
|
322
|
-
function isIgnorableKey(e) {
|
323
|
-
// for now just filter alt+tab that we receive on some platforms when
|
324
|
-
// user switches windows (goes away from the browser)
|
325
|
-
return ((e.keyCode == keyCodes.tab || e.keyCode == 192) && e.altKey);
|
326
|
-
};
|
327
|
-
|
328
|
-
////////////////////////////////////////////////////////////////////////
|
329
|
-
// Rotate through the command history
|
330
|
-
function rotateHistory(n){
|
331
|
-
if (history.length == 0) return;
|
332
|
-
ringn += n;
|
333
|
-
if (ringn < 0) ringn = history.length;
|
334
|
-
else if (ringn > history.length) ringn = 0;
|
335
|
-
var prevText = promptText;
|
336
|
-
if (ringn == 0) {
|
337
|
-
promptText = restoreText;
|
338
|
-
} else {
|
339
|
-
promptText = history[ringn - 1];
|
340
|
-
}
|
341
|
-
if (config.historyPreserveColumn) {
|
342
|
-
if (promptText.length < column + 1) {
|
343
|
-
column = promptText.length;
|
344
|
-
} else if (column == 0) {
|
345
|
-
column = promptText.length;
|
346
|
-
}
|
347
|
-
} else {
|
348
|
-
column = promptText.length;
|
349
|
-
}
|
350
|
-
updatePromptDisplay();
|
351
|
-
};
|
352
|
-
|
353
|
-
function previousHistory() {
|
354
|
-
rotateHistory(-1);
|
355
|
-
};
|
356
|
-
|
357
|
-
function nextHistory() {
|
358
|
-
rotateHistory(1);
|
359
|
-
};
|
360
|
-
|
361
|
-
// Add something to the history ring
|
362
|
-
function addToHistory(line){
|
363
|
-
history.push(line);
|
364
|
-
restoreText = '';
|
365
|
-
};
|
366
|
-
|
367
|
-
// Delete the character at the current position
|
368
|
-
function deleteCharAtPos(){
|
369
|
-
if (column < promptText.length){
|
370
|
-
promptText =
|
371
|
-
promptText.substring(0,column) +
|
372
|
-
promptText.substring(column+1);
|
373
|
-
restoreText = promptText;
|
374
|
-
return true;
|
375
|
-
} else return false;
|
376
|
-
};
|
377
|
-
|
378
|
-
function backDelete() {
|
379
|
-
if (moveColumn(-1)){
|
380
|
-
deleteCharAtPos();
|
381
|
-
updatePromptDisplay();
|
382
|
-
}
|
383
|
-
};
|
384
|
-
|
385
|
-
function forwardDelete() {
|
386
|
-
if (deleteCharAtPos()){
|
387
|
-
updatePromptDisplay();
|
388
|
-
}
|
389
|
-
};
|
390
|
-
|
391
|
-
function deleteUntilEnd() {
|
392
|
-
while(deleteCharAtPos()) {
|
393
|
-
updatePromptDisplay();
|
394
|
-
}
|
395
|
-
};
|
396
|
-
|
397
|
-
function deleteNextWord() {
|
398
|
-
// A word is defined within this context as a series of alphanumeric
|
399
|
-
// characters.
|
400
|
-
// Delete up to the next alphanumeric character
|
401
|
-
while(
|
402
|
-
column < promptText.length &&
|
403
|
-
!isCharAlphanumeric(promptText[column])
|
404
|
-
) {
|
405
|
-
deleteCharAtPos();
|
406
|
-
updatePromptDisplay();
|
407
|
-
}
|
408
|
-
// Then, delete until the next non-alphanumeric character
|
409
|
-
while(
|
410
|
-
column < promptText.length &&
|
411
|
-
isCharAlphanumeric(promptText[column])
|
412
|
-
) {
|
413
|
-
deleteCharAtPos();
|
414
|
-
updatePromptDisplay();
|
415
|
-
}
|
416
|
-
};
|
417
|
-
|
418
|
-
////////////////////////////////////////////////////////////////////////
|
419
|
-
// Validate command and trigger it if valid, or show a validation error
|
420
|
-
function commandTrigger() {
|
421
|
-
var line = promptText;
|
422
|
-
if (typeof config.commandValidate == 'function') {
|
423
|
-
var ret = config.commandValidate(line);
|
424
|
-
if (ret == true || ret == false) {
|
425
|
-
if (ret) {
|
426
|
-
handleCommand();
|
427
|
-
}
|
428
|
-
} else {
|
429
|
-
commandResult(ret,"jquery-console-message-error");
|
430
|
-
}
|
431
|
-
} else {
|
432
|
-
handleCommand();
|
433
|
-
}
|
434
|
-
};
|
435
|
-
|
436
|
-
// Scroll to the bottom of the view
|
437
|
-
function scrollToBottom() {
|
438
|
-
var version = jQuery.fn.jquery.split('.');
|
439
|
-
var major = parseInt(version[0]);
|
440
|
-
var minor = parseInt(version[1]);
|
441
|
-
|
442
|
-
// check if we're using jquery > 1.6
|
443
|
-
if ((major == 1 && minor > 6) || major > 1) {
|
444
|
-
inner.prop({ scrollTop: inner.prop("scrollHeight") });
|
445
|
-
}
|
446
|
-
else {
|
447
|
-
inner.attr({ scrollTop: inner.attr("scrollHeight") });
|
448
|
-
}
|
449
|
-
};
|
450
|
-
|
451
|
-
function cancelExecution() {
|
452
|
-
if(typeof config.cancelHandle == 'function') {
|
453
|
-
config.cancelHandle();
|
454
|
-
}
|
455
|
-
}
|
456
|
-
|
457
|
-
////////////////////////////////////////////////////////////////////////
|
458
|
-
// Handle a command
|
459
|
-
function handleCommand() {
|
460
|
-
if (typeof config.commandHandle == 'function') {
|
461
|
-
disableInput();
|
462
|
-
addToHistory(promptText);
|
463
|
-
var text = promptText;
|
464
|
-
if (extern.continuedPrompt) {
|
465
|
-
if (continuedText)
|
466
|
-
continuedText += '\n' + promptText;
|
467
|
-
else continuedText = promptText;
|
468
|
-
} else continuedText = undefined;
|
469
|
-
if (continuedText) text = continuedText;
|
470
|
-
var ret = config.commandHandle(text,function(msgs){
|
471
|
-
commandResult(msgs);
|
472
|
-
});
|
473
|
-
if (extern.continuedPrompt && !continuedText)
|
474
|
-
continuedText = promptText;
|
475
|
-
if (typeof ret == 'boolean') {
|
476
|
-
if (ret) {
|
477
|
-
// Command succeeded without a result.
|
478
|
-
commandResult();
|
479
|
-
} else {
|
480
|
-
commandResult(
|
481
|
-
'Command failed.',
|
482
|
-
"jquery-console-message-error"
|
483
|
-
);
|
484
|
-
}
|
485
|
-
} else if (typeof ret == "string") {
|
486
|
-
commandResult(ret,"jquery-console-message-success");
|
487
|
-
} else if (typeof ret == 'object' && ret.length) {
|
488
|
-
commandResult(ret);
|
489
|
-
} else if (extern.continuedPrompt) {
|
490
|
-
commandResult();
|
491
|
-
}
|
492
|
-
}
|
493
|
-
};
|
494
|
-
|
495
|
-
////////////////////////////////////////////////////////////////////////
|
496
|
-
// Disable input
|
497
|
-
function disableInput() {
|
498
|
-
acceptInput = false;
|
499
|
-
};
|
500
|
-
|
501
|
-
// Enable input
|
502
|
-
function enableInput() {
|
503
|
-
acceptInput = true;
|
504
|
-
}
|
505
|
-
|
506
|
-
////////////////////////////////////////////////////////////////////////
|
507
|
-
// Reset the prompt in invalid command
|
508
|
-
function commandResult(msg,className) {
|
509
|
-
column = -1;
|
510
|
-
updatePromptDisplay();
|
511
|
-
if (typeof msg == 'string') {
|
512
|
-
message(msg,className);
|
513
|
-
} else if ($.isArray(msg)) {
|
514
|
-
for (var x in msg) {
|
515
|
-
var ret = msg[x];
|
516
|
-
message(ret.msg,ret.className);
|
517
|
-
}
|
518
|
-
} else { // Assume it's a DOM node or jQuery object.
|
519
|
-
inner.append(msg);
|
520
|
-
}
|
521
|
-
newPromptBox();
|
522
|
-
};
|
523
|
-
|
524
|
-
////////////////////////////////////////////////////////////////////////
|
525
|
-
// Display a message
|
526
|
-
function message(msg,className) {
|
527
|
-
var mesg = $('<div class="jquery-console-message"></div>');
|
528
|
-
if (className) mesg.addClass(className);
|
529
|
-
mesg.filledText(msg).hide();
|
530
|
-
inner.append(mesg);
|
531
|
-
mesg.show();
|
532
|
-
};
|
533
|
-
|
534
|
-
////////////////////////////////////////////////////////////////////////
|
535
|
-
// Handle normal character insertion
|
536
|
-
// data can either be a number, which will be interpreted as the
|
537
|
-
// numeric value of a single character, or a string
|
538
|
-
typer.consoleInsert = function(data){
|
539
|
-
// TODO: remove redundant indirection
|
540
|
-
var text = isNaN(data) ? data : String.fromCharCode(data);
|
541
|
-
var before = promptText.substring(0,column);
|
542
|
-
var after = promptText.substring(column);
|
543
|
-
promptText = before + text + after;
|
544
|
-
moveColumn(text.length);
|
545
|
-
restoreText = promptText;
|
546
|
-
updatePromptDisplay();
|
547
|
-
};
|
548
|
-
|
549
|
-
////////////////////////////////////////////////////////////////////////
|
550
|
-
// Move to another column relative to this one
|
551
|
-
// Negative means go back, positive means go forward.
|
552
|
-
function moveColumn(n){
|
553
|
-
if (column + n >= 0 && column + n <= promptText.length){
|
554
|
-
column += n;
|
555
|
-
return true;
|
556
|
-
} else return false;
|
557
|
-
};
|
558
|
-
|
559
|
-
function moveForward() {
|
560
|
-
if(moveColumn(1)) {
|
561
|
-
updatePromptDisplay();
|
562
|
-
return true;
|
563
|
-
}
|
564
|
-
return false;
|
565
|
-
};
|
566
|
-
|
567
|
-
function moveBackward() {
|
568
|
-
if(moveColumn(-1)) {
|
569
|
-
updatePromptDisplay();
|
570
|
-
return true;
|
571
|
-
}
|
572
|
-
return false;
|
573
|
-
};
|
574
|
-
|
575
|
-
function moveToStart() {
|
576
|
-
if (moveColumn(-column))
|
577
|
-
updatePromptDisplay();
|
578
|
-
};
|
579
|
-
|
580
|
-
function moveToEnd() {
|
581
|
-
if (moveColumn(promptText.length-column))
|
582
|
-
updatePromptDisplay();
|
583
|
-
};
|
584
|
-
|
585
|
-
function moveToNextWord() {
|
586
|
-
while(
|
587
|
-
column < promptText.length &&
|
588
|
-
!isCharAlphanumeric(promptText[column]) &&
|
589
|
-
moveForward()
|
590
|
-
) {}
|
591
|
-
while(
|
592
|
-
column < promptText.length &&
|
593
|
-
isCharAlphanumeric(promptText[column]) &&
|
594
|
-
moveForward()
|
595
|
-
) {}
|
596
|
-
};
|
597
|
-
|
598
|
-
function moveToPreviousWord() {
|
599
|
-
// Move backward until we find the first alphanumeric
|
600
|
-
while(
|
601
|
-
column -1 >= 0 &&
|
602
|
-
!isCharAlphanumeric(promptText[column-1]) &&
|
603
|
-
moveBackward()
|
604
|
-
) {}
|
605
|
-
// Move until we find the first non-alphanumeric
|
606
|
-
while(
|
607
|
-
column -1 >= 0 &&
|
608
|
-
isCharAlphanumeric(promptText[column-1]) &&
|
609
|
-
moveBackward()
|
610
|
-
) {}
|
611
|
-
};
|
612
|
-
|
613
|
-
function isCharAlphanumeric(charToTest) {
|
614
|
-
if(typeof charToTest == 'string') {
|
615
|
-
var code = charToTest.charCodeAt();
|
616
|
-
return (code >= 'A'.charCodeAt() && code <= 'Z'.charCodeAt()) ||
|
617
|
-
(code >= 'a'.charCodeAt() && code <= 'z'.charCodeAt()) ||
|
618
|
-
(code >= '0'.charCodeAt() && code <= '9'.charCodeAt());
|
619
|
-
}
|
620
|
-
return false;
|
621
|
-
};
|
622
|
-
|
623
|
-
function doComplete() {
|
624
|
-
if(typeof config.completeHandle == 'function') {
|
625
|
-
var completions = config.completeHandle(promptText);
|
626
|
-
var len = completions.length;
|
627
|
-
if (len === 1) {
|
628
|
-
extern.promptText(promptText + completions[0]);
|
629
|
-
} else if (len > 1 && config.cols) {
|
630
|
-
var prompt = promptText;
|
631
|
-
// Compute the number of rows that will fit in the width
|
632
|
-
var max = 0;
|
633
|
-
for (var i = 0;i < len;i++) {
|
634
|
-
max = Math.max(max, completions[i].length);
|
635
|
-
}
|
636
|
-
max += 2;
|
637
|
-
var n = Math.floor(config.cols / max);
|
638
|
-
var buffer = "";
|
639
|
-
var col = 0;
|
640
|
-
for (i = 0;i < len;i++) {
|
641
|
-
var completion = completions[i];
|
642
|
-
buffer += completions[i];
|
643
|
-
for (var j = completion.length;j < max;j++) {
|
644
|
-
buffer += " ";
|
645
|
-
}
|
646
|
-
if (++col >= n) {
|
647
|
-
buffer += "\n";
|
648
|
-
col = 0;
|
649
|
-
}
|
650
|
-
}
|
651
|
-
commandResult(buffer,"jquery-console-message-value");
|
652
|
-
extern.promptText(prompt);
|
653
|
-
}
|
654
|
-
}
|
655
|
-
};
|
656
|
-
|
657
|
-
function doNothing() {};
|
658
|
-
|
659
|
-
extern.promptText = function(text){
|
660
|
-
if (typeof text === 'string') {
|
661
|
-
promptText = text;
|
662
|
-
column = promptText.length;
|
663
|
-
updatePromptDisplay();
|
664
|
-
}
|
665
|
-
return promptText;
|
666
|
-
};
|
667
|
-
|
668
|
-
////////////////////////////////////////////////////////////////////////
|
669
|
-
// Update the prompt display
|
670
|
-
function updatePromptDisplay(){
|
671
|
-
var line = promptText;
|
672
|
-
var html = '';
|
673
|
-
if (column > 0 && line == ''){
|
674
|
-
// When we have an empty line just display a cursor.
|
675
|
-
html = cursor;
|
676
|
-
} else if (column == promptText.length){
|
677
|
-
// We're at the end of the line, so we need to display
|
678
|
-
// the text *and* cursor.
|
679
|
-
html = htmlEncode(line) + cursor;
|
680
|
-
} else {
|
681
|
-
// Grab the current character, if there is one, and
|
682
|
-
// make it the current cursor.
|
683
|
-
var before = line.substring(0, column);
|
684
|
-
var current = line.substring(column,column+1);
|
685
|
-
if (current){
|
686
|
-
current =
|
687
|
-
'<span class="jquery-console-cursor">' +
|
688
|
-
htmlEncode(current) +
|
689
|
-
'</span>';
|
690
|
-
}
|
691
|
-
var after = line.substring(column+1);
|
692
|
-
html = htmlEncode(before) + current + htmlEncode(after);
|
693
|
-
}
|
694
|
-
prompt.html(html);
|
695
|
-
scrollToBottom();
|
696
|
-
};
|
697
|
-
|
698
|
-
// Simple HTML encoding
|
699
|
-
// Simply replace '<', '>' and '&'
|
700
|
-
// TODO: Use jQuery's .html() trick, or grab a proper, fast
|
701
|
-
// HTML encoder.
|
702
|
-
function htmlEncode(text){
|
703
|
-
return (
|
704
|
-
text.replace(/&/g,'&')
|
705
|
-
.replace(/</g,'<')
|
706
|
-
.replace(/</g,'<')
|
707
|
-
.replace(/ /g,' ')
|
708
|
-
.replace(/\n/g,'<br />')
|
709
|
-
);
|
710
|
-
};
|
711
|
-
|
712
|
-
return extern;
|
713
|
-
};
|
714
|
-
// Simple utility for printing messages
|
715
|
-
$.fn.filledText = function(txt){
|
716
|
-
$(this).text(txt);
|
717
|
-
$(this).html($(this).html().replace(/\n/g,'<br/>'));
|
718
|
-
return this;
|
719
|
-
};
|
720
|
-
|
721
|
-
// Alternative method for focus without scrolling
|
722
|
-
$.fn.focusWithoutScrolling = function(){
|
723
|
-
var x = window.scrollX, y = window.scrollY;
|
724
|
-
$(this).focus();
|
725
|
-
window.scrollTo(x, y);
|
726
|
-
};
|
727
|
-
})(jQuery);
|