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.
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);