/files/jquery.terminal/0.7.8/jquery.terminal-src.js
JavaScript | 1207 lines | 1087 code | 27 blank | 93 comment | 95 complexity | fb5c95232952fce84aeeb2435220dd75 MD5 | raw file
- /**@license
- *| __ _____ ________ __
- *| / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
- *| __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
- *| / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
- *| \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
- *| \/ /____/ version {{VER}}
- * http://terminal.jcubic.pl
- *
- * Licensed under GNU LGPL Version 3 license
- * Copyright (c) 2011-2013 Jakub Jankiewicz <http://jcubic.pl>
- *
- * Includes:
- *
- * Storage plugin Distributed under the MIT License
- * Copyright (c) 2010 Dave Schindler
- *
- * jQuery Timers licenced with the WTFPL
- * <http://jquery.offput.ca/every/>
- *
- * Cross-Browser Split 1.1.1
- * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
- * Available under the MIT License
- *
- * Date: {{DATE}}
- */
- (function($, undefined) {
- //"use strict";
- // -----------------------------------------------------------------------
- // :: map object to object
- // -----------------------------------------------------------------------
- $.omap = function(o, fn) {
- var result = {};
- $.each(o, function(k, v) {
- result[k] = fn.call(o, k, v);
- });
- return result;
- };
- // -----------------------------------------------------------------------
- // :: Storage plugin
- // -----------------------------------------------------------------------
- // Private data
- var isLS = typeof window.localStorage !== 'undefined';
- // Private functions
- function wls(n, v) {
- var c;
- if (typeof n === 'string' && typeof v === 'string') {
- localStorage[n] = v;
- return true;
- } else if (typeof n === 'object' && typeof v === 'undefined') {
- for (c in n) {
- if (n.hasOwnProperty(c)) {
- localStorage[c] = n[c];
- }
- }
- return true;
- }
- return false;
- }
- function wc(n, v) {
- var dt, e, c;
- dt = new Date();
- dt.setTime(dt.getTime() + 31536000000);
- e = '; expires=' + dt.toGMTString();
- if (typeof n === 'string' && typeof v === 'string') {
- document.cookie = n + '=' + v + e + '; path=/';
- return true;
- } else if (typeof n === 'object' && typeof v === 'undefined') {
- for (c in n) {
- if (n.hasOwnProperty(c)) {
- document.cookie = c + '=' + n[c] + e + '; path=/';
- }
- }
- return true;
- }
- return false;
- }
- function rls(n) {
- return localStorage[n];
- }
- function rc(n) {
- var nn, ca, i, c;
- nn = n + '=';
- ca = document.cookie.split(';');
- for (i = 0; i < ca.length; i++) {
- c = ca[i];
- while (c.charAt(0) === ' ') {
- c = c.substring(1, c.length);
- }
- if (c.indexOf(nn) === 0) {
- return c.substring(nn.length, c.length);
- }
- }
- return null;
- }
- function dls(n) {
- return delete localStorage[n];
- }
- function dc(n) {
- return wc(n, '', -1);
- }
- /**
- * Public API
- * $.Storage.set("name", "value")
- * $.Storage.set({"name1":"value1", "name2":"value2", etc})
- * $.Storage.get("name")
- * $.Storage.remove("name")
- */
- $.extend({
- Storage: {
- set: isLS ? wls : wc,
- get: isLS ? rls : rc,
- remove: isLS ? dls : dc
- }
- });
- // -----------------------------------------------------------------------
- // :: jQuery Timers
- // -----------------------------------------------------------------------
- jQuery.fn.extend({
- everyTime: function(interval, label, fn, times, belay) {
- return this.each(function() {
- jQuery.timer.add(this, interval, label, fn, times, belay);
- });
- },
- oneTime: function(interval, label, fn) {
- return this.each(function() {
- jQuery.timer.add(this, interval, label, fn, 1);
- });
- },
- stopTime: function(label, fn) {
- return this.each(function() {
- jQuery.timer.remove(this, label, fn);
- });
- }
- });
- jQuery.extend({
- timer: {
- guid: 1,
- global: {},
- regex: /^([0-9]+)\s*(.*s)?$/,
- powers: {
- // Yeah this is major overkill...
- 'ms': 1,
- 'cs': 10,
- 'ds': 100,
- 's': 1000,
- 'das': 10000,
- 'hs': 100000,
- 'ks': 1000000
- },
- timeParse: function(value) {
- if (value === undefined || value === null) {
- return null;
- }
- var result = this.regex.exec(jQuery.trim(value.toString()));
- if (result[2]) {
- var num = parseInt(result[1], 10);
- var mult = this.powers[result[2]] || 1;
- return num * mult;
- } else {
- return value;
- }
- },
- add: function(element, interval, label, fn, times, belay) {
- var counter = 0;
- if (jQuery.isFunction(label)) {
- if (!times) {
- times = fn;
- }
- fn = label;
- label = interval;
- }
- interval = jQuery.timer.timeParse(interval);
- if (typeof interval !== 'number' ||
- isNaN(interval) ||
- interval <= 0) {
- return;
- }
- if (times && times.constructor !== Number) {
- belay = !!times;
- times = 0;
- }
- times = times || 0;
- belay = belay || false;
- if (!element.$timers) {
- element.$timers = {};
- }
- if (!element.$timers[label]) {
- element.$timers[label] = {};
- }
- fn.$timerID = fn.$timerID || this.guid++;
- var handler = function() {
- if (belay && handler.inProgress) {
- return;
- }
- handler.inProgress = true;
- if ((++counter > times && times !== 0) ||
- fn.call(element, counter) === false) {
- jQuery.timer.remove(element, label, fn);
- }
- handler.inProgress = false;
- };
- handler.$timerID = fn.$timerID;
- if (!element.$timers[label][fn.$timerID]) {
- element.$timers[label][fn.$timerID] = window.setInterval(handler, interval);
- }
- if (!this.global[label]) {
- this.global[label] = [];
- }
- this.global[label].push(element);
- },
- remove: function(element, label, fn) {
- var timers = element.$timers, ret;
- if (timers) {
- if (!label) {
- for (var lab in timers) {
- if (timers.hasOwnProperty(lab)) {
- this.remove(element, lab, fn);
- }
- }
- } else if (timers[label]) {
- if (fn) {
- if (fn.$timerID) {
- window.clearInterval(timers[label][fn.$timerID]);
- delete timers[label][fn.$timerID];
- }
- } else {
- for (var _fn in timers[label]) {
- if (timers[label].hasOwnProperty(_fn)) {
- window.clearInterval(timers[label][_fn]);
- delete timers[label][_fn];
- }
- }
- }
- for (ret in timers[label]) {
- if (timers[label].hasOwnProperty(ret)) {
- break;
- }
- }
- if (!ret) {
- ret = null;
- delete timers[label];
- }
- }
- for (ret in timers) {
- if (timers.hasOwnProperty(ret)) {
- break;
- }
- }
- if (!ret) {
- element.$timers = null;
- }
- }
- }
- }
- });
- if (jQuery.browser && jQuery.browser.msie ||
- /(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase())) {
- jQuery(window).one('unload', function() {
- var global = jQuery.timer.global;
- for (var label in global) {
- if (global.hasOwnProperty(label)) {
- var els = global[label], i = els.length;
- while (--i) {
- jQuery.timer.remove(els[i], label);
- }
- }
- }
- });
- }
- // -----------------------------------------------------------------------
- // :: CROSS BROWSER SPLIT
- // -----------------------------------------------------------------------
- (function(undef) {
- // prevent double include
- if (!String.prototype.split.toString().match(/\[native/)) {
- return;
- }
- var nativeSplit = String.prototype.split,
- compliantExecNpcg = /()??/.exec("")[1] === undef, // NPCG: nonparticipating capturing group
- self;
- self = function (str, separator, limit) {
- // If `separator` is not a regex, use `nativeSplit`
- if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
- return nativeSplit.call(str, separator, limit);
- }
- var output = [],
- flags = (separator.ignoreCase ? "i" : "") +
- (separator.multiline ? "m" : "") +
- (separator.extended ? "x" : "") + // Proposed for ES6
- (separator.sticky ? "y" : ""), // Firefox 3+
- lastLastIndex = 0,
- // Make `global` and avoid `lastIndex` issues by working with a copy
- separator2, match, lastIndex, lastLength;
- separator = new RegExp(separator.source, flags + "g");
- str += ""; // Type-convert
- if (!compliantExecNpcg) {
- // Doesn't need flags gy, but they don't hurt
- separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
- }
- /* Values for `limit`, per the spec:
- * If undefined: 4294967295 // Math.pow(2, 32) - 1
- * If 0, Infinity, or NaN: 0
- * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
- * If negative number: 4294967296 - Math.floor(Math.abs(limit))
- * If other: Type-convert, then use the above rules
- */
- // ? Math.pow(2, 32) - 1 : ToUint32(limit)
- limit = limit === undef ? -1 >>> 0 : limit >>> 0;
- while (match = separator.exec(str)) {
- // `separator.lastIndex` is not reliable cross-browser
- lastIndex = match.index + match[0].length;
- if (lastIndex > lastLastIndex) {
- output.push(str.slice(lastLastIndex, match.index));
- // Fix browsers whose `exec` methods don't consistently return `undefined` for
- // nonparticipating capturing groups
- if (!compliantExecNpcg && match.length > 1) {
- match[0].replace(separator2, function () {
- for (var i = 1; i < arguments.length - 2; i++) {
- if (arguments[i] === undef) {
- match[i] = undef;
- }
- }
- });
- }
- if (match.length > 1 && match.index < str.length) {
- Array.prototype.push.apply(output, match.slice(1));
- }
- lastLength = match[0].length;
- lastLastIndex = lastIndex;
- if (output.length >= limit) {
- break;
- }
- }
- if (separator.lastIndex === match.index) {
- separator.lastIndex++; // Avoid an infinite loop
- }
- }
- if (lastLastIndex === str.length) {
- if (lastLength || !separator.test("")) {
- output.push("");
- }
- } else {
- output.push(str.slice(lastLastIndex));
- }
- return output.length > limit ? output.slice(0, limit) : output;
- };
- // For convenience
- String.prototype.split = function (separator, limit) {
- return self(this, separator, limit);
- };
- return self;
- })();
- // -----------------------------------------------------------------------
- /*
- function decodeHTML(str) {
- if (typeof str === 'string') {
- str = str.replace(/&/g, '&');
- str = str.replace(/</g, '<').replace(/>/g, '>');
- str = str.replace(/	/g, '\t');
- str = str.replace(/<br\/?>/g, '\n').replace(/ /g, ' ');
- return str;
- } else {
- return '';
- }
- }
- */
- //split string to array of strings with the same length
- // -----------------------------------------------------------------------
- // :: Split String into equal parts
- // -----------------------------------------------------------------------
- function str_parts(str, length) {
- var result = [];
- var len = str.length;
- if (len < length) {
- return [str];
- }
- for (var i = 0; i < len; i += length) {
- result.push(str.substring(i, i + length));
- }
- return result;
- }
- // -----------------------------------------------------------------------
- // :: CYCLE DATA STRUCTURE
- // -----------------------------------------------------------------------
- function Cycle(init) {
- var data = init ? [init] : [];
- var pos = 0;
- $.extend(this, {
- get: function() {
- return data;
- },
- rotate: function() {
- if (data.length === 1) {
- return data[0];
- } else {
- if (pos === data.length - 1) {
- pos = 0;
- } else {
- ++pos;
- }
- return data[pos];
- }
- },
- length: function() {
- return data.length;
- },
- set: function(item) {
- for (var i = data.length; i--;) {
- if (data[i] === item) {
- pos = i;
- return;
- }
- }
- this.append(item);
- },
- front: function() {
- return data[pos];
- },
- append: function(item) {
- data.push(item);
- }
- });
- }
- // -----------------------------------------------------------------------
- // :: STACK DATA STRUCTURE
- // -----------------------------------------------------------------------
- function Stack(init) {
- var data = init ? [init] : [];
- $.extend(this, {
- size: function() {
- return data.length;
- },
- pop: function() {
- if (data.length === 0) {
- return null;
- } else {
- var value = data[data.length - 1];
- data = data.slice(0, data.length - 1);
- return value;
- }
- },
- push: function(value) {
- data = data.concat([value]);
- return value;
- },
- top: function() {
- return data.length > 0 ? data[data.length - 1] : null;
- }
- });
- }
- // -----------------------------------------------------------------------
- // :: Serialize object myself (biwascheme or prototype library do something
- // :: wiked with JSON serialization for Arrays)
- // -----------------------------------------------------------------------
- $.json_stringify = function(object, level) {
- var result = '', i;
- level = level === undefined ? 1 : level;
- var type = typeof object;
- switch (type) {
- case 'function':
- result += object;
- break;
- case 'boolean':
- result += object ? 'true' : 'false';
- break;
- case 'object':
- if (object === null) {
- result += 'null';
- } else if (object instanceof Array) {
- result += '[';
- var len = object.length;
- for (i = 0; i < len - 1; ++i) {
- result += $.json_stringify(object[i], level + 1);
- }
- result += $.json_stringify(object[len - 1], level + 1) + ']';
- } else {
- result += '{';
- for (var property in object) {
- if (object.hasOwnProperty(property)) {
- result += '"' + property + '":' +
- $.json_stringify(object[property], level + 1);
- }
- }
- result += '}';
- }
- break;
- case 'string':
- var str = object;
- var repl = {
- '\\\\': '\\\\',
- '"': '\\"',
- '/': '\\/',
- '\\n': '\\n',
- '\\r': '\\r',
- '\\t': '\\t'};
- for (i in repl) {
- if (repl.hasOwnProperty(i)) {
- str = str.replace(new RegExp(i, 'g'), repl[i]);
- }
- }
- result += '"' + str + '"';
- break;
- case 'number':
- result += String(object);
- break;
- }
- result += (level > 1 ? ',' : '');
- // quick hacks below
- if (level === 1) {
- // fix last comma
- result = result.replace(/,([\]}])/g, '$1');
- }
- // fix comma before array or object
- return result.replace(/([\[{]),/g, '$1');
- };
- // -----------------------------------------------------------------------
- // :: HISTORY CLASS
- // -----------------------------------------------------------------------
- function History(name, size) {
- var enabled = true;
- if (typeof name === 'string' && name !== '') {
- name += '_';
- }
- var data = $.Storage.get(name + 'commands');
- data = data ? new Function('return ' + data + ';')() : [];
- var pos = data.length-1;
- $.extend(this, {
- append: function(item) {
- if (enabled) {
- if (data[data.length-1] !== item) {
- data.push(item);
- pos = data.length-1;
- if (size && data.length > size) {
- data = data.slice(-size);
- }
- $.Storage.set(name + 'commands', $.json_stringify(data));
- }
- }
- },
- data: function() {
- return data;
- },
- next: function() {
- if (pos < data.length-1) {
- ++pos;
- }
- if (pos !== -1) {
- return data[pos];
- }
- },
- reset: function() {
- pos = data.length-1;
- },
- last: function() {
- return data[length-1];
- },
- end: function() {
- return pos === data.length-1;
- },
- position: function() {
- return pos;
- },
- previous: function() {
- var old = pos;
- if (pos > 0) {
- --pos;
- }
- if (old !== -1) {
- return data[old];
- }
- },
- clear: function() {
- data = [];
- this.purge();
- },
- enabled: function() {
- return enabled;
- },
- enable: function() {
- enabled = true;
- },
- purge: function() {
- $.Storage.remove(name + 'commands');
- },
- disable: function() {
- enabled = false;
- }
- });
- }
- // -----------------------------------------------------------------------
- // :: COMMAND LINE PLUGIN
- // -----------------------------------------------------------------------
- $.fn.cmd = function(options) {
- var self = this;
- var maybe_data = self.data('cmd');
- if (maybe_data) {
- return maybe_data;
- }
- self.addClass('cmd');
- self.append('<span class="prompt"></span><span></span>' +
- '<span class="cursor"> </span><span></span>');
- var clip = $('<textarea/>').addClass('clipboard').appendTo(self);
- if (options.width) {
- self.width(options.width);
- }
- var num_chars; // calculates by draw_prompt
- var prompt_len;
- var reverse_search = false;
- var reverse_search_string = '';
- var reverse_search_position = null;
- var backup_prompt;
- var mask = options.mask || false;
- var command = '';
- var position = 0;
- var prompt;
- var enabled = options.enabled;
- var historySize = options.historySize || 60;
- var name, history;
- var cursor = self.find('.cursor');
- // -----------------------------------------------------------------------
- // ::Blinking cursor function
- // -----------------------------------------------------------------------
- function blink(i) {
- cursor.toggleClass('inverted');
- }
- // -----------------------------------------------------------------------
- // :: Set prompt for reverse search
- // -----------------------------------------------------------------------
- function draw_reverse_prompt() {
- prompt = "(reverse-i-search)`" + reverse_search_string + "': ";
- draw_prompt();
- }
- // -----------------------------------------------------------------------
- // :: Disable reverse search
- // -----------------------------------------------------------------------
- function clear_reverse_state() {
- prompt = backup_prompt;
- reverse_search = false;
- reverse_search_position = null;
- reverse_search_string = '';
- }
- // -----------------------------------------------------------------------
- // :: Search through command line history. If next is not defined or false
- // :: it search for first item from the end. If true it search for next item
- // -----------------------------------------------------------------------
- function reverse_history_search(next) {
- var history_data = history.data();
- var regex;
- var len = history_data.length;
- if (next && reverse_search_position > 0) {
- len -= reverse_search_position;
- }
- if (reverse_search_string.length > 0) {
- for (var j=reverse_search_string.length; j>0; j--) {
- regex = new RegExp('^' + reverse_search_string.substring(0, j));
- for (var i=len; i--;) {
- if (regex.test(history_data[i])) {
- reverse_search_position = history_data.length - i;
- position = 0;
- self.set(history_data[i], true);
- redraw();
- if (reverse_search_string.length !== j) {
- reverse_search_string = reverse_search_string.substring(0, j);
- draw_reverse_prompt();
- }
- return;
- }
- }
- }
- }
- }
- // -----------------------------------------------------------------------
- // :: Recalculate number of characters in command line
- // -----------------------------------------------------------------------
- function change_num_chars() {
- var W = self.width();
- var w = cursor.innerWidth();
- num_chars = Math.floor(W / w);
- }
- // -----------------------------------------------------------------------
- // :: Return string repeated n times
- // -----------------------------------------------------------------------
- function str_repeat(str, n) {
- var result = '';
- for (var i = n; i--;) {
- result += str;
- }
- return result;
- }
- // -----------------------------------------------------------------------
- // :: Split String that fit into command line where first line need to
- // :: fit next to prompt (need to have less characters)
- // -----------------------------------------------------------------------
- function get_splited_command_line(string) {
- var first = string.substring(0, num_chars - prompt_len);
- var rest = string.substring(num_chars - prompt_len);
- return [first].concat(str_parts(rest, num_chars));
- }
- // -----------------------------------------------------------------------
- // :: Function that display command line. Split long line and place cursor
- // :: in right place
- // -----------------------------------------------------------------------
- var redraw = (function(self) {
- var before = cursor.prev();
- var after = cursor.next();
- // -----------------------------------------------------------------------
- // :: Draw line with the cursor
- // -----------------------------------------------------------------------
- function draw_cursor_line(string, position) {
- var len = string.length;
- if (position === len) {
- before.html($.terminal.encode(string, true));
- cursor.html(' ');
- after.html('');
- } else if (position === 0) {
- before.html('');
- //fix for tilda in IE
- cursor.html($.terminal.encode(string.slice(0, 1), true));
- //cursor.html($.terminal.encode(string[0]));
- after.html($.terminal.encode(string.slice(1), true));
- } else {
- var before_str = $.terminal.encode(string.slice(0, position), true);
- before.html(before_str);
- //fix for tilda in IE
- var c = string.slice(position, position + 1);
- //cursor.html(string[position]));
- cursor.html(c === ' ' ? ' ' : $.terminal.encode(c, true));
- if (position === string.length - 1) {
- after.html('');
- } else {
- after.html($.terminal.encode(string.slice(position + 1), true));
- }
- }
- }
- function div(string) {
- return '<div>' + $.terminal.encode(string, true) + '</div>';
- }
- // -----------------------------------------------------------------------
- // :: Display lines afer cursor
- // -----------------------------------------------------------------------
- function lines_after(lines) {
- var last_ins = after;
- $.each(lines, function(i, line) {
- last_ins = $(div(line)).insertAfter(last_ins).
- addClass('clear');
- });
- }
- // -----------------------------------------------------------------------
- // :: Display lines before the cursor
- // -----------------------------------------------------------------------
- function lines_before(lines) {
- $.each(lines, function(i, line) {
- before.before(div(line));
- });
- }
- var count = 0;
- // -----------------------------------------------------------------------
- // :: Redraw function
- // -----------------------------------------------------------------------
- return function() {
- var string = mask ? command.replace(/./g, '*') : command;
- var i, first_len;
- self.find('div').remove();
- before.html('');
- // long line
- if (string.length > num_chars - prompt_len - 1 ||
- string.match(/\n/)) {
- var array;
- var tabs = string.match(/\t/g);
- var tabs_rm = tabs ? tabs.length * 3 : 0;
- //quick tabulation hack
- if (tabs) {
- string = string.replace(/\t/g, '\x00\x00\x00\x00');
- }
- // command contain new line characters
- if (string.match(/\n/)) {
- var tmp = string.split("\n");
- first_len = num_chars - prompt_len - 1;
- // empty character after each line
- for (i=0; i<tmp.length-1; ++i) {
- tmp[i] += ' ';
- }
- // split first line
- if (tmp[0].length > first_len) {
- array = [tmp[0].substring(0, first_len)];
- array = array.concat(str_parts(tmp[0].substring(first_len), num_chars));
- } else {
- array = [tmp[0]];
- }
- // process rest of the lines
- for (i=1; i<tmp.length; ++i) {
- if (tmp[i].length > num_chars) {
- array = array.concat(str_parts(tmp[i], num_chars));
- } else {
- array.push(tmp[i]);
- }
- }
- } else {
- array = get_splited_command_line(string);
- }
- if (tabs) {
- array = $.map(array, function(line) {
- return line.replace(/\x00\x00\x00\x00/g, '\t');
- });
- }
- first_len = array[0].length;
- //cursor in first line
- if (first_len === 0 && array.length === 1) {
- // skip empty line
- } else if (position < first_len) {
- draw_cursor_line(array[0], position);
- lines_after(array.slice(1));
- } else if (position === first_len) {
- before.before(div(array[0]));
- draw_cursor_line(array[1], 0);
- lines_after(array.slice(2));
- } else {
- var num_lines = array.length;
- var offset = 0;
- if (position < first_len) {
- draw_cursor_line(array[0], position);
- lines_after(array.slice(1));
- } else if (position === first_len) {
- before.before(div(array[0]));
- draw_cursor_line(array[1], 0);
- lines_after(array.slice(2));
- } else {
- var last = array.slice(-1)[0];
- var from_last = string.length - position;
- var last_len = last.length;
- var pos = 0;
- if (from_last <= last_len) {
- lines_before(array.slice(0, -1));
- pos = last_len === from_last ? 0 : last_len-from_last;
- draw_cursor_line(last, pos+tabs_rm);
- } else {
- // in the middle
- if (num_lines === 3) {
- before.before('<div>' + $.terminal.encode(array[0], true) +
- '</div>');
- draw_cursor_line(array[1], position-first_len-1);
- after.after('<div class="clear">' +
- $.terminal.encode(array[2], true) +
- '</div>');
- } else {
- // more lines, cursor in the middle
- var line_index;
- var current;
- pos = position;
- for (i=0; i<array.length; ++i) {
- var current_len = array[i].length;
- if (pos > current_len) {
- pos -= current_len;
- } else {
- break;
- }
- }
- current = array[i];
- line_index = i;
- // cursor on first character in line
- if (pos === current.length) {
- pos = 0;
- current = array[++line_index];
- }
- draw_cursor_line(current, pos);
- lines_before(array.slice(0, line_index));
- lines_after(array.slice(line_index+1));
- }
- }
- }
- }
- } else {
- if (string === '') {
- before.html('');
- cursor.html(' ');
- after.html('');
- } else {
- draw_cursor_line(string, position);
- }
- }
- };
- })(self);
- var last_command;
- // -----------------------------------------------------------------------
- // :: Draw prompt that can be a function or a string
- // -----------------------------------------------------------------------
- var draw_prompt = (function() {
- var prompt_node = self.find('.prompt');
- function set(prompt) {
- prompt_len = skipFormattingCount(prompt);
- prompt_node.html($.terminal.format($.terminal.encode(prompt)));
- }
- return function() {
- switch (typeof prompt) {
- case 'string':
- set(prompt);
- break;
- case 'function':
- prompt(set);
- break;
- }
- };
- })();
- // -----------------------------------------------------------------------
- // :: Paste content to terminal using hidden textarea
- // -----------------------------------------------------------------------
- function paste() {
- clip.focus();
- //wait until Browser insert text to textarea
- self.oneTime(1, function() {
- self.insert(clip.val());
- clip.blur().val('');
- });
- }
- var first_up_history = true;
- //var prevent_keypress = false;
- // -----------------------------------------------------------------------
- // :: Keydown Event Handler
- // -----------------------------------------------------------------------
- function keydown_event(e) {
- var result, pos, len;
- if (typeof options.keydown == 'function') {
- result = options.keydown(e);
- if (result !== undefined) {
- //prevent_keypress = true;
- return result;
- }
- }
- if (enabled) {
- if (e.which !== 38 &&
- !(e.which === 80 && e.ctrlKey)) {
- first_up_history = true;
- }
- // arrows / Home / End / ENTER
- if (reverse_search && (e.which === 35 || e.which === 36 ||
- e.which === 37 || e.which === 38 ||
- e.which === 39 || e.which === 40 ||
- e.which === 13 || e.which === 27)) {
- clear_reverse_state();
- draw_prompt();
- if (e.which === 27) { // ESC
- command = '';
- }
- redraw();
- // finish reverse search and execute normal event handler
- keydown_event.call(this, e);
- } else if (e.altKey) {
- // Chrome on Windows set ctrlKey and altKey for alt
- // need to check for alt first
- //if (e.which === 18) { // press ALT
- if (e.which === 68) { //ALT+D
- self.set(command.slice(0, position) +
- command.slice(position).replace(/[^ ]+ |[^ ]+$/, ''),
- true);
- // chrome jump to address bar
- return false;
- }
- return true;
- } else if (e.keyCode === 13) { //enter
- if ((history && command) &&
- ((options.historyFilter &&
- options.historyFilter(command)) ||
- !options.historyFilter)) {
- history.append(command);
- }
- var tmp = command;
- history.reset();
- self.set('');
- if (options.commands) {
- options.commands(tmp);
- }
- if (typeof prompt === 'function') {
- draw_prompt();
- }
- } else if (e.which === 8) { //backspace
- if (reverse_search) {
- reverse_search_string = reverse_search_string.slice(0, -1);
- draw_reverse_prompt();
- } else {
- if (command !== '' && position > 0) {
- command = command.slice(0, position - 1) +
- command.slice(position, command.length);
- --position;
- redraw();
- }
- }
- } else if (e.which === 9 && !(e.ctrlKey || e.altKey)) { // TAB
- self.insert('\t');
- } else if (e.which === 46) {
- //DELETE
- if (command !== '' && position < command.length) {
- command = command.slice(0, position) +
- command.slice(position + 1, command.length);
- redraw();
- }
- return true;
- } else if (history && e.which === 38 ||
- (e.which === 80 && e.ctrlKey)) {
- //UP ARROW or CTRL+P
- if (first_up_history) {
- last_command = command;
- }
- first_up_history = false;
- self.set(history.previous());
- } else if (history && e.which === 40 ||
- (e.which === 78 && e.ctrlKey)) {
- //DOWN ARROW or CTRL+N
- self.set(history.end() ? last_command : history.next());
- } else if (e.which === 37 ||
- (e.which === 66 && e.ctrlKey)) {
- //CTRL+LEFT ARROW or CTRL+B
- if (e.ctrlKey && e.which !== 66) {
- len = position - 1;
- pos = 0;
- if (command[len] === ' ') {
- --len;
- }
- for (var i = len; i > 0; --i) {
- if (command[i] === ' ' && command[i+1] !== ' ') {
- pos = i + 1;
- break;
- } else if (command[i] === '\n' && command[i+1] !== '\n') {
- pos = i;
- break;
- }
- }
- self.position(pos);
- } else {
- //LEFT ARROW or CTRL+B
- if (position > 0) {
- --position;
- redraw();
- }
- }
- } else if (e.which === 82 && e.ctrlKey) { // CTRL+R
- if (reverse_search) {
- reverse_history_search(true);
- } else {
- backup_prompt = prompt;
- draw_reverse_prompt();
- last_command = command;
- command = '';
- redraw();
- reverse_search = true;
- }
- } else if (e.which == 71 && e.ctrlKey) { // CTRL+G
- if (reverse_search) {
- prompt = backup_prompt;
- draw_prompt();
- command = last_command;
- redraw();
- reverse_search = false;
- }
- } else if (e.which === 39 ||
- (e.which === 70 && e.ctrlKey)) {
- //RIGHT ARROW OR CTRL+F
- if (e.ctrlKey && e.which !== 70) {
- // jump to beginig or end of the word
- if (command[position] === ' ') {
- ++position;
- }
- var match = command.slice(position).match(/\S[\n\s]{2,}|[\n\s]+\S?/);
- if (!match || match[0].match(/^\s+$/)) {
- position = command.length;
- } else {
- if (match[0][0] !== ' ') {
- position += match.index + 1;
- } else {
- position += match.index + match[0].length - 1;
- if (match[0][match[0].length-1] !== ' ') {
- --position;
- }
- }
- }
- redraw();
- } else {
- if (position < command.length) {
- ++position;
- redraw();
- }
- }
- } else if (e.which === 123) { //F12 - Allow Firebug
- return true;
- } else if (e.which === 36) { //HOME
- self.position(0);
- } else if (e.which === 35) {
- //END
- self.position(command.length);
- } else if (e.shiftKey && e.which == 45) { // Shift+Insert
- paste();
- return true;
- } else if (e.ctrlKey || e.metaKey) {
- if (e.which === 192) { // CMD+` switch browser window on Mac
- return true;
- }
- if (e.metaKey) {
- if(e.which === 82) { // CMD+r page reload in Chrome Mac
- return true;
- } else if(e.which === 76) {
- return true; // CMD+l jump into Ominbox on Chrome Mac
- }
- }
- if (e.shiftKey) { // CTRL+SHIFT+??
- if (e.which === 84) {
- //CTRL+SHIFT+T open closed tab
- return true;
- }
- //} else if (e.altKey) { //ALT+CTRL+??
- } else {
- if (e.which === 87) { // CTRL+W
- if (command !== '') {
- var first = command.slice(0, position);
- var last = command.slice(position+1);
- var m = first.match(/([^ ]+ *$)/);
- position = first.length-m[0].length;
- command = first.slice(0, position) + last;
- redraw();
- }
- return false;
- } else if (e.which === 72) { // CTRL+H
- if (command !== '' && position > 0) {
- command = command.slice(0, --position);
- if (position < command.length-1) {
- command += command.slice(position);
- }
- redraw();
- }
- return false;
- //NOTE: in opera charCode is undefined
- } else if (e.which === 65) {
- //CTRL+A
- self.position(0);
- } else if (e.which === 69) {
- //CTRL+E
- self.position(command.length);
- } else if (e.which === 88 || e.which === 67 || e.which === 84) {
- //CTRL+X CTRL+C CTRL+W CTRL+T
- return true;
- } else if (e.which === 86) {
- //CTRL+V
- paste();
- return true;
- } else if (e.which === 75) {
- //CTRL+K
- if (position === 0) {
- self.set('');
- } else if (position !== command.length) {
- self.set(command.slice(0, position));
- }
- } else if (e.which === 85) { // CTRL+U
- self.set(command.slice(position, command.length));
- self.position(0);
- } else if (e.which === 17) { //CTRL+TAB switch tab
- return false;
- }
- }
- } else {
- return true;
- }
- return false;
- } /*else {
- if ((e.altKey && e.which === 68) ||
- (e.ctrlKey &&
- $.inArray(e.which, [65, 66, 68, 69, 80, 78, 70]) > -1) ||
- // 68 === D
- [35, 36, 37, 38, 39, 40].has(e.which)) {
- return false;
- }
- } */
- }
- var history_list = [];
- // -----------------------------------------------------------------------
- // :: Command Line Methods
- // -----------------------------------------------------------------------
- $.extend(self, {
- name: function(string) {
- if (string !== undefined) {
- name = string;
- history = new History(str