parade 0.8.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.
- data/LICENSE +21 -0
- data/README.md +542 -0
- data/Rakefile +15 -0
- data/bin/parade +138 -0
- data/lib/parade.rb +43 -0
- data/lib/parade/commands/commands.rb +84 -0
- data/lib/parade/commands/generate_outline.rb +34 -0
- data/lib/parade/commands/generate_presentation.rb +34 -0
- data/lib/parade/commands/generate_rackup.rb +32 -0
- data/lib/parade/commands/html_output.rb +47 -0
- data/lib/parade/commands/render_from_template.rb +50 -0
- data/lib/parade/commands/static_html.rb +38 -0
- data/lib/parade/commands/static_pdf.rb +39 -0
- data/lib/parade/commands/unknown.rb +23 -0
- data/lib/parade/features/live_ruby.rb +18 -0
- data/lib/parade/features/pdf_presentation.rb +24 -0
- data/lib/parade/features/preshow.rb +11 -0
- data/lib/parade/helpers/encode_image.rb +24 -0
- data/lib/parade/helpers/template_generator.rb +130 -0
- data/lib/parade/metadata.rb +73 -0
- data/lib/parade/metadata/assignment.rb +38 -0
- data/lib/parade/metadata/css_classes.rb +22 -0
- data/lib/parade/metadata/html_id.rb +35 -0
- data/lib/parade/metadata/template.rb +31 -0
- data/lib/parade/parsers/dsl.rb +138 -0
- data/lib/parade/parsers/dsl_file_parser.rb +17 -0
- data/lib/parade/parsers/json_file_parser.rb +67 -0
- data/lib/parade/parsers/markdown_image_paths.rb +44 -0
- data/lib/parade/parsers/markdown_slide_splitter.rb +63 -0
- data/lib/parade/parsers/presentation_directory_parser.rb +36 -0
- data/lib/parade/parsers/presentation_file_parser.rb +27 -0
- data/lib/parade/parsers/presentation_filepath_parser.rb +35 -0
- data/lib/parade/parsers/slides_file_content_parser.rb +27 -0
- data/lib/parade/renderers/columns_renderer.rb +68 -0
- data/lib/parade/renderers/command_line_renderer.rb +142 -0
- data/lib/parade/renderers/html_with_pygments.rb +42 -0
- data/lib/parade/renderers/inline_images.rb +31 -0
- data/lib/parade/renderers/special_paragraph_renderer.rb +23 -0
- data/lib/parade/renderers/update_image_paths.rb +75 -0
- data/lib/parade/section.rb +183 -0
- data/lib/parade/server.rb +139 -0
- data/lib/parade/slide.rb +128 -0
- data/lib/parade/version.rb +3 -0
- data/lib/public/css/960.css +653 -0
- data/lib/public/css/fg.menu.css +114 -0
- data/lib/public/css/ghf_marked.css +180 -0
- data/lib/public/css/jquery-terminal.css +73 -0
- data/lib/public/css/onepage.css +62 -0
- data/lib/public/css/parade.css +450 -0
- data/lib/public/css/pdf.css +13 -0
- data/lib/public/css/reset.css +53 -0
- data/lib/public/css/spinner_bar.gif +0 -0
- data/lib/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
- data/lib/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
- data/lib/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
- data/lib/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
- data/lib/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/public/css/theme/ui.accordion.css +9 -0
- data/lib/public/css/theme/ui.all.css +2 -0
- data/lib/public/css/theme/ui.base.css +9 -0
- data/lib/public/css/theme/ui.core.css +37 -0
- data/lib/public/css/theme/ui.datepicker.css +62 -0
- data/lib/public/css/theme/ui.dialog.css +13 -0
- data/lib/public/css/theme/ui.progressbar.css +4 -0
- data/lib/public/css/theme/ui.resizable.css +13 -0
- data/lib/public/css/theme/ui.slider.css +17 -0
- data/lib/public/css/theme/ui.tabs.css +9 -0
- data/lib/public/css/theme/ui.theme.css +245 -0
- data/lib/public/favicon.ico +0 -0
- data/lib/public/js/coffee-script.js +8 -0
- data/lib/public/js/fg.menu.js +645 -0
- data/lib/public/js/jTypeWriter.js +26 -0
- data/lib/public/js/jquery-1.4.2.js +6240 -0
- data/lib/public/js/jquery-print.js +109 -0
- data/lib/public/js/jquery-pubsub.js +27 -0
- data/lib/public/js/jquery-terminal.js +2712 -0
- data/lib/public/js/jquery.batchImageLoad.js +56 -0
- data/lib/public/js/jquery.cycle.all.js +1284 -0
- data/lib/public/js/keyboard.js +733 -0
- data/lib/public/js/parade-code-execution.js +122 -0
- data/lib/public/js/parade-command-input.js +16 -0
- data/lib/public/js/parade-command-visor.js +92 -0
- data/lib/public/js/parade-keyboard-input.js +54 -0
- data/lib/public/js/parade.js +675 -0
- data/lib/public/js/spine.js +904 -0
- data/lib/templates/config.ru.erb +4 -0
- data/lib/templates/showoff.erb +27 -0
- data/lib/templates/slides.md.erb +25 -0
- data/lib/views/header.erb +73 -0
- data/lib/views/index.erb +53 -0
- data/lib/views/inline_css.erb +3 -0
- data/lib/views/inline_js.erb +3 -0
- data/lib/views/onepage.erb +17 -0
- data/lib/views/pdf.erb +17 -0
- data/lib/views/slide.erb +5 -0
- metadata +317 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
(function($) {
|
|
2
|
+
|
|
3
|
+
function print_array(obj, opts) {
|
|
4
|
+
var result = [];
|
|
5
|
+
for (var i = 0; i < Math.min(opts.max_array, obj.length); i++)
|
|
6
|
+
result.push($.print(obj[i], $.extend({}, opts, { max_array: 3, max_string: 40 })));
|
|
7
|
+
|
|
8
|
+
if (obj.length > opts.max_array)
|
|
9
|
+
result.push((obj.length - opts.max_array) + ' more...');
|
|
10
|
+
if (result.length == 0) return "[]"
|
|
11
|
+
return "[ " + result.join(", ") + " ]";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function print_element(obj) {
|
|
15
|
+
if (obj.nodeType == 1) {
|
|
16
|
+
var result = [];
|
|
17
|
+
var properties = [ 'className', 'id' ];
|
|
18
|
+
var extra = {
|
|
19
|
+
'input': ['type', 'name', 'value'],
|
|
20
|
+
'a': ['href', 'target'],
|
|
21
|
+
'form': ['method', 'action'],
|
|
22
|
+
'script': ['src'],
|
|
23
|
+
'link': ['href'],
|
|
24
|
+
'img': ['src']
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
$.each(properties.concat(extra[obj.tagName.toLowerCase()] || []), function(){
|
|
28
|
+
if (obj[this])
|
|
29
|
+
result.push(' ' + this.replace('className', 'class') + "=" + $.print(obj[this]))
|
|
30
|
+
});
|
|
31
|
+
return "<" + obj.tagName.toLowerCase()
|
|
32
|
+
+ result.join('') + ">";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function print_object(obj, opts) {
|
|
37
|
+
var seen = opts.seen || [ obj ];
|
|
38
|
+
|
|
39
|
+
var result = [], key, value;
|
|
40
|
+
for (var k in obj) {
|
|
41
|
+
if (obj.hasOwnProperty(k) && $.inArray(obj[k], seen) < 0) {
|
|
42
|
+
seen.push(obj[k]);
|
|
43
|
+
value = $.print(obj[k], $.extend({}, opts, { max_array: 6, max_string: 40, seen: seen }));
|
|
44
|
+
} else
|
|
45
|
+
value = "...";
|
|
46
|
+
result.push(k + ": " + value);
|
|
47
|
+
}
|
|
48
|
+
if (result.length == 0) return "{}";
|
|
49
|
+
return "{ " + result.join(", ") + " }";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function print_string(value, opts) {
|
|
53
|
+
var character_substitutions = {
|
|
54
|
+
'\b': '\\b',
|
|
55
|
+
'\t': '\\t',
|
|
56
|
+
'\n': '\\n',
|
|
57
|
+
'\f': '\\f',
|
|
58
|
+
'\r': '\\r',
|
|
59
|
+
'"' : '\\"',
|
|
60
|
+
'\\': '\\\\'
|
|
61
|
+
};
|
|
62
|
+
var r = /["\\\x00-\x1f\x7f-\x9f]/g;
|
|
63
|
+
|
|
64
|
+
var str = r.test(value)
|
|
65
|
+
? value.replace(r, function (a) {
|
|
66
|
+
var c = character_substitutions[a];
|
|
67
|
+
if (c) return c;
|
|
68
|
+
c = a.charCodeAt();
|
|
69
|
+
return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
|
|
70
|
+
})
|
|
71
|
+
: value ;
|
|
72
|
+
if (str.length > opts.max_string)
|
|
73
|
+
return str.slice(0, opts.max_string + 1) + '..."';
|
|
74
|
+
else
|
|
75
|
+
return str;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
$.print = function(obj, options) {
|
|
79
|
+
var opts = $.extend({}, { max_array: 10, max_string: 100 }, options);
|
|
80
|
+
|
|
81
|
+
if (typeof obj == 'undefined')
|
|
82
|
+
return "undefined";
|
|
83
|
+
else if (typeof obj == 'boolean')
|
|
84
|
+
return obj.toString();
|
|
85
|
+
else if (typeof obj == 'number')
|
|
86
|
+
return obj.toString();
|
|
87
|
+
else if (!obj)
|
|
88
|
+
return "null";
|
|
89
|
+
else if (typeof obj == 'string')
|
|
90
|
+
return print_string(obj, opts);
|
|
91
|
+
else if (obj instanceof RegExp)
|
|
92
|
+
return obj.toString();
|
|
93
|
+
else if (obj instanceof Array || obj.callee || obj.item)
|
|
94
|
+
return print_array(obj, opts);
|
|
95
|
+
else if (typeof obj == 'function' || obj instanceof Function)
|
|
96
|
+
return obj.toString().match(/^([^)]*\))/)[1];
|
|
97
|
+
else if (obj.nodeType)
|
|
98
|
+
return print_element(obj);
|
|
99
|
+
else if (obj instanceof jQuery)
|
|
100
|
+
return "$(" + $.print(obj.get()) + ")";
|
|
101
|
+
else if (obj instanceof Error)
|
|
102
|
+
return print_object(obj, $.extend({}, options, { max_string: 200 }));
|
|
103
|
+
else if (obj instanceof Object)
|
|
104
|
+
return print_object(obj, opts);
|
|
105
|
+
else
|
|
106
|
+
return obj.toString().replace(/\n\s*/g, '');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
})(jQuery);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* jQuery Tiny Pub/Sub - v0.3 - 11/4/2010
|
|
3
|
+
* http://benalman.com/
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2010 "Cowboy" Ben Alman
|
|
6
|
+
* Dual licensed under the MIT and GPL licenses.
|
|
7
|
+
* http://benalman.com/about/license/
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
(function($){
|
|
11
|
+
|
|
12
|
+
var o = $({});
|
|
13
|
+
|
|
14
|
+
$.subscribe = function() {
|
|
15
|
+
o.bind.apply( o, arguments );
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
$.unsubscribe = function() {
|
|
19
|
+
o.unbind.apply( o, arguments );
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
$.publish = function() {
|
|
23
|
+
console.log("Publish: " + arguments[0]);
|
|
24
|
+
o.trigger.apply( o, arguments );
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
})(jQuery);
|
|
@@ -0,0 +1,2712 @@
|
|
|
1
|
+
/**@license
|
|
2
|
+
*| __ _____ ________ __
|
|
3
|
+
*| / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
|
|
4
|
+
*| __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
|
|
5
|
+
*| / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
|
|
6
|
+
*| \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
|
|
7
|
+
*| \/ /____/ version 0.4.22
|
|
8
|
+
* http://terminal.jcubic.pl
|
|
9
|
+
*
|
|
10
|
+
* Licensed under GNU LGPL Version 3 license
|
|
11
|
+
* Copyright (c) 2011-2012 Jakub Jankiewicz <http://jcubic.pl>
|
|
12
|
+
*
|
|
13
|
+
* Includes:
|
|
14
|
+
*
|
|
15
|
+
* Storage plugin Distributed under the MIT License
|
|
16
|
+
* Copyright (c) 2010 Dave Schindler
|
|
17
|
+
*
|
|
18
|
+
* jQuery Timers licenced with the WTFPL
|
|
19
|
+
* <http://jquery.offput.ca/every/>
|
|
20
|
+
*
|
|
21
|
+
* Cross-Browser Split 1.1.1
|
|
22
|
+
* Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
|
|
23
|
+
* Available under the MIT License
|
|
24
|
+
*
|
|
25
|
+
* Date: Thu, 15 Nov 2012 07:12:21 +0000
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
|
|
30
|
+
TODO:
|
|
31
|
+
add destroy method to terminal (cmd alrady have it)
|
|
32
|
+
|
|
33
|
+
add support for - $(...).each(function() { ... });
|
|
34
|
+
|
|
35
|
+
$.fn.pluginname = function(options) {
|
|
36
|
+
var settings = $.extend({}, $.fn.pluginname.defaultOptions, options);
|
|
37
|
+
|
|
38
|
+
return this.each(function() {
|
|
39
|
+
var $this = $(this);
|
|
40
|
+
});
|
|
41
|
+
$.fn.pluginname.defaultOptions = {
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
distinguish between paused and disabled
|
|
46
|
+
paused should block keydown in terminal it should disable command line
|
|
47
|
+
disable
|
|
48
|
+
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
(function($, undefined) {
|
|
54
|
+
"use strict";
|
|
55
|
+
|
|
56
|
+
// map object to object
|
|
57
|
+
$.omap = function(o, fn) {
|
|
58
|
+
var result = {};
|
|
59
|
+
$.each(o, function(k, v) {
|
|
60
|
+
result[k] = fn.call(o, k, v);
|
|
61
|
+
});
|
|
62
|
+
return result;
|
|
63
|
+
};
|
|
64
|
+
// debug function
|
|
65
|
+
function get_stack(caller) {
|
|
66
|
+
"use strict";
|
|
67
|
+
if (caller) {
|
|
68
|
+
return [caller.toString().match(/.*\n.*\n/)].
|
|
69
|
+
concat(get_stack(caller.caller));
|
|
70
|
+
} else {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ----------------------------------------
|
|
75
|
+
// START Storage plugin
|
|
76
|
+
// ----------------------------------------
|
|
77
|
+
// Private data
|
|
78
|
+
var isLS = typeof window.localStorage !== 'undefined';
|
|
79
|
+
// Private functions
|
|
80
|
+
function wls(n, v) {
|
|
81
|
+
var c;
|
|
82
|
+
if (typeof n === 'string' && typeof v === 'string') {
|
|
83
|
+
localStorage[n] = v;
|
|
84
|
+
return true;
|
|
85
|
+
} else if (typeof n === 'object' && typeof v === 'undefined') {
|
|
86
|
+
for (c in n) {
|
|
87
|
+
if (n.hasOwnProperty(c)) {
|
|
88
|
+
localStorage[c] = n[c];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
function wc(n, v) {
|
|
96
|
+
var dt, e, c;
|
|
97
|
+
dt = new Date();
|
|
98
|
+
dt.setTime(dt.getTime() + 31536000000);
|
|
99
|
+
e = '; expires=' + dt.toGMTString();
|
|
100
|
+
if (typeof n === 'string' && typeof v === 'string') {
|
|
101
|
+
document.cookie = n + '=' + v + e + '; path=/';
|
|
102
|
+
return true;
|
|
103
|
+
} else if (typeof n === 'object' && typeof v === 'undefined') {
|
|
104
|
+
for (c in n) {
|
|
105
|
+
if (n.hasOwnProperty(c)) {
|
|
106
|
+
document.cookie = c + '=' + n[c] + e + '; path=/';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
function rls(n) {
|
|
114
|
+
return localStorage[n];
|
|
115
|
+
}
|
|
116
|
+
function rc(n) {
|
|
117
|
+
var nn, ca, i, c;
|
|
118
|
+
nn = n + '=';
|
|
119
|
+
ca = document.cookie.split(';');
|
|
120
|
+
for (i = 0; i < ca.length; i++) {
|
|
121
|
+
c = ca[i];
|
|
122
|
+
while (c.charAt(0) === ' ') {
|
|
123
|
+
c = c.substring(1, c.length);
|
|
124
|
+
}
|
|
125
|
+
if (c.indexOf(nn) === 0) {
|
|
126
|
+
return c.substring(nn.length, c.length);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
function dls(n) {
|
|
132
|
+
return delete localStorage[n];
|
|
133
|
+
}
|
|
134
|
+
function dc(n) {
|
|
135
|
+
return wc(n, '', -1);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Public API
|
|
139
|
+
* $.Storage.set("name", "value")
|
|
140
|
+
* $.Storage.set({"name1":"value1", "name2":"value2", etc})
|
|
141
|
+
* $.Storage.get("name")
|
|
142
|
+
* $.Storage.remove("name")
|
|
143
|
+
*/
|
|
144
|
+
$.extend({
|
|
145
|
+
Storage: {
|
|
146
|
+
set: isLS ? wls : wc,
|
|
147
|
+
get: isLS ? rls : rc,
|
|
148
|
+
remove: isLS ? dls : dc
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
// ----------------------------------------
|
|
152
|
+
// END Storage plugin
|
|
153
|
+
// ----------------------------------------
|
|
154
|
+
// START jQuery Timers
|
|
155
|
+
// ----------------------------------------
|
|
156
|
+
jQuery.fn.extend({
|
|
157
|
+
everyTime: function(interval, label, fn, times, belay) {
|
|
158
|
+
return this.each(function() {
|
|
159
|
+
jQuery.timer.add(this, interval, label, fn, times, belay);
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
oneTime: function(interval, label, fn) {
|
|
163
|
+
return this.each(function() {
|
|
164
|
+
jQuery.timer.add(this, interval, label, fn, 1);
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
stopTime: function(label, fn) {
|
|
168
|
+
return this.each(function() {
|
|
169
|
+
jQuery.timer.remove(this, label, fn);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
jQuery.extend({
|
|
175
|
+
timer: {
|
|
176
|
+
guid: 1,
|
|
177
|
+
global: {},
|
|
178
|
+
regex: /^([0-9]+)\s*(.*s)?$/,
|
|
179
|
+
powers: {
|
|
180
|
+
// Yeah this is major overkill...
|
|
181
|
+
'ms': 1,
|
|
182
|
+
'cs': 10,
|
|
183
|
+
'ds': 100,
|
|
184
|
+
's': 1000,
|
|
185
|
+
'das': 10000,
|
|
186
|
+
'hs': 100000,
|
|
187
|
+
'ks': 1000000
|
|
188
|
+
},
|
|
189
|
+
timeParse: function(value) {
|
|
190
|
+
if (value === undefined || value === null) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
var result = this.regex.exec(jQuery.trim(value.toString()));
|
|
194
|
+
if (result[2]) {
|
|
195
|
+
var num = parseInt(result[1], 10);
|
|
196
|
+
var mult = this.powers[result[2]] || 1;
|
|
197
|
+
return num * mult;
|
|
198
|
+
} else {
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
add: function(element, interval, label, fn, times, belay) {
|
|
203
|
+
var counter = 0;
|
|
204
|
+
|
|
205
|
+
if (jQuery.isFunction(label)) {
|
|
206
|
+
if (!times) {
|
|
207
|
+
times = fn;
|
|
208
|
+
}
|
|
209
|
+
fn = label;
|
|
210
|
+
label = interval;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
interval = jQuery.timer.timeParse(interval);
|
|
214
|
+
|
|
215
|
+
if (typeof interval !== 'number' ||
|
|
216
|
+
isNaN(interval) ||
|
|
217
|
+
interval <= 0) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (times && times.constructor !== Number) {
|
|
221
|
+
belay = !!times;
|
|
222
|
+
times = 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
times = times || 0;
|
|
226
|
+
belay = belay || false;
|
|
227
|
+
|
|
228
|
+
if (!element.$timers) {
|
|
229
|
+
element.$timers = {};
|
|
230
|
+
}
|
|
231
|
+
if (!element.$timers[label]) {
|
|
232
|
+
element.$timers[label] = {};
|
|
233
|
+
}
|
|
234
|
+
fn.$timerID = fn.$timerID || this.guid++;
|
|
235
|
+
|
|
236
|
+
var handler = function() {
|
|
237
|
+
if (belay && handler.inProgress) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
handler.inProgress = true;
|
|
241
|
+
if ((++counter > times && times !== 0) ||
|
|
242
|
+
fn.call(element, counter) === false) {
|
|
243
|
+
jQuery.timer.remove(element, label, fn);
|
|
244
|
+
}
|
|
245
|
+
handler.inProgress = false;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
handler.$timerID = fn.$timerID;
|
|
249
|
+
|
|
250
|
+
if (!element.$timers[label][fn.$timerID]) {
|
|
251
|
+
element.$timers[label][fn.$timerID] = window.setInterval(handler, interval);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (!this.global[label]) {
|
|
255
|
+
this.global[label] = [];
|
|
256
|
+
}
|
|
257
|
+
this.global[label].push(element);
|
|
258
|
+
|
|
259
|
+
},
|
|
260
|
+
remove: function(element, label, fn) {
|
|
261
|
+
var timers = element.$timers, ret;
|
|
262
|
+
|
|
263
|
+
if (timers) {
|
|
264
|
+
|
|
265
|
+
if (!label) {
|
|
266
|
+
for (var lab in timers) {
|
|
267
|
+
if (timers.hasOwnProperty(lab)) {
|
|
268
|
+
this.remove(element, lab, fn);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} else if (timers[label]) {
|
|
272
|
+
if (fn) {
|
|
273
|
+
if (fn.$timerID) {
|
|
274
|
+
window.clearInterval(timers[label][fn.$timerID]);
|
|
275
|
+
delete timers[label][fn.$timerID];
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
for (var _fn in timers[label]) {
|
|
279
|
+
if (timers[label].hasOwnProperty(_fn)) {
|
|
280
|
+
window.clearInterval(timers[label][_fn]);
|
|
281
|
+
delete timers[label][_fn];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
for (ret in timers[label]) {
|
|
287
|
+
if (timers[label].hasOwnProperty(ret)) {
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (!ret) {
|
|
292
|
+
ret = null;
|
|
293
|
+
delete timers[label];
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
for (ret in timers) {
|
|
298
|
+
if (timers.hasOwnProperty(ret)) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (!ret) {
|
|
303
|
+
element.$timers = null;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
if (jQuery.browser.msie) {
|
|
311
|
+
jQuery(window).one('unload', function() {
|
|
312
|
+
var global = jQuery.timer.global;
|
|
313
|
+
for (var label in global) {
|
|
314
|
+
if (global.hasOwnProperty(label)) {
|
|
315
|
+
var els = global[label], i = els.length;
|
|
316
|
+
while (--i) {
|
|
317
|
+
jQuery.timer.remove(els[i], label);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
// ----------------------------------------
|
|
324
|
+
// START CROSS BROWSER SPLIT
|
|
325
|
+
// ----------------------------------------
|
|
326
|
+
|
|
327
|
+
(function(undef) {
|
|
328
|
+
|
|
329
|
+
// prevent double include
|
|
330
|
+
|
|
331
|
+
if (!String.prototype.split.toString().match(/\[native/)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
var nativeSplit = String.prototype.split,
|
|
336
|
+
compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
|
|
337
|
+
self;
|
|
338
|
+
|
|
339
|
+
self = function (str, separator, limit) {
|
|
340
|
+
// If `separator` is not a regex, use `nativeSplit`
|
|
341
|
+
if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
|
|
342
|
+
return nativeSplit.call(str, separator, limit);
|
|
343
|
+
}
|
|
344
|
+
var output = [],
|
|
345
|
+
flags = (separator.ignoreCase ? "i" : "") +
|
|
346
|
+
(separator.multiline ? "m" : "") +
|
|
347
|
+
(separator.extended ? "x" : "") + // Proposed for ES6
|
|
348
|
+
(separator.sticky ? "y" : ""), // Firefox 3+
|
|
349
|
+
lastLastIndex = 0,
|
|
350
|
+
// Make `global` and avoid `lastIndex` issues by working with a copy
|
|
351
|
+
separator2, match, lastIndex, lastLength;
|
|
352
|
+
separator = new RegExp(separator.source, flags + "g");
|
|
353
|
+
str += ""; // Type-convert
|
|
354
|
+
if (!compliantExecNpcg) {
|
|
355
|
+
// Doesn't need flags gy, but they don't hurt
|
|
356
|
+
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
|
|
357
|
+
}
|
|
358
|
+
/* Values for `limit`, per the spec:
|
|
359
|
+
* If undefined: 4294967295 // Math.pow(2, 32) - 1
|
|
360
|
+
* If 0, Infinity, or NaN: 0
|
|
361
|
+
* If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
|
|
362
|
+
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
|
|
363
|
+
* If other: Type-convert, then use the above rules
|
|
364
|
+
*/
|
|
365
|
+
// ? Math.pow(2, 32) - 1 : ToUint32(limit)
|
|
366
|
+
limit = limit === undef ? -1 >>> 0 : limit >>> 0;
|
|
367
|
+
while (match = separator.exec(str)) {
|
|
368
|
+
// `separator.lastIndex` is not reliable cross-browser
|
|
369
|
+
lastIndex = match.index + match[0].length;
|
|
370
|
+
if (lastIndex > lastLastIndex) {
|
|
371
|
+
output.push(str.slice(lastLastIndex, match.index));
|
|
372
|
+
// Fix browsers whose `exec` methods don't consistently return `undefined` for
|
|
373
|
+
// nonparticipating capturing groups
|
|
374
|
+
if (!compliantExecNpcg && match.length > 1) {
|
|
375
|
+
match[0].replace(separator2, function () {
|
|
376
|
+
for (var i = 1; i < arguments.length - 2; i++) {
|
|
377
|
+
if (arguments[i] === undef) {
|
|
378
|
+
match[i] = undef;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
if (match.length > 1 && match.index < str.length) {
|
|
384
|
+
Array.prototype.push.apply(output, match.slice(1));
|
|
385
|
+
}
|
|
386
|
+
lastLength = match[0].length;
|
|
387
|
+
lastLastIndex = lastIndex;
|
|
388
|
+
if (output.length >= limit) {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (separator.lastIndex === match.index) {
|
|
393
|
+
separator.lastIndex++; // Avoid an infinite loop
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (lastLastIndex === str.length) {
|
|
397
|
+
if (lastLength || !separator.test("")) {
|
|
398
|
+
output.push("");
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
output.push(str.slice(lastLastIndex));
|
|
402
|
+
}
|
|
403
|
+
return output.length > limit ? output.slice(0, limit) : output;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
// For convenience
|
|
407
|
+
String.prototype.split = function (separator, limit) {
|
|
408
|
+
return self(this, separator, limit);
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
return self;
|
|
412
|
+
|
|
413
|
+
})();
|
|
414
|
+
|
|
415
|
+
// -----------------------------------------------------------------------
|
|
416
|
+
/*
|
|
417
|
+
function decodeHTML(str) {
|
|
418
|
+
if (typeof str === 'string') {
|
|
419
|
+
str = str.replace(/&/g, '&');
|
|
420
|
+
str = str.replace(/</g, '<').replace(/>/g, '>');
|
|
421
|
+
str = str.replace(/	/g, '\t');
|
|
422
|
+
str = str.replace(/<br\/?>/g, '\n').replace(/ /g, ' ');
|
|
423
|
+
return str;
|
|
424
|
+
} else {
|
|
425
|
+
return '';
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
*/
|
|
429
|
+
//split string to array of strings with the same length
|
|
430
|
+
function str_parts(str, length) {
|
|
431
|
+
var result = [];
|
|
432
|
+
var len = str.length;
|
|
433
|
+
if (len < length) {
|
|
434
|
+
return [str];
|
|
435
|
+
}
|
|
436
|
+
for (var i = 0; i < len; i += length) {
|
|
437
|
+
result.push(str.substring(i, i + length));
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
// -----------------------------------------------------------------------
|
|
444
|
+
|
|
445
|
+
function skipFormattingCount(string) {
|
|
446
|
+
return $('<div>' + $.terminal.strip(string) + '</div>').text().length;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// -----------------------------------------------------------------------
|
|
450
|
+
function formattingCount(string) {
|
|
451
|
+
return string.length - skipFormattingCount(string);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// -----------------------------------------------------------------------
|
|
455
|
+
// CYCLE DATA STRUCTURE
|
|
456
|
+
// -----------------------------------------------------------------------
|
|
457
|
+
function Cycle(init) {
|
|
458
|
+
var data = init ? [init] : [];
|
|
459
|
+
var pos = 0;
|
|
460
|
+
$.extend(this, {
|
|
461
|
+
rotate: function() {
|
|
462
|
+
if (data.length === 1) {
|
|
463
|
+
return data[0];
|
|
464
|
+
} else {
|
|
465
|
+
if (pos === data.length - 1) {
|
|
466
|
+
pos = 0;
|
|
467
|
+
} else {
|
|
468
|
+
++pos;
|
|
469
|
+
}
|
|
470
|
+
return data[pos];
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
length: function() {
|
|
474
|
+
return data.length;
|
|
475
|
+
},
|
|
476
|
+
set: function(item) {
|
|
477
|
+
for (var i = data.length; i--;) {
|
|
478
|
+
if (data[i] === item) {
|
|
479
|
+
pos = i;
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
this.append(item);
|
|
484
|
+
},
|
|
485
|
+
front: function() {
|
|
486
|
+
return data[pos];
|
|
487
|
+
},
|
|
488
|
+
append: function(item) {
|
|
489
|
+
data.push(item);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
// -----------------------------------------------------------------------
|
|
494
|
+
// :: BCYCLE DATA STRUCTURE // Two way cycle
|
|
495
|
+
// -----------------------------------------------------------------------
|
|
496
|
+
function BCycle(init) {
|
|
497
|
+
var data = init instanceof Array ? init : init ? [init] : [];
|
|
498
|
+
var pos = 0;
|
|
499
|
+
$.extend(this, {
|
|
500
|
+
left: function() {
|
|
501
|
+
if (pos === 0) {
|
|
502
|
+
pos = data.length - 1;
|
|
503
|
+
} else {
|
|
504
|
+
--pos;
|
|
505
|
+
}
|
|
506
|
+
return data[pos];
|
|
507
|
+
},
|
|
508
|
+
right: function() {
|
|
509
|
+
if (pos === data.length - 1) {
|
|
510
|
+
pos = 0;
|
|
511
|
+
} else {
|
|
512
|
+
++pos;
|
|
513
|
+
}
|
|
514
|
+
return data[pos];
|
|
515
|
+
},
|
|
516
|
+
current: function() {
|
|
517
|
+
return data[pos];
|
|
518
|
+
},
|
|
519
|
+
data: function() {
|
|
520
|
+
return data;
|
|
521
|
+
},
|
|
522
|
+
length: function() {
|
|
523
|
+
return data.length;
|
|
524
|
+
},
|
|
525
|
+
reset: function() {
|
|
526
|
+
pos = 0;
|
|
527
|
+
},
|
|
528
|
+
append: function(item) {
|
|
529
|
+
data.push(item);
|
|
530
|
+
this.reset();
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
// -----------------------------------------------------------------------
|
|
535
|
+
// :: STACK DATA STRUCTURE
|
|
536
|
+
// -----------------------------------------------------------------------
|
|
537
|
+
function Stack(init) {
|
|
538
|
+
var data = init ? [init] : [];
|
|
539
|
+
$.extend(this, {
|
|
540
|
+
size: function() {
|
|
541
|
+
return data.length;
|
|
542
|
+
},
|
|
543
|
+
pop: function() {
|
|
544
|
+
if (data.length === 0) {
|
|
545
|
+
return null;
|
|
546
|
+
} else {
|
|
547
|
+
var value = data[data.length - 1];
|
|
548
|
+
data = data.slice(0, data.length - 1);
|
|
549
|
+
return value;
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
push: function(value) {
|
|
553
|
+
data = data.concat([value]);
|
|
554
|
+
return value;
|
|
555
|
+
},
|
|
556
|
+
top: function() {
|
|
557
|
+
return data.length > 0 ? data[data.length - 1] : null;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
// serialize object myself (biwascheme or prototype library do something
|
|
562
|
+
// wiked with JSON serialization for Arrays)
|
|
563
|
+
$.json_stringify = function(object, level) {
|
|
564
|
+
var result = '', i;
|
|
565
|
+
level = level === undefined ? 1 : level;
|
|
566
|
+
var type = typeof object;
|
|
567
|
+
switch (type) {
|
|
568
|
+
case 'function':
|
|
569
|
+
result += object;
|
|
570
|
+
break;
|
|
571
|
+
case 'boolean':
|
|
572
|
+
result += object ? 'true' : 'false';
|
|
573
|
+
break;
|
|
574
|
+
case 'object':
|
|
575
|
+
if (object === null) {
|
|
576
|
+
result += 'null';
|
|
577
|
+
} else if (object instanceof Array) {
|
|
578
|
+
result += '[';
|
|
579
|
+
var len = object.length;
|
|
580
|
+
for (i = 0; i < len - 1; ++i) {
|
|
581
|
+
result += $.json_stringify(object[i], level + 1);
|
|
582
|
+
}
|
|
583
|
+
result += $.json_stringify(object[len - 1], level + 1) + ']';
|
|
584
|
+
} else {
|
|
585
|
+
result += '{';
|
|
586
|
+
for (var property in object) {
|
|
587
|
+
if (object.hasOwnProperty(property)) {
|
|
588
|
+
result += '"' + property + '":' +
|
|
589
|
+
$.json_stringify(object[property], level + 1);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
result += '}';
|
|
593
|
+
}
|
|
594
|
+
break;
|
|
595
|
+
case 'string':
|
|
596
|
+
var str = object;
|
|
597
|
+
var repl = {
|
|
598
|
+
'\\\\': '\\\\',
|
|
599
|
+
'"': '\\"',
|
|
600
|
+
'/': '\\/',
|
|
601
|
+
'\\n': '\\n',
|
|
602
|
+
'\\r': '\\r',
|
|
603
|
+
'\\t': '\\t'};
|
|
604
|
+
for (i in repl) {
|
|
605
|
+
if (repl.hasOwnProperty(i)) {
|
|
606
|
+
str = str.replace(new RegExp(i, 'g'), repl[i]);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
result += '"' + str + '"';
|
|
610
|
+
break;
|
|
611
|
+
case 'number':
|
|
612
|
+
result += String(object);
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
result += (level > 1 ? ',' : '');
|
|
616
|
+
// quick hacks below
|
|
617
|
+
if (level === 1) {
|
|
618
|
+
// fix last comma
|
|
619
|
+
result = result.replace(/,([\]}])/g, '$1');
|
|
620
|
+
}
|
|
621
|
+
// fix comma before array or object
|
|
622
|
+
return result.replace(/([\[{]),/g, '$1');
|
|
623
|
+
};
|
|
624
|
+
// -----------------------------------------------------------------------
|
|
625
|
+
// :: HISTORY CLASS
|
|
626
|
+
// -----------------------------------------------------------------------
|
|
627
|
+
function History(name) {
|
|
628
|
+
var enabled = true;
|
|
629
|
+
if (typeof name === 'string' && name !== '') {
|
|
630
|
+
name += '_';
|
|
631
|
+
}
|
|
632
|
+
var data = $.Storage.get(name + 'commands');
|
|
633
|
+
var bc = new BCycle(data ? eval('(' + data + ')') : ['']);
|
|
634
|
+
|
|
635
|
+
$.extend(this, {
|
|
636
|
+
append: function(item) {
|
|
637
|
+
if (enabled) {
|
|
638
|
+
bc.append(item);
|
|
639
|
+
$.Storage.set(name + 'commands', $.json_stringify(bc.data()));
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
data: function() {
|
|
643
|
+
return bc.data();
|
|
644
|
+
},
|
|
645
|
+
next: function() {
|
|
646
|
+
return bc.right();
|
|
647
|
+
},
|
|
648
|
+
last: function() {
|
|
649
|
+
bc.reset();
|
|
650
|
+
},
|
|
651
|
+
previous: function() {
|
|
652
|
+
return bc.left();
|
|
653
|
+
},
|
|
654
|
+
clear: function() {
|
|
655
|
+
bc = new BCycle();
|
|
656
|
+
$.Storage.remove(name + 'commands');
|
|
657
|
+
},
|
|
658
|
+
enable: function() {
|
|
659
|
+
enabled = true;
|
|
660
|
+
},
|
|
661
|
+
disable: function() {
|
|
662
|
+
enabled = false;
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
// -----------------------------------------------------------------------
|
|
667
|
+
// :: COMMAND LINE PLUGIN
|
|
668
|
+
// -----------------------------------------------------------------------
|
|
669
|
+
$.fn.cmd = function(options) {
|
|
670
|
+
var self = this;
|
|
671
|
+
self.addClass('cmd');
|
|
672
|
+
self.append('<span class="prompt"></span><span></span>' +
|
|
673
|
+
'<span class="cursor"> </span><span></span>');
|
|
674
|
+
var clip = $('<textarea/>').addClass('clipboard').appendTo(self);
|
|
675
|
+
if (options.width) {
|
|
676
|
+
self.width(options.width);
|
|
677
|
+
}
|
|
678
|
+
var num_chars; // calculates by draw_prompt
|
|
679
|
+
var prompt_len;
|
|
680
|
+
var reverse_search = false;
|
|
681
|
+
var reverse_search_string = '';
|
|
682
|
+
var reverse_search_position = null;
|
|
683
|
+
var backup_prompt;
|
|
684
|
+
var mask = options.mask || false;
|
|
685
|
+
var command = '';
|
|
686
|
+
var position = 0;
|
|
687
|
+
var prompt;
|
|
688
|
+
var enabled = options.enabled;
|
|
689
|
+
var name, history;
|
|
690
|
+
var cursor = self.find('.cursor');
|
|
691
|
+
|
|
692
|
+
function blink(i) {
|
|
693
|
+
cursor.toggleClass('inverted');
|
|
694
|
+
}
|
|
695
|
+
function draw_reverse_prompt() {
|
|
696
|
+
prompt = "(reverse-i-search)`" + reverse_search_string + "': ";
|
|
697
|
+
draw_prompt();
|
|
698
|
+
}
|
|
699
|
+
function clear_reverse_state() {
|
|
700
|
+
prompt = backup_prompt;
|
|
701
|
+
reverse_search = false;
|
|
702
|
+
reverse_search_position = null;
|
|
703
|
+
reverse_search_string = '';
|
|
704
|
+
}
|
|
705
|
+
// if next is not defined or false it search for first item from the end
|
|
706
|
+
// if true it search for next item
|
|
707
|
+
function reverse_history_search(next) {
|
|
708
|
+
var history_data = history.data();
|
|
709
|
+
var regex = new RegExp('^' + reverse_search_string);
|
|
710
|
+
var len = history_data.length;
|
|
711
|
+
if (next && reverse_search_position > 0) {
|
|
712
|
+
len -= reverse_search_position;
|
|
713
|
+
}
|
|
714
|
+
for (var i=len; i--;) {
|
|
715
|
+
if (regex.test(history_data[i])) {
|
|
716
|
+
reverse_search_position = history_data.length - i;
|
|
717
|
+
position = 0;
|
|
718
|
+
self.set(history_data[i], true);
|
|
719
|
+
redraw();
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
function change_num_chars() {
|
|
726
|
+
var W = self.width();
|
|
727
|
+
var w = cursor.innerWidth();
|
|
728
|
+
num_chars = Math.floor(W / w);
|
|
729
|
+
}
|
|
730
|
+
function str_repeat(str, n) {
|
|
731
|
+
var result = '';
|
|
732
|
+
for (var i = n; i--;) {
|
|
733
|
+
result += str;
|
|
734
|
+
}
|
|
735
|
+
return result;
|
|
736
|
+
}
|
|
737
|
+
function get_splited_command_line(string) {
|
|
738
|
+
/*
|
|
739
|
+
string = str_repeat('x', prompt_len) + string;
|
|
740
|
+
var result = $.terminal.split_equal(string);
|
|
741
|
+
result[0] = result[0].substring(prompt_len);
|
|
742
|
+
return result;
|
|
743
|
+
*/
|
|
744
|
+
var first = string.substring(0, num_chars - prompt_len);
|
|
745
|
+
var rest = string.substring(num_chars - prompt_len);
|
|
746
|
+
return [first].concat(str_parts(rest, num_chars));
|
|
747
|
+
}
|
|
748
|
+
var redraw = (function(self) {
|
|
749
|
+
var before = cursor.prev();
|
|
750
|
+
var after = cursor.next();
|
|
751
|
+
function draw_cursor_line(string, position) {
|
|
752
|
+
var len = string.length;
|
|
753
|
+
if (position === len) {
|
|
754
|
+
before.html($.terminal.encode(string));
|
|
755
|
+
cursor.html(' ');
|
|
756
|
+
after.html('');
|
|
757
|
+
} else if (position === 0) {
|
|
758
|
+
before.html('');
|
|
759
|
+
//fix for tilda in IE
|
|
760
|
+
cursor.html($.terminal.encode(string.slice(0, 1)));
|
|
761
|
+
//cursor.html($.terminal.encode(string[0]));
|
|
762
|
+
after.html($.terminal.encode(string.slice(1)));
|
|
763
|
+
} else {
|
|
764
|
+
var before_str = $.terminal.encode(string.slice(0, position));
|
|
765
|
+
before.html(before_str);
|
|
766
|
+
//fix for tilda in IE
|
|
767
|
+
var c = string.slice(position, position + 1);
|
|
768
|
+
//cursor.html(string[position]));
|
|
769
|
+
cursor.html(c === ' ' ? ' ' : $.terminal.encode(c));
|
|
770
|
+
if (position === string.length - 1) {
|
|
771
|
+
after.html('');
|
|
772
|
+
} else {
|
|
773
|
+
after.html($.terminal.encode(string.slice(position + 1)));
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
function div(string) {
|
|
778
|
+
return '<div>' + $.terminal.encode(string) + '</div>';
|
|
779
|
+
}
|
|
780
|
+
function lines_after(lines) {
|
|
781
|
+
var last_ins = after;
|
|
782
|
+
$.each(lines, function(i, line) {
|
|
783
|
+
last_ins = $(div(line)).insertAfter(last_ins).
|
|
784
|
+
addClass('clear');
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
function lines_before(lines) {
|
|
788
|
+
$.each(lines, function(i, line) {
|
|
789
|
+
before.before(div(line));
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
var count = 0;
|
|
793
|
+
return function() {
|
|
794
|
+
var string = mask ? command.replace(/./g, '*') : command;
|
|
795
|
+
var i, first_len;
|
|
796
|
+
self.find('div').remove();
|
|
797
|
+
before.html('');
|
|
798
|
+
// long line
|
|
799
|
+
if (string.length > num_chars - prompt_len - 1 ||
|
|
800
|
+
string.match(/\n/)) {
|
|
801
|
+
var array;
|
|
802
|
+
var tabs = string.match(/\t/g);
|
|
803
|
+
var tabs_rm = tabs ? tabs.length * 3 : 0;
|
|
804
|
+
//quick tabulation hack
|
|
805
|
+
if (tabs) {
|
|
806
|
+
string = string.replace(/\t/g, '\x00\x00\x00\x00');
|
|
807
|
+
}
|
|
808
|
+
// command contain new line characters
|
|
809
|
+
if (string.match(/\n/)) {
|
|
810
|
+
var tmp = string.split("\n");
|
|
811
|
+
first_len = num_chars - prompt_len - 1;
|
|
812
|
+
// empty character after each line
|
|
813
|
+
for (i=0; i<tmp.length-1; ++i) {
|
|
814
|
+
tmp[i] += ' ';
|
|
815
|
+
}
|
|
816
|
+
// split first line
|
|
817
|
+
if (tmp[0].length > first_len) {
|
|
818
|
+
array = [tmp[0].substring(0, first_len)];
|
|
819
|
+
array = array.concat(str_parts(tmp[0].substring(first_len), num_chars));
|
|
820
|
+
} else {
|
|
821
|
+
array = [tmp[0]];
|
|
822
|
+
}
|
|
823
|
+
// process rest of the lines
|
|
824
|
+
for (i=1; i<tmp.length; ++i) {
|
|
825
|
+
if (tmp[i].length > num_chars) {
|
|
826
|
+
array = array.concat(str_parts(tmp[i], num_chars));
|
|
827
|
+
} else {
|
|
828
|
+
array.push(tmp[i]);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
} else {
|
|
832
|
+
array = get_splited_command_line(string);
|
|
833
|
+
}
|
|
834
|
+
if (tabs) {
|
|
835
|
+
array = $.map(array, function(line) {
|
|
836
|
+
return line.replace(/\x00\x00\x00\x00/g, '\t');
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
first_len = array[0].length;
|
|
840
|
+
//cursor in first line
|
|
841
|
+
if (position < first_len) {
|
|
842
|
+
draw_cursor_line(array[0], position);
|
|
843
|
+
lines_after(array.slice(1));
|
|
844
|
+
} else if (position === first_len) {
|
|
845
|
+
before.before(div(array[0]));
|
|
846
|
+
draw_cursor_line(array[1], 0);
|
|
847
|
+
lines_after(array.slice(2));
|
|
848
|
+
} else {
|
|
849
|
+
var num_lines = array.length;
|
|
850
|
+
var offset = 0;
|
|
851
|
+
if (position < first_len) {
|
|
852
|
+
draw_cursor_line(array[0], position);
|
|
853
|
+
lines_after(array.slice(1));
|
|
854
|
+
} else if (position === first_len) {
|
|
855
|
+
before.before(div(array[0]));
|
|
856
|
+
draw_cursor_line(array[1], 0);
|
|
857
|
+
lines_after(array.slice(2));
|
|
858
|
+
} else {
|
|
859
|
+
var last = array.slice(-1)[0];
|
|
860
|
+
var from_last = string.length - position;
|
|
861
|
+
var last_len = last.length;
|
|
862
|
+
var pos = 0;
|
|
863
|
+
if (from_last <= last_len) {
|
|
864
|
+
lines_before(array.slice(0, -1));
|
|
865
|
+
pos = last_len === from_last ? 0 : last_len-from_last;
|
|
866
|
+
draw_cursor_line(last, pos+tabs_rm);
|
|
867
|
+
} else {
|
|
868
|
+
// in the middle
|
|
869
|
+
if (num_lines === 3) {
|
|
870
|
+
before.before('<div>' + $.terminal.encode(array[0]) +
|
|
871
|
+
'</div>');
|
|
872
|
+
draw_cursor_line(array[1], position-first_len-1);
|
|
873
|
+
after.after('<div class="clear">' +
|
|
874
|
+
$.terminal.encode(array[2]) +
|
|
875
|
+
'</div>');
|
|
876
|
+
} else {
|
|
877
|
+
// more lines, cursor in the middle
|
|
878
|
+
var line_index;
|
|
879
|
+
var current;
|
|
880
|
+
pos = position;
|
|
881
|
+
for (i=0; i<array.length; ++i) {
|
|
882
|
+
var current_len = array[i].length;
|
|
883
|
+
if (pos > current_len) {
|
|
884
|
+
pos -= current_len;
|
|
885
|
+
} else {
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
current = array[i];
|
|
890
|
+
line_index = i;
|
|
891
|
+
// cursor on first character in line
|
|
892
|
+
if (pos === current.length) {
|
|
893
|
+
pos = 0;
|
|
894
|
+
current = array[++line_index];
|
|
895
|
+
}
|
|
896
|
+
draw_cursor_line(current, pos);
|
|
897
|
+
lines_before(array.slice(0, line_index));
|
|
898
|
+
lines_after(array.slice(line_index+1));
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
} else {
|
|
904
|
+
if (string === '') {
|
|
905
|
+
before.html('');
|
|
906
|
+
cursor.html(' ');
|
|
907
|
+
after.html('');
|
|
908
|
+
} else {
|
|
909
|
+
draw_cursor_line(string, position);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
})(self);
|
|
914
|
+
|
|
915
|
+
var draw_prompt = (function() {
|
|
916
|
+
var prompt_node = self.find('.prompt');
|
|
917
|
+
return function() {
|
|
918
|
+
if (typeof prompt === 'string') {
|
|
919
|
+
prompt_len = skipFormattingCount(prompt);
|
|
920
|
+
prompt_node.html($.terminal.format(prompt));
|
|
921
|
+
} else {
|
|
922
|
+
prompt(function(string) {
|
|
923
|
+
prompt_len = skipFormattingCount(string);
|
|
924
|
+
prompt_node.html($.terminal.format(string));
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
//change_num_chars();
|
|
928
|
+
};
|
|
929
|
+
})();
|
|
930
|
+
// paste content to terminal using hidden textarea
|
|
931
|
+
function paste() {
|
|
932
|
+
clip.focus();
|
|
933
|
+
//wait until Browser insert text to textarea
|
|
934
|
+
self.oneTime(1, function() {
|
|
935
|
+
self.insert(clip.val());
|
|
936
|
+
clip.blur().val('');
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
function keydown_event(e) {
|
|
940
|
+
if (options.keydown && options.keydown(e) === false) {
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
if (enabled) {
|
|
944
|
+
var pos, len, result;
|
|
945
|
+
// arrows / Home / End / ENTER
|
|
946
|
+
if (reverse_search && (e.which === 35 || e.which === 36 ||
|
|
947
|
+
e.which === 37 || e.which === 38 ||
|
|
948
|
+
e.which === 39 || e.which === 40 ||
|
|
949
|
+
e.which === 66 || e.which === 13 ||
|
|
950
|
+
e.which === 27)) {
|
|
951
|
+
clear_reverse_state();
|
|
952
|
+
draw_prompt();
|
|
953
|
+
if (e.which === 27) { // ESC
|
|
954
|
+
command = '';
|
|
955
|
+
}
|
|
956
|
+
redraw();
|
|
957
|
+
// finish reverse search and execute normal event handler
|
|
958
|
+
keydown_event.call(this, e);
|
|
959
|
+
} else if (e.altKey) {
|
|
960
|
+
// Chrome on Windows set ctrlKey and altKey for alt
|
|
961
|
+
// need to check for alt first
|
|
962
|
+
//if (e.which === 18) { // press ALT
|
|
963
|
+
if (e.which === 68) { //ALT+D
|
|
964
|
+
var regex = /[^ ]+ |[^ ]+$/;
|
|
965
|
+
self.set(command.slice(0, position) +
|
|
966
|
+
command.slice(position).replace(regex, ''),
|
|
967
|
+
true);
|
|
968
|
+
// chrome jump to address bar
|
|
969
|
+
return false;
|
|
970
|
+
}
|
|
971
|
+
return true;
|
|
972
|
+
} else if (e.keyCode === 13) { //enter
|
|
973
|
+
if ((history && command) &&
|
|
974
|
+
((options.historyFilter &&
|
|
975
|
+
options.historyFilter(command)) ||
|
|
976
|
+
!options.historyFilter)) {
|
|
977
|
+
if (history.data().slice(-1)[0] !== command) {
|
|
978
|
+
history.append(command);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
history.last();
|
|
982
|
+
var tmp = command;
|
|
983
|
+
self.set('');
|
|
984
|
+
if (options.commands) {
|
|
985
|
+
options.commands(tmp);
|
|
986
|
+
}
|
|
987
|
+
if (typeof prompt === 'function') {
|
|
988
|
+
draw_prompt();
|
|
989
|
+
}
|
|
990
|
+
} else if (e.which === 32) { //space
|
|
991
|
+
if (reverse_search) {
|
|
992
|
+
reverse_search_string += ' ';
|
|
993
|
+
draw_reverse_prompt();
|
|
994
|
+
} else {
|
|
995
|
+
self.insert(' ');
|
|
996
|
+
}
|
|
997
|
+
} else if (e.which === 8) { //backspace
|
|
998
|
+
if (reverse_search) {
|
|
999
|
+
reverse_search_string = reverse_search_string.slice(0, -1);
|
|
1000
|
+
draw_reverse_prompt();
|
|
1001
|
+
} else {
|
|
1002
|
+
if (command !== '' && position > 0) {
|
|
1003
|
+
command = command.slice(0, position - 1) +
|
|
1004
|
+
command.slice(position, command.length);
|
|
1005
|
+
--position;
|
|
1006
|
+
redraw();
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
} else if (e.which === 9 && !(e.ctrlKey || e.altKey)) { // TAB
|
|
1010
|
+
self.insert('\t');
|
|
1011
|
+
} else if (e.which === 46) {
|
|
1012
|
+
//DELETE
|
|
1013
|
+
if (command !== '' && position < command.length) {
|
|
1014
|
+
command = command.slice(0, position) +
|
|
1015
|
+
command.slice(position + 1, command.length);
|
|
1016
|
+
redraw();
|
|
1017
|
+
}
|
|
1018
|
+
return true;
|
|
1019
|
+
} else if (history && e.which === 38 ||
|
|
1020
|
+
(e.which === 80 && e.ctrlKey)) {
|
|
1021
|
+
//UP ARROW or CTRL+P
|
|
1022
|
+
self.set(history.previous());
|
|
1023
|
+
} else if (history && e.which === 40 ||
|
|
1024
|
+
(e.which === 78 && e.ctrlKey)) {
|
|
1025
|
+
//DOWN ARROW or CTRL+N
|
|
1026
|
+
self.set(history.next());
|
|
1027
|
+
} else if (e.which === 37 ||
|
|
1028
|
+
(e.which === 66 && e.ctrlKey)) {
|
|
1029
|
+
//CTRL+LEFT ARROW or CTRL+B
|
|
1030
|
+
if (e.ctrlKey && e.which !== 66) {
|
|
1031
|
+
len = position - 1;
|
|
1032
|
+
pos = 0;
|
|
1033
|
+
if (command[len] === ' ') {
|
|
1034
|
+
--len;
|
|
1035
|
+
}
|
|
1036
|
+
for (var i = len; i > 0; --i) {
|
|
1037
|
+
if (command[i] === ' ' && command[i+1] !== ' ') {
|
|
1038
|
+
pos = i + 1;
|
|
1039
|
+
break;
|
|
1040
|
+
} else if (command[i] === '\n' && command[i+1] !== '\n') {
|
|
1041
|
+
pos = i;
|
|
1042
|
+
break;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
self.position(pos);
|
|
1046
|
+
} else {
|
|
1047
|
+
//LEFT ARROW or CTRL+B
|
|
1048
|
+
if (position > 0) {
|
|
1049
|
+
--position;
|
|
1050
|
+
redraw();
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
} else if (e.which === 82 && e.ctrlKey) { // CTRL+R
|
|
1054
|
+
if (reverse_search) {
|
|
1055
|
+
reverse_history_search(true);
|
|
1056
|
+
} else {
|
|
1057
|
+
backup_prompt = prompt;
|
|
1058
|
+
draw_reverse_prompt();
|
|
1059
|
+
command = '';
|
|
1060
|
+
redraw();
|
|
1061
|
+
reverse_search = true;
|
|
1062
|
+
}
|
|
1063
|
+
} else if (e.which === 39 ||
|
|
1064
|
+
(e.which === 70 && e.ctrlKey)) {
|
|
1065
|
+
//RIGHT ARROW OR CTRL+F
|
|
1066
|
+
if (e.ctrlKey && e.which !== 70) {
|
|
1067
|
+
// jump to beginig or end of the word
|
|
1068
|
+
if (command[position] === ' ') {
|
|
1069
|
+
++position;
|
|
1070
|
+
}
|
|
1071
|
+
var match = command.slice(position).match(/\S[\n\s]{2,}|[\n\s]+\S?/);
|
|
1072
|
+
if (!match || match[0].match(/^\s+$/)) {
|
|
1073
|
+
position = command.length;
|
|
1074
|
+
} else {
|
|
1075
|
+
if (match[0][0] !== ' ') {
|
|
1076
|
+
position += match.index + 1;
|
|
1077
|
+
} else {
|
|
1078
|
+
position += match.index + match[0].length - 1;
|
|
1079
|
+
if (match[0][match[0].length-1] !== ' ') {
|
|
1080
|
+
--position;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
redraw();
|
|
1085
|
+
} else {
|
|
1086
|
+
if (position < command.length) {
|
|
1087
|
+
++position;
|
|
1088
|
+
redraw();
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
} else if (e.which === 123) { //F12 - Allow Firebug
|
|
1092
|
+
return true;
|
|
1093
|
+
} else if (e.which === 36) { //HOME
|
|
1094
|
+
self.position(0);
|
|
1095
|
+
} else if (e.which === 35) {
|
|
1096
|
+
//END
|
|
1097
|
+
self.position(command.length);
|
|
1098
|
+
} else if (e.ctrlKey || e.metaKey) {
|
|
1099
|
+
if (e.shiftKey) { // CTRL+SHIFT+??
|
|
1100
|
+
if (e.which === 84) {
|
|
1101
|
+
//CTRL+SHIFT+T open closed tab
|
|
1102
|
+
return true;
|
|
1103
|
+
}
|
|
1104
|
+
//} else if (e.altKey) { //ALT+CTRL+??
|
|
1105
|
+
} else {
|
|
1106
|
+
//NOTE: in opera charCode is undefined
|
|
1107
|
+
if (e.which === 65) {
|
|
1108
|
+
//CTRL+A
|
|
1109
|
+
self.position(0);
|
|
1110
|
+
} else if (e.which === 69) {
|
|
1111
|
+
//CTRL+E
|
|
1112
|
+
self.position(command.length);
|
|
1113
|
+
} else if (e.which === 88 || e.which === 67 ||
|
|
1114
|
+
e.which === 87 || e.which === 84) {
|
|
1115
|
+
//CTRL+X CTRL+C CTRL+W CTRL+T
|
|
1116
|
+
return true;
|
|
1117
|
+
} else if (e.which === 86) {
|
|
1118
|
+
//CTRL+V
|
|
1119
|
+
paste();
|
|
1120
|
+
return true;
|
|
1121
|
+
} else if (e.which === 75) {
|
|
1122
|
+
//CTRL+K
|
|
1123
|
+
if (position === 0) {
|
|
1124
|
+
self.set('');
|
|
1125
|
+
} else if (position !== command.length) {
|
|
1126
|
+
self.set(command.slice(0, position));
|
|
1127
|
+
}
|
|
1128
|
+
} else if (e.which === 85) { // CTRL+U
|
|
1129
|
+
self.set(command.slice(position, command.length));
|
|
1130
|
+
self.position(0);
|
|
1131
|
+
} else if (e.which === 17) { //CTRL+TAB switch tab
|
|
1132
|
+
return true;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
} else {
|
|
1136
|
+
return true;
|
|
1137
|
+
}
|
|
1138
|
+
return false;
|
|
1139
|
+
} /*else {
|
|
1140
|
+
if ((e.altKey && e.which === 68) ||
|
|
1141
|
+
(e.ctrlKey &&
|
|
1142
|
+
$.inArray(e.which, [65, 66, 68, 69, 80, 78, 70]) > -1) ||
|
|
1143
|
+
// 68 === D
|
|
1144
|
+
[35, 36, 37, 38, 39, 40].has(e.which)) {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
} */
|
|
1148
|
+
}
|
|
1149
|
+
$.extend(self, {
|
|
1150
|
+
name: function(string) {
|
|
1151
|
+
if (string !== undefined) {
|
|
1152
|
+
name = string;
|
|
1153
|
+
history = new History(string);
|
|
1154
|
+
} else {
|
|
1155
|
+
return name;
|
|
1156
|
+
}
|
|
1157
|
+
},
|
|
1158
|
+
history: function() {
|
|
1159
|
+
return history;
|
|
1160
|
+
},
|
|
1161
|
+
set: function(string, stay) {
|
|
1162
|
+
if (string !== undefined) {
|
|
1163
|
+
command = string;
|
|
1164
|
+
if (!stay) {
|
|
1165
|
+
position = command.length;
|
|
1166
|
+
}
|
|
1167
|
+
redraw();
|
|
1168
|
+
if (typeof options.onCommandChange === 'function') {
|
|
1169
|
+
options.onCommandChange(command);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
insert: function(string, stay) {
|
|
1174
|
+
if (position === command.length) {
|
|
1175
|
+
command += string;
|
|
1176
|
+
} else if (position === 0) {
|
|
1177
|
+
command = string + command;
|
|
1178
|
+
} else {
|
|
1179
|
+
command = command.slice(0, position) +
|
|
1180
|
+
string + command.slice(position);
|
|
1181
|
+
}
|
|
1182
|
+
if (!stay) {
|
|
1183
|
+
position += string.length;
|
|
1184
|
+
}
|
|
1185
|
+
redraw();
|
|
1186
|
+
if (typeof options.onCommandChange === 'function') {
|
|
1187
|
+
options.onCommandChange(command);
|
|
1188
|
+
}
|
|
1189
|
+
},
|
|
1190
|
+
get: function() {
|
|
1191
|
+
return command;
|
|
1192
|
+
},
|
|
1193
|
+
commands: function(commands) {
|
|
1194
|
+
if (commands) {
|
|
1195
|
+
options.commands = commands;
|
|
1196
|
+
} else {
|
|
1197
|
+
return commands;
|
|
1198
|
+
}
|
|
1199
|
+
},
|
|
1200
|
+
destroy: function() {
|
|
1201
|
+
$(document.documentElement).unbind('.commandline');
|
|
1202
|
+
self.find('.prompt').remove();
|
|
1203
|
+
},
|
|
1204
|
+
prompt: function(user_prompt) {
|
|
1205
|
+
if (user_prompt === undefined) {
|
|
1206
|
+
return prompt;
|
|
1207
|
+
} else {
|
|
1208
|
+
if (typeof user_prompt === 'string' ||
|
|
1209
|
+
typeof user_prompt === 'function') {
|
|
1210
|
+
prompt = user_prompt;
|
|
1211
|
+
} else {
|
|
1212
|
+
throw 'prompt must be a function or string';
|
|
1213
|
+
}
|
|
1214
|
+
draw_prompt();
|
|
1215
|
+
// we could check if command is longer then numchars-new prompt
|
|
1216
|
+
redraw();
|
|
1217
|
+
}
|
|
1218
|
+
},
|
|
1219
|
+
position: function(n) {
|
|
1220
|
+
if (typeof n === 'number') {
|
|
1221
|
+
position = n < 0 ? 0 : n > command.length ? command.length : n;
|
|
1222
|
+
redraw();
|
|
1223
|
+
} else {
|
|
1224
|
+
return position;
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1227
|
+
visible: (function() {
|
|
1228
|
+
var visible = self.visible;
|
|
1229
|
+
return function() {
|
|
1230
|
+
visible.apply(self, []);
|
|
1231
|
+
redraw();
|
|
1232
|
+
draw_prompt();
|
|
1233
|
+
};
|
|
1234
|
+
})(),
|
|
1235
|
+
show: (function() {
|
|
1236
|
+
var show = self.show;
|
|
1237
|
+
return function() {
|
|
1238
|
+
show.apply(self, []);
|
|
1239
|
+
redraw();
|
|
1240
|
+
draw_prompt();
|
|
1241
|
+
};
|
|
1242
|
+
})(),
|
|
1243
|
+
resize: function(num) {
|
|
1244
|
+
if (num) {
|
|
1245
|
+
num_chars = num;
|
|
1246
|
+
} else {
|
|
1247
|
+
change_num_chars();
|
|
1248
|
+
}
|
|
1249
|
+
redraw();
|
|
1250
|
+
},
|
|
1251
|
+
enable: function() {
|
|
1252
|
+
if (!enabled) {
|
|
1253
|
+
cursor.addClass('inverted');
|
|
1254
|
+
self.everyTime(500, 'blink', blink);
|
|
1255
|
+
enabled = true;
|
|
1256
|
+
}
|
|
1257
|
+
},
|
|
1258
|
+
isenabled: function() {
|
|
1259
|
+
return enabled;
|
|
1260
|
+
},
|
|
1261
|
+
disable: function() {
|
|
1262
|
+
if (enabled) {
|
|
1263
|
+
self.stopTime('blink', blink);
|
|
1264
|
+
cursor.removeClass('inverted');
|
|
1265
|
+
enabled = false;
|
|
1266
|
+
}
|
|
1267
|
+
},
|
|
1268
|
+
mask: function(display) {
|
|
1269
|
+
if (typeof display === 'boolean') {
|
|
1270
|
+
mask = display;
|
|
1271
|
+
redraw();
|
|
1272
|
+
} else {
|
|
1273
|
+
return mask;
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
// INIT
|
|
1278
|
+
self.name(options.name || '');
|
|
1279
|
+
prompt = options.prompt || '> ';
|
|
1280
|
+
draw_prompt();
|
|
1281
|
+
if (options.enabled === undefined || options.enabled === true) {
|
|
1282
|
+
self.enable();
|
|
1283
|
+
}
|
|
1284
|
+
// Keystrokes
|
|
1285
|
+
//document.documentElement
|
|
1286
|
+
var object;
|
|
1287
|
+
if ($.browser.msie) {
|
|
1288
|
+
object = document.documentElement;
|
|
1289
|
+
} else {
|
|
1290
|
+
object = window;
|
|
1291
|
+
}
|
|
1292
|
+
$(object).keypress(function(e) {
|
|
1293
|
+
var result;
|
|
1294
|
+
if (e.ctrlKey && e.which === 99) {
|
|
1295
|
+
return true;
|
|
1296
|
+
}
|
|
1297
|
+
if (!reverse_search && options.keypress) {
|
|
1298
|
+
result = options.keypress(e);
|
|
1299
|
+
}
|
|
1300
|
+
if (result === undefined || result) {
|
|
1301
|
+
if (enabled) {
|
|
1302
|
+
if ($.inArray(e.which, [38, 32, 13, 0, 8]) > -1 &&
|
|
1303
|
+
e.keyCode !== 123 && // for F12 which === 0
|
|
1304
|
+
//!(e.which === 40 && e.shiftKey ||
|
|
1305
|
+
!(e.which === 38 && e.shiftKey)) {
|
|
1306
|
+
return false;
|
|
1307
|
+
} else if (!e.ctrlKey && !(e.altKey && e.which === 100)) {
|
|
1308
|
+
// TODO: this should be in one statement
|
|
1309
|
+
if (reverse_search) {
|
|
1310
|
+
reverse_search_string += String.fromCharCode(e.which);
|
|
1311
|
+
draw_reverse_prompt();
|
|
1312
|
+
reverse_history_search();
|
|
1313
|
+
} else {
|
|
1314
|
+
self.insert(String.fromCharCode(e.which));
|
|
1315
|
+
}
|
|
1316
|
+
return false;
|
|
1317
|
+
} else if (e.altKey) {
|
|
1318
|
+
if (reverse_search) {
|
|
1319
|
+
reverse_search_string += String.fromCharCode(e.which);
|
|
1320
|
+
draw_reverse_prompt();
|
|
1321
|
+
reverse_history_search();
|
|
1322
|
+
} else {
|
|
1323
|
+
self.insert(String.fromCharCode(e.which));
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
} else {
|
|
1328
|
+
return result;
|
|
1329
|
+
}
|
|
1330
|
+
}).keydown(keydown_event);
|
|
1331
|
+
// characters
|
|
1332
|
+
return self;
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1335
|
+
// -------------------------------------------------------------------------
|
|
1336
|
+
// :: TOOLS
|
|
1337
|
+
// -------------------------------------------------------------------------
|
|
1338
|
+
|
|
1339
|
+
var format_split_re = /(\[\[[gbius]*;[^;]*;[^\]]*\](?:[^\]\[]*|\[*(?!\[)[^\]]*\][^\]]*)\])/g;
|
|
1340
|
+
var format_re = /\[\[([gbius]*);([^;]*);([^;\]]*;|[^\]]*);?([^\]]*)\]([^\]\[]*|[^\[]*\[(?!\[)*[^\]]*\][^\]]*)\]/g;
|
|
1341
|
+
var color_hex_re = /#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})/;
|
|
1342
|
+
var url_re = /(https?:((?!&[^;]+;)[^\s:"'<)])+)/g;
|
|
1343
|
+
var email_regex = /((([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,})))/g;
|
|
1344
|
+
$.terminal = {
|
|
1345
|
+
// split text into lines with equal width and make each line be renderd
|
|
1346
|
+
// separatly (text formating can be longer then a line).
|
|
1347
|
+
split_equal: function(str, length) {
|
|
1348
|
+
var array = str.split(/\n/g);
|
|
1349
|
+
var re_format = /(\[\[[gbius]*;[^;]*;[^\]]*\][^\]\[]*\]?)/g;
|
|
1350
|
+
var re_begin = /(\[\[[gbius]*;[^;]*;[^\]]*\])/;
|
|
1351
|
+
var re_last = /\[\[[gbius]*;?[^;]*;?[^\]]*\]?$/;
|
|
1352
|
+
var formatting = false;
|
|
1353
|
+
var in_text = false;
|
|
1354
|
+
var braket = 0;
|
|
1355
|
+
var prev_format = '';
|
|
1356
|
+
var result = [];
|
|
1357
|
+
for (var i = 0, len = array.length; i < len; ++i) {
|
|
1358
|
+
if (prev_format !== '') {
|
|
1359
|
+
if (array[i] === '') {
|
|
1360
|
+
result.push(prev_format + ']');
|
|
1361
|
+
continue;
|
|
1362
|
+
} else {
|
|
1363
|
+
array[i] = prev_format + array[i];
|
|
1364
|
+
prev_format = '';
|
|
1365
|
+
}
|
|
1366
|
+
} else {
|
|
1367
|
+
if (array[i] === '') {
|
|
1368
|
+
result.push('');
|
|
1369
|
+
continue;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
var line = array[i];
|
|
1373
|
+
var first_index = 0;
|
|
1374
|
+
var count = 0;
|
|
1375
|
+
for (var j=0, jlen=line.length; j<jlen; ++j) {
|
|
1376
|
+
if (line[j] === '[' && line[j+1] === '[') {
|
|
1377
|
+
formatting = true;
|
|
1378
|
+
} else if (formatting && line[j] === ']') {
|
|
1379
|
+
if (in_text) {
|
|
1380
|
+
formatting = false;
|
|
1381
|
+
in_text = false;
|
|
1382
|
+
} else {
|
|
1383
|
+
in_text = true;
|
|
1384
|
+
}
|
|
1385
|
+
} else if ((formatting && in_text) || !formatting) {
|
|
1386
|
+
++count;
|
|
1387
|
+
}
|
|
1388
|
+
if (count === length || j === jlen-1) {
|
|
1389
|
+
var output_line = line.substring(first_index, j+1);
|
|
1390
|
+
if (prev_format) {
|
|
1391
|
+
output_line = prev_format + output_line;
|
|
1392
|
+
if (output_line.match(']')) {
|
|
1393
|
+
prev_format = '';
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
first_index = j+1;
|
|
1397
|
+
count = 0;
|
|
1398
|
+
var matched = output_line.match(re_format);
|
|
1399
|
+
if (matched) {
|
|
1400
|
+
var last = matched[matched.length-1];
|
|
1401
|
+
if (last[last.length-1] !== ']') {
|
|
1402
|
+
prev_format = last.match(re_begin)[1];
|
|
1403
|
+
output_line += ']';
|
|
1404
|
+
} else if (output_line.match(re_last)) {
|
|
1405
|
+
var line_len = output_line.length;
|
|
1406
|
+
var f_len = line_len - last[last.length-1].length;
|
|
1407
|
+
output_line = output_line.replace(re_last, '');
|
|
1408
|
+
prev_format = last.match(re_begin)[1];
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
result.push(output_line);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
return result;
|
|
1416
|
+
},
|
|
1417
|
+
// encode formating as html for inserto into DOM
|
|
1418
|
+
encode: function(str) {
|
|
1419
|
+
// don't escape entities
|
|
1420
|
+
return str.replace(/&(?!#[0-9]+;|[a-zA-Z]+;)/g, '&')
|
|
1421
|
+
.replace(/</g, '<').replace(/>/g, '>')
|
|
1422
|
+
// I don't think that it find \n
|
|
1423
|
+
.replace(/\n/g, '<br/>')
|
|
1424
|
+
.replace(/ /g, ' ')
|
|
1425
|
+
.replace(/\t/g, ' ');
|
|
1426
|
+
},
|
|
1427
|
+
format: function(str) {
|
|
1428
|
+
if (typeof str === 'string') {
|
|
1429
|
+
str = $.terminal.encode($.terminal.from_ansi(str));
|
|
1430
|
+
//support for formating foo[[u;;]bar]baz[[b;#fff;]quux]zzz
|
|
1431
|
+
var splited = str.split(format_split_re);
|
|
1432
|
+
if (splited && splited.length > 1) {
|
|
1433
|
+
str = $.map(splited, function(text) {
|
|
1434
|
+
if (text === '') {
|
|
1435
|
+
return text;
|
|
1436
|
+
} else if (text.substring(0,1) === '[') {
|
|
1437
|
+
// use substring for IE quirks mode - [0] don't work
|
|
1438
|
+
return text.replace(format_re, function(s,
|
|
1439
|
+
style,
|
|
1440
|
+
color,
|
|
1441
|
+
background,
|
|
1442
|
+
_class,
|
|
1443
|
+
text) {
|
|
1444
|
+
if (text === '') {
|
|
1445
|
+
return '<span> </span>';
|
|
1446
|
+
}
|
|
1447
|
+
var style_str = '';
|
|
1448
|
+
if (style.indexOf('b') !== -1) {
|
|
1449
|
+
style_str += 'font-weight:bold;';
|
|
1450
|
+
}
|
|
1451
|
+
var text_decoration = 'text-decoration:';
|
|
1452
|
+
if (style.indexOf('u') !== -1) {
|
|
1453
|
+
text_decoration += 'underline ';
|
|
1454
|
+
}
|
|
1455
|
+
if (style.indexOf('s') !== -1) {
|
|
1456
|
+
text_decoration += 'line-through';
|
|
1457
|
+
}
|
|
1458
|
+
if (style.indexOf('s') !== -1 ||
|
|
1459
|
+
style.indexOf('u') !== -1) {
|
|
1460
|
+
style_str += text_decoration + ';';
|
|
1461
|
+
}
|
|
1462
|
+
if (style.indexOf('i') !== -1) {
|
|
1463
|
+
style_str += 'font-style:italic;';
|
|
1464
|
+
}
|
|
1465
|
+
if (color.match(color_hex_re)) {
|
|
1466
|
+
style_str += 'color:' + color + ';';
|
|
1467
|
+
if (style.indexOf('g') !== -1) {
|
|
1468
|
+
style_str += 'text-shadow: 0 0 5px ' + color + ';';
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
if (background.match(color_hex_re)) {
|
|
1472
|
+
style_str += 'background-color:' + background;
|
|
1473
|
+
}
|
|
1474
|
+
var result = '<span style="' + style_str + '"' +
|
|
1475
|
+
(_class != '' ? ' class="' + _class + '"' : '') +
|
|
1476
|
+
'>' + text + '</span>';
|
|
1477
|
+
return result;
|
|
1478
|
+
});
|
|
1479
|
+
} else {
|
|
1480
|
+
return '<span>' + text + '</span>';
|
|
1481
|
+
}
|
|
1482
|
+
}).join('');
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
return str.replace(url_re, function(link) {
|
|
1486
|
+
var comma = link.match(/\.$/);
|
|
1487
|
+
link = link.replace(/\.$/, '');
|
|
1488
|
+
return '<a target="_blank" href="' + link + '">' + link + '</a>' +
|
|
1489
|
+
(comma ? '.' : '');
|
|
1490
|
+
}).replace(email_regex, '<a href="mailto:$1">$1</a>').
|
|
1491
|
+
replace(/<span><br\/?><\/span>/g, '<br/>');
|
|
1492
|
+
} else {
|
|
1493
|
+
return '';
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
// remove formatting from text
|
|
1497
|
+
strip: function(str) {
|
|
1498
|
+
return str.replace(format_re, '$5');
|
|
1499
|
+
},
|
|
1500
|
+
// return active terminal
|
|
1501
|
+
active: function() {
|
|
1502
|
+
return terminals.front();
|
|
1503
|
+
},
|
|
1504
|
+
ansi_colors: {
|
|
1505
|
+
normal: {
|
|
1506
|
+
black: '#000',
|
|
1507
|
+
red: '#AA0000',
|
|
1508
|
+
green: '#008400',
|
|
1509
|
+
yellow: '#AA5500',
|
|
1510
|
+
blue: '#0000AA',
|
|
1511
|
+
magenta: '#AA00AA',
|
|
1512
|
+
cyan: '#00AAAA',
|
|
1513
|
+
white: '#fff'
|
|
1514
|
+
},
|
|
1515
|
+
bold: {
|
|
1516
|
+
white: '#fff',
|
|
1517
|
+
red: '#FF5555',
|
|
1518
|
+
green: '#44D544',
|
|
1519
|
+
yellow: '#FFFF55',
|
|
1520
|
+
blue: '#5555FF',
|
|
1521
|
+
magenta: '#FF55FF',
|
|
1522
|
+
cyan: '#55FFFF',
|
|
1523
|
+
black: '#000'
|
|
1524
|
+
}
|
|
1525
|
+
},
|
|
1526
|
+
from_ansi: (function() {
|
|
1527
|
+
var color = {
|
|
1528
|
+
30: 'black',
|
|
1529
|
+
31: 'red',
|
|
1530
|
+
32: 'green',
|
|
1531
|
+
33: 'yellow',
|
|
1532
|
+
34: 'blue',
|
|
1533
|
+
35: 'magenta',
|
|
1534
|
+
36: 'cyan',
|
|
1535
|
+
37: 'white'
|
|
1536
|
+
};
|
|
1537
|
+
var background = {
|
|
1538
|
+
40: 'black',
|
|
1539
|
+
41: 'red',
|
|
1540
|
+
42: 'green',
|
|
1541
|
+
43: 'yellow',
|
|
1542
|
+
44: 'blue',
|
|
1543
|
+
45: 'magenta',
|
|
1544
|
+
46: 'cyan',
|
|
1545
|
+
47: 'white'
|
|
1546
|
+
};
|
|
1547
|
+
function format_ansi(code) {
|
|
1548
|
+
var controls = code.split(';');
|
|
1549
|
+
var num;
|
|
1550
|
+
var styles = [];
|
|
1551
|
+
var output_color = '';
|
|
1552
|
+
var output_background = '';
|
|
1553
|
+
for(var i in controls) {
|
|
1554
|
+
num = parseInt(controls[i], 10);
|
|
1555
|
+
if (num === 1) {
|
|
1556
|
+
styles.push('b');
|
|
1557
|
+
}
|
|
1558
|
+
if (num === 4) {
|
|
1559
|
+
styles.push('u');
|
|
1560
|
+
}
|
|
1561
|
+
if (background[num]) {
|
|
1562
|
+
output_background = background[num];
|
|
1563
|
+
}
|
|
1564
|
+
if (color[num]) {
|
|
1565
|
+
output_color = color[num];
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
var normal = $.terminal.ansi_colors.normal;
|
|
1569
|
+
var colors = normal;
|
|
1570
|
+
for (var i=styles.length;i--;) {
|
|
1571
|
+
if (styles[i] == 'b') {
|
|
1572
|
+
if (output_color == '') {
|
|
1573
|
+
output_color = 'white';
|
|
1574
|
+
}
|
|
1575
|
+
colors = $.terminal.ansi_colors.bold;
|
|
1576
|
+
break;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return '[[' + [styles.join(''),
|
|
1580
|
+
colors[output_color],
|
|
1581
|
+
normal[output_background]
|
|
1582
|
+
].join(';') + ']';
|
|
1583
|
+
}
|
|
1584
|
+
return function(input) {
|
|
1585
|
+
var splitted = input.split(/(\[[0-9;]*m)/g);
|
|
1586
|
+
if (splitted.length == 1) {
|
|
1587
|
+
return input;
|
|
1588
|
+
}
|
|
1589
|
+
var output = [];
|
|
1590
|
+
//skip closing at the begining
|
|
1591
|
+
if (splitted.length > 3 && splitted.slice(0,3).join('') == '[0m') {
|
|
1592
|
+
splitted = splitted.slice(3);
|
|
1593
|
+
}
|
|
1594
|
+
var inside = false;
|
|
1595
|
+
for (var i=0; i<splitted.length; ++i) {
|
|
1596
|
+
var match = splitted[i].match(/^\[([0-9;]*)m$/);
|
|
1597
|
+
if (match) {
|
|
1598
|
+
if (match[1] == '') {
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
if (inside) {
|
|
1602
|
+
output.push(']');
|
|
1603
|
+
if (match[1] == '0') {
|
|
1604
|
+
//just closing
|
|
1605
|
+
inside = false;
|
|
1606
|
+
} else {
|
|
1607
|
+
// someone forget to close - process
|
|
1608
|
+
output.push(format_ansi(match[1]));
|
|
1609
|
+
}
|
|
1610
|
+
} else {
|
|
1611
|
+
inside = true;
|
|
1612
|
+
output.push(format_ansi(match[1]));
|
|
1613
|
+
}
|
|
1614
|
+
} else {
|
|
1615
|
+
output.push(splitted[i]);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
if (inside) {
|
|
1619
|
+
output.push(']');
|
|
1620
|
+
}
|
|
1621
|
+
return output.join('');
|
|
1622
|
+
};
|
|
1623
|
+
})()
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
// -----------------------------------------------------------------------
|
|
1627
|
+
// Helpers
|
|
1628
|
+
// -----------------------------------------------------------------------
|
|
1629
|
+
$.fn.visible = function() {
|
|
1630
|
+
return this.css('visibility', 'visible');
|
|
1631
|
+
};
|
|
1632
|
+
$.fn.hidden = function() {
|
|
1633
|
+
return this.css('visibility', 'hidden');
|
|
1634
|
+
};
|
|
1635
|
+
// -----------------------------------------------------------------------
|
|
1636
|
+
// JSON-RPC CALL
|
|
1637
|
+
// -----------------------------------------------------------------------
|
|
1638
|
+
$.jrpc = function(url, id, method, params, success, error) {
|
|
1639
|
+
var request = $.json_stringify({
|
|
1640
|
+
'jsonrpc': '2.0', 'method': method,
|
|
1641
|
+
'params': params, 'id': id});
|
|
1642
|
+
return $.ajax({
|
|
1643
|
+
url: url,
|
|
1644
|
+
data: request,
|
|
1645
|
+
success: success,
|
|
1646
|
+
error: error,
|
|
1647
|
+
contentType: 'application/json',
|
|
1648
|
+
dataType: 'json',
|
|
1649
|
+
async: true,
|
|
1650
|
+
cache: false,
|
|
1651
|
+
//timeout: 1,
|
|
1652
|
+
type: 'POST'});
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
// -----------------------------------------------------------------------
|
|
1656
|
+
// :: TERMINAL PLUGIN CODE
|
|
1657
|
+
// -----------------------------------------------------------------------
|
|
1658
|
+
var version = '0.4.22';
|
|
1659
|
+
var copyright = 'Copyright (c) 2011-2012 Jakub Jankiewicz <http://jcubic.pl>';
|
|
1660
|
+
var version_string = 'version ' + version;
|
|
1661
|
+
//regex is for placing version string aligned to the right
|
|
1662
|
+
var reg = new RegExp(" {" + version_string.length + "}$");
|
|
1663
|
+
var signatures = [
|
|
1664
|
+
['jQuery Terminal', '(c) 2011-2012 jcubic'],
|
|
1665
|
+
['jQuery Terminal Emulator v. ' + version,
|
|
1666
|
+
copyright.replace(/ *<.*>/, '')],
|
|
1667
|
+
['jQuery Terminal Emulator version ' + version_string,
|
|
1668
|
+
copyright],
|
|
1669
|
+
[' _______ ________ __',
|
|
1670
|
+
' / / _ /_ ____________ _/__ ___/______________ _____ / /',
|
|
1671
|
+
' __ / / // / // / _ / _/ // / / / _ / _/ / / \\/ / _ \\/ /',
|
|
1672
|
+
'/ / / // / // / ___/ // // / / / ___/ // / / / / /\\ / // / /__',
|
|
1673
|
+
'\\___/____ \\\\__/____/_/ \\__ / /_/____/_//_/ /_/ /_/ \\/\\__\\_\\___/',
|
|
1674
|
+
' \\/ /____/ '.replace(reg, '') +
|
|
1675
|
+
version_string,
|
|
1676
|
+
copyright],
|
|
1677
|
+
[' __ _____ ________ __',
|
|
1678
|
+
' / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /',
|
|
1679
|
+
' __ / // // // // // _ // _// // / / // _ // _// // // \\/ // _ \\/ /',
|
|
1680
|
+
'/ / // // // // // ___// / / // / / // ___// / / / / // // /\\ // // / /__',
|
|
1681
|
+
'\\___//____ \\\\___//____//_/ _\\_ / /_//____//_/ /_/ /_//_//_/ /_/ \\__\\_\\___/',
|
|
1682
|
+
' \\/ /____/ '.replace(reg, '') +
|
|
1683
|
+
version_string,
|
|
1684
|
+
copyright]
|
|
1685
|
+
];
|
|
1686
|
+
// for canceling on CTRL+D
|
|
1687
|
+
var requests = [];
|
|
1688
|
+
var terminals = new Cycle(); //list of terminals global in this scope
|
|
1689
|
+
$.fn.terminal = function(init_eval, options) {
|
|
1690
|
+
var self = this;
|
|
1691
|
+
var lines = [];
|
|
1692
|
+
var output;
|
|
1693
|
+
var terminal_id = terminals.length();
|
|
1694
|
+
var num_chars; // numer of chars in line
|
|
1695
|
+
var command_list = []; // for tab completion
|
|
1696
|
+
var settings = $.extend({
|
|
1697
|
+
name: '',
|
|
1698
|
+
prompt: '> ',
|
|
1699
|
+
history: true,
|
|
1700
|
+
exit: true,
|
|
1701
|
+
clear: true,
|
|
1702
|
+
enabled: true,
|
|
1703
|
+
displayExceptions: true,
|
|
1704
|
+
cancelableAjax: true,
|
|
1705
|
+
login: null,
|
|
1706
|
+
tabcompletion: null,
|
|
1707
|
+
historyFilter: null,
|
|
1708
|
+
onInit: $.noop,
|
|
1709
|
+
onClear: $.noop,
|
|
1710
|
+
onBlur: $.noop,
|
|
1711
|
+
onFocus: $.noop,
|
|
1712
|
+
onTerminalChange: $.noop,
|
|
1713
|
+
onExit: $.noop,
|
|
1714
|
+
keypress: $.noop,
|
|
1715
|
+
keydown: $.noop
|
|
1716
|
+
}, options || {});
|
|
1717
|
+
|
|
1718
|
+
if (settings.width) {
|
|
1719
|
+
self.width(settings.width);
|
|
1720
|
+
}
|
|
1721
|
+
if (settings.height) {
|
|
1722
|
+
self.height(settings.height);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
var pause = !settings.enabled;
|
|
1726
|
+
if (self.length === 0) {
|
|
1727
|
+
throw 'Sorry, but terminal said that "' + self.selector +
|
|
1728
|
+
'" is not valid selector!';
|
|
1729
|
+
}
|
|
1730
|
+
// register ajaxSend for cancel requests on CTRL+D
|
|
1731
|
+
self.ajaxSend(function(e, xhr, opt) {
|
|
1732
|
+
requests.push(xhr);
|
|
1733
|
+
});
|
|
1734
|
+
// terminal already exist
|
|
1735
|
+
if (self.data('terminal')) {
|
|
1736
|
+
return self.data('terminal');
|
|
1737
|
+
}
|
|
1738
|
+
output = $('<div>').addClass('terminal-output').appendTo(self);
|
|
1739
|
+
self.addClass('terminal').append('<div/>');
|
|
1740
|
+
self.click(function() {
|
|
1741
|
+
self.find('textarea').focus();
|
|
1742
|
+
});
|
|
1743
|
+
/*
|
|
1744
|
+
self.bind('touchstart.touchScroll', function() {
|
|
1745
|
+
|
|
1746
|
+
});
|
|
1747
|
+
self.bind('touchmove.touchScroll', function() {
|
|
1748
|
+
|
|
1749
|
+
});
|
|
1750
|
+
*/
|
|
1751
|
+
//$('<input type="text"/>').hide().focus().appendTo(self);
|
|
1752
|
+
//calculate numbers of characters
|
|
1753
|
+
function haveScrollbars() {
|
|
1754
|
+
return self.get(0).scrollHeight > self.innerHeight();
|
|
1755
|
+
}
|
|
1756
|
+
function get_num_chars() {
|
|
1757
|
+
var cursor = self.find('.cursor');
|
|
1758
|
+
var cur_width = cursor.width();
|
|
1759
|
+
var result = Math.floor(self.width() / cur_width);
|
|
1760
|
+
if (haveScrollbars()) {
|
|
1761
|
+
// assume that scrollbars are 20px - in my Laptop with
|
|
1762
|
+
// Linux/Chrome they are 16px
|
|
1763
|
+
var margins = self.innerWidth() - self.width();
|
|
1764
|
+
result -= Math.ceil((20 - margins / 2) / (cur_width-1));
|
|
1765
|
+
}
|
|
1766
|
+
return result;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
function escape_brackets(string) {
|
|
1770
|
+
return string.replace(/\[/g, '[').replace(/\]/g, ']');
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// display Exception on terminal
|
|
1774
|
+
function display_exception(e, label) {
|
|
1775
|
+
if (settings.displayExceptions) {
|
|
1776
|
+
var message;
|
|
1777
|
+
if (typeof e === 'string') {
|
|
1778
|
+
message = e;
|
|
1779
|
+
} else {
|
|
1780
|
+
if (typeof e.fileName === 'string') {
|
|
1781
|
+
message = e.fileName + ': ' + e.message;
|
|
1782
|
+
} else {
|
|
1783
|
+
message = e.message;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
self.error('[' + label + ']: ' + message);
|
|
1787
|
+
if (typeof e.fileName === 'string') {
|
|
1788
|
+
//display filename and line which throw exeption
|
|
1789
|
+
self.pause();
|
|
1790
|
+
$.get(e.fileName, function(file) {
|
|
1791
|
+
self.resume();
|
|
1792
|
+
var num = e.lineNumber - 1;
|
|
1793
|
+
var line = file.split('\n')[num];
|
|
1794
|
+
if (line) {
|
|
1795
|
+
self.error('[' + e.lineNumber + ']: ' + line);
|
|
1796
|
+
}
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
if (e.stack) {
|
|
1800
|
+
self.error(e.stack);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
//validating if object is string or function, call that function and
|
|
1806
|
+
//display exeption if any
|
|
1807
|
+
function validate(label, object) {
|
|
1808
|
+
try {
|
|
1809
|
+
if (typeof object === 'function') {
|
|
1810
|
+
object(function() {
|
|
1811
|
+
// don't care
|
|
1812
|
+
});
|
|
1813
|
+
} else if (typeof object !== 'string') {
|
|
1814
|
+
var msg = label + ' must be string or function';
|
|
1815
|
+
throw msg;
|
|
1816
|
+
}
|
|
1817
|
+
} catch (e) {
|
|
1818
|
+
display_exception(e, label.toUpperCase());
|
|
1819
|
+
return false;
|
|
1820
|
+
}
|
|
1821
|
+
return true;
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
function scroll_to_bottom() {
|
|
1825
|
+
var scrollHeight = self.prop ? self.prop('scrollHeight') :
|
|
1826
|
+
self.attr('scrollHeight');
|
|
1827
|
+
self.scrollTop(scrollHeight);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
function draw_line(string) {
|
|
1831
|
+
string = typeof string === 'string' ? string : String(string);
|
|
1832
|
+
var div, i, len;
|
|
1833
|
+
if (string.length > num_chars) {
|
|
1834
|
+
// string can have line break
|
|
1835
|
+
//var array = string.split('\n');
|
|
1836
|
+
// TODO: the way it should work
|
|
1837
|
+
var array = $.terminal.split_equal(string, num_chars);
|
|
1838
|
+
|
|
1839
|
+
div = $('<div></div>');
|
|
1840
|
+
for (i = 0, len = array.length; i < len; ++i) {
|
|
1841
|
+
if (array[i] === '' || array[i] === '\r') {
|
|
1842
|
+
div.append('<div> </div>');
|
|
1843
|
+
} else {
|
|
1844
|
+
$('<div/>').html($.terminal.format(array[i])).appendTo(div);
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
} else {
|
|
1848
|
+
div = $('<div/>').html($.terminal.format(string));
|
|
1849
|
+
}
|
|
1850
|
+
output.append(div);
|
|
1851
|
+
div.width('100%');
|
|
1852
|
+
scroll_to_bottom();
|
|
1853
|
+
return div;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
function show_greetings() {
|
|
1857
|
+
if (options.greetings === undefined) {
|
|
1858
|
+
self.echo(self.signature);
|
|
1859
|
+
} else if (options.greetings) {
|
|
1860
|
+
self.echo(options.greetings);
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
function is_scrolled_into_view(elem) {
|
|
1865
|
+
var docViewTop = $(window).scrollTop();
|
|
1866
|
+
var docViewBottom = docViewTop + $(window).height();
|
|
1867
|
+
|
|
1868
|
+
var elemTop = $(elem).offset().top;
|
|
1869
|
+
var elemBottom = elemTop + $(elem).height();
|
|
1870
|
+
|
|
1871
|
+
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
// ----------------------------------------------------------
|
|
1875
|
+
// TERMINAL METHODS
|
|
1876
|
+
// ----------------------------------------------------------
|
|
1877
|
+
|
|
1878
|
+
var dalyed_commands = [];
|
|
1879
|
+
$.extend(self, $.omap({
|
|
1880
|
+
clear: function() {
|
|
1881
|
+
output.html('');
|
|
1882
|
+
command_line.set('');
|
|
1883
|
+
lines = [];
|
|
1884
|
+
try {
|
|
1885
|
+
settings.onClear(self);
|
|
1886
|
+
} catch (e) {
|
|
1887
|
+
display_exception(e, 'onClear');
|
|
1888
|
+
throw e;
|
|
1889
|
+
}
|
|
1890
|
+
self.attr({ scrollTop: 0});
|
|
1891
|
+
return self;
|
|
1892
|
+
},
|
|
1893
|
+
exec: function(command, silent) {
|
|
1894
|
+
if (pause) {
|
|
1895
|
+
dalyed_commands.push([command, silent]);
|
|
1896
|
+
} else {
|
|
1897
|
+
commands(command, silent);
|
|
1898
|
+
}
|
|
1899
|
+
return self;
|
|
1900
|
+
},
|
|
1901
|
+
commands: function() {
|
|
1902
|
+
return interpreters.top().eval;
|
|
1903
|
+
},
|
|
1904
|
+
greetings: function() {
|
|
1905
|
+
show_greetings();
|
|
1906
|
+
return self;
|
|
1907
|
+
},
|
|
1908
|
+
paused: function() {
|
|
1909
|
+
return pause;
|
|
1910
|
+
},
|
|
1911
|
+
pause: function() {
|
|
1912
|
+
if (command_line) {
|
|
1913
|
+
pause = true;
|
|
1914
|
+
self.disable();
|
|
1915
|
+
command_line.hidden();
|
|
1916
|
+
}
|
|
1917
|
+
return self;
|
|
1918
|
+
},
|
|
1919
|
+
resume: function() {
|
|
1920
|
+
if (command_line) {
|
|
1921
|
+
self.enable();
|
|
1922
|
+
var original = dalyed_commands;
|
|
1923
|
+
dalyed_commands = [];
|
|
1924
|
+
while (original.length) {
|
|
1925
|
+
var command = original.shift();
|
|
1926
|
+
self.exec.apply(self, command);
|
|
1927
|
+
}
|
|
1928
|
+
command_line.visible();
|
|
1929
|
+
scroll_to_bottom();
|
|
1930
|
+
}
|
|
1931
|
+
return self;
|
|
1932
|
+
},
|
|
1933
|
+
cols: function() {
|
|
1934
|
+
return num_chars;
|
|
1935
|
+
},
|
|
1936
|
+
rows: function() {
|
|
1937
|
+
return lines.length;
|
|
1938
|
+
},
|
|
1939
|
+
history: function() {
|
|
1940
|
+
return command_line.history();
|
|
1941
|
+
},
|
|
1942
|
+
next: function() {
|
|
1943
|
+
if (terminals.length() === 1) {
|
|
1944
|
+
return self;
|
|
1945
|
+
} else {
|
|
1946
|
+
var offsetTop = self.offset().top;
|
|
1947
|
+
var height = self.height();
|
|
1948
|
+
var scrollTop = self.scrollTop();
|
|
1949
|
+
if (!is_scrolled_into_view(self)) {
|
|
1950
|
+
self.enable();
|
|
1951
|
+
$('html,body').animate({scrollTop: offsetTop-50}, 500);
|
|
1952
|
+
return self;
|
|
1953
|
+
} else {
|
|
1954
|
+
terminals.front().disable();
|
|
1955
|
+
var next = terminals.rotate().enable();
|
|
1956
|
+
// 100 provides buffer in viewport
|
|
1957
|
+
var x = next.offset().top - 50;
|
|
1958
|
+
$('html,body').animate({scrollTop: x}, 500);
|
|
1959
|
+
try {
|
|
1960
|
+
settings.onTerminalChange(next);
|
|
1961
|
+
} catch (e) {
|
|
1962
|
+
display_exception(e, 'onTerminalChange');
|
|
1963
|
+
throw e;
|
|
1964
|
+
}
|
|
1965
|
+
return next;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
},
|
|
1969
|
+
// silent used so events are not fired on init
|
|
1970
|
+
focus: function(toggle, silent) {
|
|
1971
|
+
self.oneTime(1, function() {
|
|
1972
|
+
if (terminals.length() === 1) {
|
|
1973
|
+
if (toggle === false) {
|
|
1974
|
+
try {
|
|
1975
|
+
if (!silent && settings.onBlur(self) !== false) {
|
|
1976
|
+
self.disable();
|
|
1977
|
+
}
|
|
1978
|
+
} catch (e) {
|
|
1979
|
+
display_exception(e, 'onBlur');
|
|
1980
|
+
throw e;
|
|
1981
|
+
}
|
|
1982
|
+
} else {
|
|
1983
|
+
try {
|
|
1984
|
+
if (!silent && settings.onFocus(self) !== false) {
|
|
1985
|
+
self.enable();
|
|
1986
|
+
}
|
|
1987
|
+
} catch (e) {
|
|
1988
|
+
display_exception(e, 'onFocus');
|
|
1989
|
+
throw e;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
} else {
|
|
1993
|
+
if (toggle === false) {
|
|
1994
|
+
self.next();
|
|
1995
|
+
} else {
|
|
1996
|
+
var front = terminals.front();
|
|
1997
|
+
if (front != self) {
|
|
1998
|
+
front.disable();
|
|
1999
|
+
if (!silent) {
|
|
2000
|
+
try {
|
|
2001
|
+
settings.onTerminalChange(self);
|
|
2002
|
+
} catch (e) {
|
|
2003
|
+
display_exception(e, 'onTerminalChange');
|
|
2004
|
+
throw e;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
terminals.set(self);
|
|
2009
|
+
self.enable();
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
}
|
|
2013
|
+
});
|
|
2014
|
+
return self;
|
|
2015
|
+
},
|
|
2016
|
+
enable: function() {
|
|
2017
|
+
if (num_chars === undefined) {
|
|
2018
|
+
//enabling first time
|
|
2019
|
+
self.resize();
|
|
2020
|
+
}
|
|
2021
|
+
if (pause) {
|
|
2022
|
+
if (command_line) {
|
|
2023
|
+
command_line.enable();
|
|
2024
|
+
pause = false;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
return self;
|
|
2028
|
+
},
|
|
2029
|
+
disable: function() {
|
|
2030
|
+
if (command_line) {
|
|
2031
|
+
pause = true;
|
|
2032
|
+
command_line.disable();
|
|
2033
|
+
}
|
|
2034
|
+
return self;
|
|
2035
|
+
},
|
|
2036
|
+
enabled: function() {
|
|
2037
|
+
return pause;
|
|
2038
|
+
},
|
|
2039
|
+
signature: function() {
|
|
2040
|
+
var cols = self.cols();
|
|
2041
|
+
var i = cols < 15 ? null : cols < 35 ? 0 : cols < 55 ? 1 : cols < 64 ? 2 : cols < 75 ? 3 : 4;
|
|
2042
|
+
if (i !== null) {
|
|
2043
|
+
return signatures[i].join('\n') + '\n';
|
|
2044
|
+
} else {
|
|
2045
|
+
return '';
|
|
2046
|
+
}
|
|
2047
|
+
},
|
|
2048
|
+
version: function() {
|
|
2049
|
+
return version;
|
|
2050
|
+
},
|
|
2051
|
+
/* COMMAND LINE FUNCTIONS */
|
|
2052
|
+
get_command: function() {
|
|
2053
|
+
return command_line.get();
|
|
2054
|
+
},
|
|
2055
|
+
insert: function(string) {
|
|
2056
|
+
if (typeof string === 'string') {
|
|
2057
|
+
command_line.insert(string);
|
|
2058
|
+
return self;
|
|
2059
|
+
} else {
|
|
2060
|
+
throw "insert function argument is not a string";
|
|
2061
|
+
}
|
|
2062
|
+
},
|
|
2063
|
+
set_prompt: function(prompt) {
|
|
2064
|
+
if (validate('prompt', prompt)) {
|
|
2065
|
+
if (typeof prompt == 'function') {
|
|
2066
|
+
command_line.prompt(function(command) {
|
|
2067
|
+
prompt(command, self);
|
|
2068
|
+
});
|
|
2069
|
+
} else {
|
|
2070
|
+
command_line.prompt(prompt);
|
|
2071
|
+
}
|
|
2072
|
+
interpreters.top().prompt = prompt;
|
|
2073
|
+
}
|
|
2074
|
+
return self;
|
|
2075
|
+
},
|
|
2076
|
+
get_prompt: function() {
|
|
2077
|
+
return interpreters.top().prompt;
|
|
2078
|
+
// command_line.prompt(); - can be a wrapper
|
|
2079
|
+
//return command_line.prompt();
|
|
2080
|
+
},
|
|
2081
|
+
set_command: function(command) {
|
|
2082
|
+
command_line.set(command);
|
|
2083
|
+
return self;
|
|
2084
|
+
},
|
|
2085
|
+
set_mask: function(display) {
|
|
2086
|
+
command_line.mask(display);
|
|
2087
|
+
return self;
|
|
2088
|
+
},
|
|
2089
|
+
get_output: function(raw) {
|
|
2090
|
+
if (raw) {
|
|
2091
|
+
return lines;
|
|
2092
|
+
} else {
|
|
2093
|
+
return $.map(lines, function(i, item) {
|
|
2094
|
+
return typeof item == 'function' ? item() : item;
|
|
2095
|
+
}).join('\n');
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
resize: function(width, height) {
|
|
2099
|
+
if (width && height) {
|
|
2100
|
+
self.width(width);
|
|
2101
|
+
self.height(height);
|
|
2102
|
+
}
|
|
2103
|
+
num_chars = get_num_chars();
|
|
2104
|
+
command_line.resize(num_chars);
|
|
2105
|
+
var o = output.detach();
|
|
2106
|
+
output.html('');
|
|
2107
|
+
$.each(lines, function(i, line) {
|
|
2108
|
+
draw_line(line && typeof line == 'function' ? line() : line);
|
|
2109
|
+
});
|
|
2110
|
+
self.prepend(o);
|
|
2111
|
+
scroll_to_bottom();
|
|
2112
|
+
return self;
|
|
2113
|
+
},
|
|
2114
|
+
echo: function(line) {
|
|
2115
|
+
lines.push(line);
|
|
2116
|
+
draw_line(typeof line === 'function' ? line() : line);
|
|
2117
|
+
on_scrollbar_show_resize();
|
|
2118
|
+
return self;
|
|
2119
|
+
},
|
|
2120
|
+
error: function(message) {
|
|
2121
|
+
//echo red message
|
|
2122
|
+
return self.echo('[[;#f00;]' + escape_brackets(message) + ']');
|
|
2123
|
+
},
|
|
2124
|
+
scroll: function(amount) {
|
|
2125
|
+
var pos;
|
|
2126
|
+
amount = Math.round(amount);
|
|
2127
|
+
if (self.prop) {
|
|
2128
|
+
if (amount > self.prop('scrollTop') && amount > 0) {
|
|
2129
|
+
self.prop('scrollTop', 0);
|
|
2130
|
+
}
|
|
2131
|
+
pos = self.prop('scrollTop');
|
|
2132
|
+
self.prop('scrollTop', pos + amount);
|
|
2133
|
+
return self;
|
|
2134
|
+
} else {
|
|
2135
|
+
if (amount > self.attr('scrollTop') && amount > 0) {
|
|
2136
|
+
self.attr('scrollTop', 0);
|
|
2137
|
+
}
|
|
2138
|
+
pos = self.attr('scrollTop');
|
|
2139
|
+
self.attr('scrollTop', pos + amount);
|
|
2140
|
+
return self;
|
|
2141
|
+
}
|
|
2142
|
+
},
|
|
2143
|
+
logout: settings.login ? function() {
|
|
2144
|
+
while (interpreters.size() > 1) {
|
|
2145
|
+
interpreters.pop();
|
|
2146
|
+
}
|
|
2147
|
+
logout();
|
|
2148
|
+
return self;
|
|
2149
|
+
} : function() {
|
|
2150
|
+
throw "You don't have login function";
|
|
2151
|
+
},
|
|
2152
|
+
token: settings.login ? function() {
|
|
2153
|
+
var name = settings.name;
|
|
2154
|
+
return $.Storage.get('token' + (name ? '_' + name : ''));
|
|
2155
|
+
} : $.noop,
|
|
2156
|
+
login_name: settings.login ? function() {
|
|
2157
|
+
var name = settings.name;
|
|
2158
|
+
return $.Storage.get('login' + (name ? '_' + name : ''));
|
|
2159
|
+
} : $.noop,
|
|
2160
|
+
name: function() {
|
|
2161
|
+
return settings.name;
|
|
2162
|
+
},
|
|
2163
|
+
push: function(_eval, options) {
|
|
2164
|
+
if (options && (!options.prompt || validate('prompt', options.prompt)) || !options) {
|
|
2165
|
+
if (typeof _eval === 'string') {
|
|
2166
|
+
_eval = make_json_rpc_eval_fun(options['eval'], self);
|
|
2167
|
+
}
|
|
2168
|
+
interpreters.push($.extend({'eval': _eval}, options));
|
|
2169
|
+
prepare_top_interpreter();
|
|
2170
|
+
}
|
|
2171
|
+
return self;
|
|
2172
|
+
},
|
|
2173
|
+
reset: function() {
|
|
2174
|
+
self.clear();
|
|
2175
|
+
while(interpreters.size() > 1) {
|
|
2176
|
+
interpreters.pop();
|
|
2177
|
+
}
|
|
2178
|
+
initialize();
|
|
2179
|
+
},
|
|
2180
|
+
pop: function(string) {
|
|
2181
|
+
if (string !== undefined) {
|
|
2182
|
+
echo_command(string);
|
|
2183
|
+
}
|
|
2184
|
+
if (interpreters.top().name === settings.name) {
|
|
2185
|
+
if (settings.login) {
|
|
2186
|
+
logout();
|
|
2187
|
+
if (typeof settings.onExit === 'function') {
|
|
2188
|
+
try {
|
|
2189
|
+
settings.onExit(self);
|
|
2190
|
+
} catch (e) {
|
|
2191
|
+
display_exception(e, 'onExit');
|
|
2192
|
+
throw e;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
} else {
|
|
2197
|
+
var current = interpreters.pop();
|
|
2198
|
+
prepare_top_interpreter();
|
|
2199
|
+
if (typeof current.onExit === 'function') {
|
|
2200
|
+
try {
|
|
2201
|
+
current.onExit(self);
|
|
2202
|
+
} catch (e) {
|
|
2203
|
+
display_exception(e, 'onExit');
|
|
2204
|
+
throw e;
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
return self;
|
|
2209
|
+
}
|
|
2210
|
+
}, function(_, fun) {
|
|
2211
|
+
// wrap all functions and display execptions
|
|
2212
|
+
return function() {
|
|
2213
|
+
try {
|
|
2214
|
+
return fun.apply(this, Array.prototype.slice.apply(arguments));
|
|
2215
|
+
} catch(e) {
|
|
2216
|
+
display_exception(e, 'TERMINAL');
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
}));
|
|
2220
|
+
|
|
2221
|
+
//function constructor for eval
|
|
2222
|
+
function make_json_rpc_eval_fun(url, terminal) {
|
|
2223
|
+
var id = 1;
|
|
2224
|
+
var service = function(method, params) {
|
|
2225
|
+
terminal.pause();
|
|
2226
|
+
$.jrpc(url, id++, method, params, function(json) {
|
|
2227
|
+
if (!json.error) {
|
|
2228
|
+
if (typeof json.result === 'string') {
|
|
2229
|
+
terminal.echo(json.result);
|
|
2230
|
+
} else if (json.result instanceof Array) {
|
|
2231
|
+
terminal.echo(json.result.join(' '));
|
|
2232
|
+
} else if (typeof json.result === 'object') {
|
|
2233
|
+
var string = '';
|
|
2234
|
+
for (var f in json.result) {
|
|
2235
|
+
if (json.result.hasOwnProperty(f)) {
|
|
2236
|
+
string += f + ': ' + json.result[f] + '\n';
|
|
2237
|
+
}
|
|
2238
|
+
}
|
|
2239
|
+
terminal.echo(string);
|
|
2240
|
+
}
|
|
2241
|
+
} else {
|
|
2242
|
+
terminal.error('[RPC] ' + json.error.message);
|
|
2243
|
+
}
|
|
2244
|
+
terminal.resume();
|
|
2245
|
+
}, function(xhr, status, error) {
|
|
2246
|
+
terminal.error('[AJAX] ' + status +
|
|
2247
|
+
' - Server reponse is: \n' +
|
|
2248
|
+
xhr.responseText);
|
|
2249
|
+
terminal.resume();
|
|
2250
|
+
});
|
|
2251
|
+
};
|
|
2252
|
+
//this is eval function
|
|
2253
|
+
return function(command, terminal) {
|
|
2254
|
+
if (command === '') {
|
|
2255
|
+
return;
|
|
2256
|
+
}
|
|
2257
|
+
var method, params;
|
|
2258
|
+
if (!command.match(/[^ ]* /)) {
|
|
2259
|
+
method = command;
|
|
2260
|
+
params = [];
|
|
2261
|
+
} else {
|
|
2262
|
+
command = command.split(/ +/);
|
|
2263
|
+
method = command[0];
|
|
2264
|
+
params = command.slice(1);
|
|
2265
|
+
}
|
|
2266
|
+
if (!settings.login || method === 'help') {
|
|
2267
|
+
service(method, params);
|
|
2268
|
+
} else {
|
|
2269
|
+
var token = terminal.token();
|
|
2270
|
+
if (token) {
|
|
2271
|
+
service(method, [token].concat(params));
|
|
2272
|
+
} else {
|
|
2273
|
+
//should never happen
|
|
2274
|
+
terminal.error('[AUTH] Access denied (no token)');
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
|
|
2280
|
+
//display prompt and last command
|
|
2281
|
+
function echo_command(command) {
|
|
2282
|
+
command = command.replace(/\[/g, '[').replace(/\]/g, ']');
|
|
2283
|
+
var prompt = command_line.prompt();
|
|
2284
|
+
if (command_line.mask()) {
|
|
2285
|
+
command = command.replace(/./g, '*');
|
|
2286
|
+
}
|
|
2287
|
+
if (typeof prompt === 'function') {
|
|
2288
|
+
prompt(function(string) {
|
|
2289
|
+
self.echo(string + command);
|
|
2290
|
+
});
|
|
2291
|
+
} else {
|
|
2292
|
+
self.echo(prompt + command);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
// wrapper over eval it implements exit and catch all exeptions
|
|
2297
|
+
// from user code and display them on terminal
|
|
2298
|
+
function commands(command, silent) {
|
|
2299
|
+
try {
|
|
2300
|
+
var interpreter = interpreters.top();
|
|
2301
|
+
if (command === 'exit' && settings.exit) {
|
|
2302
|
+
if (interpreters.size() === 1) {
|
|
2303
|
+
if (settings.login) {
|
|
2304
|
+
logout();
|
|
2305
|
+
} else {
|
|
2306
|
+
var msg = 'You can exit from main interpeter';
|
|
2307
|
+
if (!silent) {
|
|
2308
|
+
echo_command(command);
|
|
2309
|
+
}
|
|
2310
|
+
self.echo(msg);
|
|
2311
|
+
}
|
|
2312
|
+
} else {
|
|
2313
|
+
self.pop('exit');
|
|
2314
|
+
}
|
|
2315
|
+
} else {
|
|
2316
|
+
if (!silent) {
|
|
2317
|
+
echo_command(command);
|
|
2318
|
+
}
|
|
2319
|
+
if (command === 'clear' && settings.clear) {
|
|
2320
|
+
self.clear();
|
|
2321
|
+
} else {
|
|
2322
|
+
interpreter['eval'](command, self);
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
} catch (e) {
|
|
2327
|
+
display_exception(e, 'USER');
|
|
2328
|
+
self.resume();
|
|
2329
|
+
throw e;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
// functions change prompt of command line to login to password
|
|
2334
|
+
// and call user login function with callback that set token
|
|
2335
|
+
// if user call it with value that is true
|
|
2336
|
+
function login() {
|
|
2337
|
+
var user = null;
|
|
2338
|
+
command_line.prompt('login: ');
|
|
2339
|
+
// don't stor logins in history
|
|
2340
|
+
if (settings.history) {
|
|
2341
|
+
command_line.history().disable();
|
|
2342
|
+
}
|
|
2343
|
+
command_line.commands(function(command) {
|
|
2344
|
+
try {
|
|
2345
|
+
echo_command(command);
|
|
2346
|
+
if (!user) {
|
|
2347
|
+
user = command;
|
|
2348
|
+
command_line.prompt('password: ');
|
|
2349
|
+
command_line.mask(true);
|
|
2350
|
+
} else {
|
|
2351
|
+
command_line.mask(false);
|
|
2352
|
+
self.pause();
|
|
2353
|
+
if (typeof settings.login !== 'function') {
|
|
2354
|
+
throw "Value of login property must be a function";
|
|
2355
|
+
}
|
|
2356
|
+
var passwd = command;
|
|
2357
|
+
settings.login(user, passwd, function(token) {
|
|
2358
|
+
if (token) {
|
|
2359
|
+
var name = settings.name;
|
|
2360
|
+
name = (name ? '_' + name : '');
|
|
2361
|
+
$.Storage.set('token' + name, token);
|
|
2362
|
+
$.Storage.set('login' + name, user);
|
|
2363
|
+
//restore commands and run interpreter
|
|
2364
|
+
command_line.commands(commands);
|
|
2365
|
+
// move this to one function init.
|
|
2366
|
+
initialize();
|
|
2367
|
+
} else {
|
|
2368
|
+
self.error('Wrong password try again');
|
|
2369
|
+
command_line.prompt('login: ');
|
|
2370
|
+
user = null;
|
|
2371
|
+
}
|
|
2372
|
+
self.resume();
|
|
2373
|
+
if (settings.history) {
|
|
2374
|
+
command_line.history().enable();
|
|
2375
|
+
}
|
|
2376
|
+
});
|
|
2377
|
+
}
|
|
2378
|
+
} catch (e) {
|
|
2379
|
+
display_exception(e, 'LOGIN', self);
|
|
2380
|
+
throw e;
|
|
2381
|
+
}
|
|
2382
|
+
});
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
//logout function remove Storage, disable history and run login function
|
|
2386
|
+
//this function is call only when options.login function is defined
|
|
2387
|
+
//check for this is in self.pop method
|
|
2388
|
+
function logout() {
|
|
2389
|
+
if (typeof settings.onBeforelogout === 'function') {
|
|
2390
|
+
try {
|
|
2391
|
+
if (settings.onBeforelogout(self) == false) {
|
|
2392
|
+
return;
|
|
2393
|
+
}
|
|
2394
|
+
} catch (e) {
|
|
2395
|
+
display_exception(e, 'onBeforelogout');
|
|
2396
|
+
throw e;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
var name = settings.name;
|
|
2400
|
+
name = (name ? '_' + name : '');
|
|
2401
|
+
$.Storage.remove('token' + name, null);
|
|
2402
|
+
$.Storage.remove('login' + name, null);
|
|
2403
|
+
if (settings.history) {
|
|
2404
|
+
command_line.history().disable();
|
|
2405
|
+
}
|
|
2406
|
+
login();
|
|
2407
|
+
if (typeof settings.onAfterlogout === 'function') {
|
|
2408
|
+
try {
|
|
2409
|
+
settings.onAfterlogout(self);
|
|
2410
|
+
} catch (e) {
|
|
2411
|
+
display_exception(e, 'onAfterlogout');
|
|
2412
|
+
throw e;
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
//function enable history, set prompt, run eval function
|
|
2418
|
+
function prepare_top_interpreter() {
|
|
2419
|
+
var interpreter = interpreters.top();
|
|
2420
|
+
var name = '';
|
|
2421
|
+
if (interpreter.name !== undefined &&
|
|
2422
|
+
interpreter.name !== '') {
|
|
2423
|
+
name += interpreter.name + '_';
|
|
2424
|
+
}
|
|
2425
|
+
name += terminal_id;
|
|
2426
|
+
command_line.name(name);
|
|
2427
|
+
if (typeof interpreter.prompt == 'function') {
|
|
2428
|
+
command_line.prompt(function(command) {
|
|
2429
|
+
interpreter.prompt(command, self);
|
|
2430
|
+
});
|
|
2431
|
+
} else {
|
|
2432
|
+
command_line.prompt(interpreter.prompt);
|
|
2433
|
+
}
|
|
2434
|
+
if (settings.history) {
|
|
2435
|
+
command_line.history().enable();
|
|
2436
|
+
}
|
|
2437
|
+
command_line.set('');
|
|
2438
|
+
if (typeof interpreter.onStart === 'function') {
|
|
2439
|
+
interpreter.onStart(self);
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
function initialize() {
|
|
2443
|
+
prepare_top_interpreter();
|
|
2444
|
+
show_greetings();
|
|
2445
|
+
if (typeof settings.onInit === 'function') {
|
|
2446
|
+
try {
|
|
2447
|
+
settings.onInit(self);
|
|
2448
|
+
} catch (e) {
|
|
2449
|
+
display_exception(e, 'OnInit');
|
|
2450
|
+
throw e;
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
|
|
2455
|
+
// ---------------------------------------------------------------------
|
|
2456
|
+
var on_scrollbar_show_resize = (function() {
|
|
2457
|
+
var scrollBars = haveScrollbars();
|
|
2458
|
+
return function() {
|
|
2459
|
+
if (scrollBars !== haveScrollbars()) {
|
|
2460
|
+
// if scollbars appearance change we will have different
|
|
2461
|
+
// number of chars
|
|
2462
|
+
self.resize();
|
|
2463
|
+
scrollBars = haveScrollbars();
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2466
|
+
})();
|
|
2467
|
+
// ---------------------------------------------------------------------
|
|
2468
|
+
// KEYDOWN EVENT HANDLER
|
|
2469
|
+
// ---------------------------------------------------------------------
|
|
2470
|
+
var tab_count = 0;
|
|
2471
|
+
|
|
2472
|
+
function key_down(e) {
|
|
2473
|
+
var i;
|
|
2474
|
+
// after text pasted into textarea in cmd plugin
|
|
2475
|
+
self.oneTime(5, function() {
|
|
2476
|
+
on_scrollbar_show_resize();
|
|
2477
|
+
});
|
|
2478
|
+
if (settings.keydown && settings.keydown(e, self) === false) {
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2481
|
+
if (!self.paused()) {
|
|
2482
|
+
|
|
2483
|
+
if (e.which !== 9) { // not a TAB
|
|
2484
|
+
tab_count = 0;
|
|
2485
|
+
}
|
|
2486
|
+
if (e.which === 68 && e.ctrlKey) { // CTRL+D
|
|
2487
|
+
if (command_line.get() === '') {
|
|
2488
|
+
if (interpreters.size() > 1 ||
|
|
2489
|
+
settings.login !== undefined) {
|
|
2490
|
+
self.pop('');
|
|
2491
|
+
} else {
|
|
2492
|
+
self.resume();
|
|
2493
|
+
self.echo('');
|
|
2494
|
+
}
|
|
2495
|
+
} else {
|
|
2496
|
+
self.set_command('');
|
|
2497
|
+
}
|
|
2498
|
+
return false;
|
|
2499
|
+
} else if (settings.tabcompletion && e.which === 9) { // TAB
|
|
2500
|
+
// TODO: move this to cmd plugin
|
|
2501
|
+
// add tabcompletion = array | function
|
|
2502
|
+
++tab_count;
|
|
2503
|
+
var command = command_line.get();
|
|
2504
|
+
if (!command.match(' ')) { // complete only first word
|
|
2505
|
+
var reg = new RegExp('^' + command);
|
|
2506
|
+
var commands = interpreters.top().command_list;
|
|
2507
|
+
var matched = [];
|
|
2508
|
+
for (i=commands.length; i--;) {
|
|
2509
|
+
if (reg.test(commands[i])) {
|
|
2510
|
+
matched.push(commands[i]);
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
if (matched.length === 1) {
|
|
2514
|
+
self.set_command(matched[0]);
|
|
2515
|
+
} else if (matched.length > 1) {
|
|
2516
|
+
if (tab_count >= 2) {
|
|
2517
|
+
echo_command(command);
|
|
2518
|
+
self.echo(matched.join('\t'));
|
|
2519
|
+
tab_count = 0;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
return false;
|
|
2524
|
+
} else if (e.which === 86 && e.ctrlKey) { // CTRL+V
|
|
2525
|
+
self.oneTime(1, function() {
|
|
2526
|
+
scroll_to_bottom();
|
|
2527
|
+
});
|
|
2528
|
+
return true;
|
|
2529
|
+
} else if (e.which === 9 && e.ctrlKey) { // CTRL+TAB
|
|
2530
|
+
if (terminals.length() > 1) {
|
|
2531
|
+
self.focus(false);
|
|
2532
|
+
}
|
|
2533
|
+
return false;
|
|
2534
|
+
} else if (e.which === 34) { // PAGE DOWN
|
|
2535
|
+
self.scroll(self.height());
|
|
2536
|
+
} else if (e.which === 33) { // PAGE UP
|
|
2537
|
+
self.scroll(-self.height());
|
|
2538
|
+
} else {
|
|
2539
|
+
self.attr({scrollTop: self.attr('scrollHeight')});
|
|
2540
|
+
}
|
|
2541
|
+
} else {
|
|
2542
|
+
if (e.which === 68 && e.ctrlKey) { // CTRL+D
|
|
2543
|
+
for (i=requests.length; i--;) {
|
|
2544
|
+
var r = requests[i];
|
|
2545
|
+
if (4 !== r.readyState) {
|
|
2546
|
+
try {
|
|
2547
|
+
r.abort();
|
|
2548
|
+
} catch(e) {
|
|
2549
|
+
self.error('error in aborting ajax');
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
self.resume();
|
|
2554
|
+
return false;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
// ---------------------------------------------------------------------
|
|
2559
|
+
// INIT CODE
|
|
2560
|
+
// ---------------------------------------------------------------------
|
|
2561
|
+
var url;
|
|
2562
|
+
if (settings.login && typeof settings.onBeforeLogin === 'function') {
|
|
2563
|
+
try {
|
|
2564
|
+
settings.onBeforeLogin(self);
|
|
2565
|
+
} catch (e) {
|
|
2566
|
+
display_exception(e, 'onBeforeLogin');
|
|
2567
|
+
throw e;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
if (typeof init_eval == 'string') {
|
|
2571
|
+
url = init_eval; //url variable is use when making login function
|
|
2572
|
+
init_eval = make_json_rpc_eval_fun(init_eval, self);
|
|
2573
|
+
} else if (typeof init_eval == 'object' && init_eval.constructor === Array) {
|
|
2574
|
+
throw "You can't use array as eval";
|
|
2575
|
+
} else if (typeof init_eval === 'object') {
|
|
2576
|
+
// top commands
|
|
2577
|
+
for (var i in init_eval) {
|
|
2578
|
+
if (init_eval.hasOwnProperty(i)) {
|
|
2579
|
+
command_list.push(i);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
init_eval = (function make_eval(object) {
|
|
2583
|
+
// function that maps commands to object methods
|
|
2584
|
+
// it keeps terminal context
|
|
2585
|
+
return function(command, terminal) {
|
|
2586
|
+
if (command === '') {
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
command = command.split(/ +/);
|
|
2590
|
+
var method = command[0];
|
|
2591
|
+
var params = command.slice(1);
|
|
2592
|
+
var val = object[method];
|
|
2593
|
+
var type = typeof val;
|
|
2594
|
+
if (type === 'function') {
|
|
2595
|
+
val.apply(self, params);
|
|
2596
|
+
} else if (type === 'object' || type === 'string') {
|
|
2597
|
+
var commands = [];
|
|
2598
|
+
if (type === 'object') {
|
|
2599
|
+
for (var m in val) {
|
|
2600
|
+
if (val.hasOwnProperty(m)) {
|
|
2601
|
+
commands.push(m);
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
val = make_eval(val);
|
|
2605
|
+
}
|
|
2606
|
+
self.push(val, {
|
|
2607
|
+
prompt: method + '> ',
|
|
2608
|
+
name: method,
|
|
2609
|
+
command_list: commands
|
|
2610
|
+
});
|
|
2611
|
+
} else {
|
|
2612
|
+
self.error("Command '" + method + "' Not Found");
|
|
2613
|
+
}
|
|
2614
|
+
};
|
|
2615
|
+
})(init_eval);
|
|
2616
|
+
} else if (typeof init_eval !== 'function') {
|
|
2617
|
+
throw 'Unknow object "' + String(init_eval) + '" passed as eval';
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// create json-rpc authentication function
|
|
2621
|
+
if (url && (typeof settings.login === 'string' || settings.login)) {
|
|
2622
|
+
settings.login = (function(method) {
|
|
2623
|
+
var id = 1;
|
|
2624
|
+
return function(user, passwd, callback) {
|
|
2625
|
+
self.pause();
|
|
2626
|
+
$.jrpc(url,
|
|
2627
|
+
id++,
|
|
2628
|
+
method,
|
|
2629
|
+
[user, passwd],
|
|
2630
|
+
function(response) {
|
|
2631
|
+
self.resume();
|
|
2632
|
+
if (!response.error && response.result) {
|
|
2633
|
+
callback(response.result);
|
|
2634
|
+
} else {
|
|
2635
|
+
callback(null);
|
|
2636
|
+
}
|
|
2637
|
+
}, function(xhr, status, error) {
|
|
2638
|
+
self.resume();
|
|
2639
|
+
self.error('[AJAX\ Response: ' +
|
|
2640
|
+
status + '\n' +
|
|
2641
|
+
xhr.responseText);
|
|
2642
|
+
});
|
|
2643
|
+
};
|
|
2644
|
+
//default name is login so you can pass true
|
|
2645
|
+
})(typeof settings.login === 'boolean' ? 'login' : settings.login);
|
|
2646
|
+
}
|
|
2647
|
+
if (validate('prompt', settings.prompt)) {
|
|
2648
|
+
var interpreters = new Stack({
|
|
2649
|
+
name: settings.name,
|
|
2650
|
+
'eval': init_eval,
|
|
2651
|
+
prompt: settings.prompt,
|
|
2652
|
+
command_list: command_list,
|
|
2653
|
+
greetings: settings.greetings
|
|
2654
|
+
});
|
|
2655
|
+
var command_line = self.find('.terminal-output').next().cmd({
|
|
2656
|
+
prompt: settings.prompt,
|
|
2657
|
+
history: settings.history,
|
|
2658
|
+
historyFilter: settings.historyFilter,
|
|
2659
|
+
width: '100%',
|
|
2660
|
+
keydown: key_down,
|
|
2661
|
+
keypress: settings.keypress ? function(e) {
|
|
2662
|
+
return settings.keypress(e, self);
|
|
2663
|
+
} : null,
|
|
2664
|
+
onCommandChange: function(command) {
|
|
2665
|
+
if (typeof settings.onCommandChange === 'function') {
|
|
2666
|
+
try {
|
|
2667
|
+
settings.onCommandChange(command, self);
|
|
2668
|
+
} catch (e) {
|
|
2669
|
+
display_exception(e, 'onCommandChange');
|
|
2670
|
+
throw e;
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2673
|
+
scroll_to_bottom();
|
|
2674
|
+
},
|
|
2675
|
+
commands: commands
|
|
2676
|
+
});
|
|
2677
|
+
//num_chars = get_num_chars();
|
|
2678
|
+
terminals.append(self);
|
|
2679
|
+
if (settings.enabled === true) {
|
|
2680
|
+
self.focus(undefined, true);
|
|
2681
|
+
} else {
|
|
2682
|
+
self.disable();
|
|
2683
|
+
}
|
|
2684
|
+
$(window).resize(self.resize);
|
|
2685
|
+
self.click(function() {
|
|
2686
|
+
if (!(pause && terminals.length() > 1 && self === $.terminal.active())) {
|
|
2687
|
+
self.focus();
|
|
2688
|
+
}
|
|
2689
|
+
});
|
|
2690
|
+
if (options.login && self.token && !self.token() && self.login_name &&
|
|
2691
|
+
!self.login_name()) {
|
|
2692
|
+
login();
|
|
2693
|
+
} else {
|
|
2694
|
+
initialize();
|
|
2695
|
+
}
|
|
2696
|
+
if (typeof $.fn.init.prototype.mousewheel === 'function') {
|
|
2697
|
+
self.mousewheel(function(event, delta) {
|
|
2698
|
+
//self.echo(dir(event));
|
|
2699
|
+
if (delta > 0) {
|
|
2700
|
+
self.scroll(-40);
|
|
2701
|
+
} else {
|
|
2702
|
+
self.scroll(40);
|
|
2703
|
+
}
|
|
2704
|
+
return false;
|
|
2705
|
+
}, true);
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
self.data('terminal', self);
|
|
2709
|
+
return self;
|
|
2710
|
+
|
|
2711
|
+
}; //terminal plugin
|
|
2712
|
+
})(jQuery);
|