parade 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/LICENSE +21 -0
  2. data/README.md +542 -0
  3. data/Rakefile +15 -0
  4. data/bin/parade +138 -0
  5. data/lib/parade.rb +43 -0
  6. data/lib/parade/commands/commands.rb +84 -0
  7. data/lib/parade/commands/generate_outline.rb +34 -0
  8. data/lib/parade/commands/generate_presentation.rb +34 -0
  9. data/lib/parade/commands/generate_rackup.rb +32 -0
  10. data/lib/parade/commands/html_output.rb +47 -0
  11. data/lib/parade/commands/render_from_template.rb +50 -0
  12. data/lib/parade/commands/static_html.rb +38 -0
  13. data/lib/parade/commands/static_pdf.rb +39 -0
  14. data/lib/parade/commands/unknown.rb +23 -0
  15. data/lib/parade/features/live_ruby.rb +18 -0
  16. data/lib/parade/features/pdf_presentation.rb +24 -0
  17. data/lib/parade/features/preshow.rb +11 -0
  18. data/lib/parade/helpers/encode_image.rb +24 -0
  19. data/lib/parade/helpers/template_generator.rb +130 -0
  20. data/lib/parade/metadata.rb +73 -0
  21. data/lib/parade/metadata/assignment.rb +38 -0
  22. data/lib/parade/metadata/css_classes.rb +22 -0
  23. data/lib/parade/metadata/html_id.rb +35 -0
  24. data/lib/parade/metadata/template.rb +31 -0
  25. data/lib/parade/parsers/dsl.rb +138 -0
  26. data/lib/parade/parsers/dsl_file_parser.rb +17 -0
  27. data/lib/parade/parsers/json_file_parser.rb +67 -0
  28. data/lib/parade/parsers/markdown_image_paths.rb +44 -0
  29. data/lib/parade/parsers/markdown_slide_splitter.rb +63 -0
  30. data/lib/parade/parsers/presentation_directory_parser.rb +36 -0
  31. data/lib/parade/parsers/presentation_file_parser.rb +27 -0
  32. data/lib/parade/parsers/presentation_filepath_parser.rb +35 -0
  33. data/lib/parade/parsers/slides_file_content_parser.rb +27 -0
  34. data/lib/parade/renderers/columns_renderer.rb +68 -0
  35. data/lib/parade/renderers/command_line_renderer.rb +142 -0
  36. data/lib/parade/renderers/html_with_pygments.rb +42 -0
  37. data/lib/parade/renderers/inline_images.rb +31 -0
  38. data/lib/parade/renderers/special_paragraph_renderer.rb +23 -0
  39. data/lib/parade/renderers/update_image_paths.rb +75 -0
  40. data/lib/parade/section.rb +183 -0
  41. data/lib/parade/server.rb +139 -0
  42. data/lib/parade/slide.rb +128 -0
  43. data/lib/parade/version.rb +3 -0
  44. data/lib/public/css/960.css +653 -0
  45. data/lib/public/css/fg.menu.css +114 -0
  46. data/lib/public/css/ghf_marked.css +180 -0
  47. data/lib/public/css/jquery-terminal.css +73 -0
  48. data/lib/public/css/onepage.css +62 -0
  49. data/lib/public/css/parade.css +450 -0
  50. data/lib/public/css/pdf.css +13 -0
  51. data/lib/public/css/reset.css +53 -0
  52. data/lib/public/css/spinner_bar.gif +0 -0
  53. data/lib/public/css/theme/images/ui-bg_diagonals-small_100_f0efea_40x40.png +0 -0
  54. data/lib/public/css/theme/images/ui-bg_flat_35_f0f0f0_40x100.png +0 -0
  55. data/lib/public/css/theme/images/ui-bg_glass_55_fcf0ba_1x400.png +0 -0
  56. data/lib/public/css/theme/images/ui-bg_glow-ball_25_2e2e28_600x600.png +0 -0
  57. data/lib/public/css/theme/images/ui-bg_highlight-soft_100_f0efea_1x100.png +0 -0
  58. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_327E04_1x100.png +0 -0
  59. data/lib/public/css/theme/images/ui-bg_highlight-soft_25_5A9D1A_1x100.png +0 -0
  60. data/lib/public/css/theme/images/ui-bg_highlight-soft_95_ffedad_1x100.png +0 -0
  61. data/lib/public/css/theme/images/ui-bg_inset-soft_22_3b3b35_1x100.png +0 -0
  62. data/lib/public/css/theme/images/ui-icons_808080_256x240.png +0 -0
  63. data/lib/public/css/theme/images/ui-icons_8DC262_256x240.png +0 -0
  64. data/lib/public/css/theme/images/ui-icons_cd0a0a_256x240.png +0 -0
  65. data/lib/public/css/theme/images/ui-icons_e7e6e4_256x240.png +0 -0
  66. data/lib/public/css/theme/images/ui-icons_eeeeee_256x240.png +0 -0
  67. data/lib/public/css/theme/images/ui-icons_ffffff_256x240.png +0 -0
  68. data/lib/public/css/theme/ui.accordion.css +9 -0
  69. data/lib/public/css/theme/ui.all.css +2 -0
  70. data/lib/public/css/theme/ui.base.css +9 -0
  71. data/lib/public/css/theme/ui.core.css +37 -0
  72. data/lib/public/css/theme/ui.datepicker.css +62 -0
  73. data/lib/public/css/theme/ui.dialog.css +13 -0
  74. data/lib/public/css/theme/ui.progressbar.css +4 -0
  75. data/lib/public/css/theme/ui.resizable.css +13 -0
  76. data/lib/public/css/theme/ui.slider.css +17 -0
  77. data/lib/public/css/theme/ui.tabs.css +9 -0
  78. data/lib/public/css/theme/ui.theme.css +245 -0
  79. data/lib/public/favicon.ico +0 -0
  80. data/lib/public/js/coffee-script.js +8 -0
  81. data/lib/public/js/fg.menu.js +645 -0
  82. data/lib/public/js/jTypeWriter.js +26 -0
  83. data/lib/public/js/jquery-1.4.2.js +6240 -0
  84. data/lib/public/js/jquery-print.js +109 -0
  85. data/lib/public/js/jquery-pubsub.js +27 -0
  86. data/lib/public/js/jquery-terminal.js +2712 -0
  87. data/lib/public/js/jquery.batchImageLoad.js +56 -0
  88. data/lib/public/js/jquery.cycle.all.js +1284 -0
  89. data/lib/public/js/keyboard.js +733 -0
  90. data/lib/public/js/parade-code-execution.js +122 -0
  91. data/lib/public/js/parade-command-input.js +16 -0
  92. data/lib/public/js/parade-command-visor.js +92 -0
  93. data/lib/public/js/parade-keyboard-input.js +54 -0
  94. data/lib/public/js/parade.js +675 -0
  95. data/lib/public/js/spine.js +904 -0
  96. data/lib/templates/config.ru.erb +4 -0
  97. data/lib/templates/showoff.erb +27 -0
  98. data/lib/templates/slides.md.erb +25 -0
  99. data/lib/views/header.erb +73 -0
  100. data/lib/views/index.erb +53 -0
  101. data/lib/views/inline_css.erb +3 -0
  102. data/lib/views/inline_js.erb +3 -0
  103. data/lib/views/onepage.erb +17 -0
  104. data/lib/views/pdf.erb +17 -0
  105. data/lib/views/slide.erb +5 -0
  106. 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(/&amp;/g, '&');
420
+ str = str.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
421
+ str = str.replace(/&#09;/g, '\t');
422
+ str = str.replace(/<br\/?>/g, '\n').replace(/&nbsp;/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">&nbsp;</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('&nbsp;');
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 === ' ' ? '&nbsp;' : $.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('&nbsp;');
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, '&amp;')
1421
+ .replace(/</g, '&lt;').replace(/>/g, '&gt;')
1422
+ // I don't think that it find \n
1423
+ .replace(/\n/g, '<br/>')
1424
+ .replace(/ /g, '&nbsp;')
1425
+ .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;');
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>&nbsp;</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, '&#91;').replace(/\]/g, '&#93;');
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('&#91;' + label + '&#93;: ' + 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('&#91;' + e.lineNumber + '&#93;: ' + 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>&nbsp;</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('&#91;RPC&#93; ' + json.error.message);
2243
+ }
2244
+ terminal.resume();
2245
+ }, function(xhr, status, error) {
2246
+ terminal.error('&#91;AJAX&#93; ' + 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('&#91;AUTH&#93; 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, '&#91;').replace(/\]/g, '&#93;');
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('&#91;AJAX&#92; 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);