Added --linkify option. Default settings cause the terminal to recognize fully qualified URLs and to make them clickable.
git-svn-id: https://shellinabox.googlecode.com/svn/trunk@134 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
parent
ee1cd17b18
commit
19177de98c
12 changed files with 468 additions and 8 deletions
|
@ -1,3 +1,8 @@
|
|||
2009-07-03 Markus Gutschke <markus@shellinabox.com>
|
||||
|
||||
* Added --linkify option. Default settings cause the terminal to
|
||||
recognize fully qualified URLs and to make them clickable.
|
||||
|
||||
2009-06-28 Markus Gutschke <markus@shellinabox.com>
|
||||
|
||||
* Added support for keyboards that have a dedicated "<" / ">" key.
|
||||
|
|
2
config.h
2
config.h
|
@ -132,7 +132,7 @@
|
|||
#define STDC_HEADERS 1
|
||||
|
||||
/* Most recent revision number in the version control system */
|
||||
#define VCS_REVISION "133"
|
||||
#define VCS_REVISION "134"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.8"
|
||||
|
|
2
configure
vendored
2
configure
vendored
|
@ -2037,7 +2037,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
|
|||
ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
|
||||
VCS_REVISION=133
|
||||
VCS_REVISION=134
|
||||
|
||||
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
|
|
@ -2,7 +2,7 @@ AC_PREREQ(2.57)
|
|||
|
||||
dnl This is the one location where the authoritative version number is stored
|
||||
AC_INIT(shellinabox, 2.8, markus@shellinabox.com)
|
||||
VCS_REVISION=133
|
||||
VCS_REVISION=134
|
||||
AC_SUBST(VCS_REVISION)
|
||||
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
|
||||
[Most recent revision number in the version control system])
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
#vt100 a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#vt100 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#vt100 #reconnect {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
|
138
demo/vt100.js
138
demo/vt100.js
|
@ -96,6 +96,82 @@
|
|||
// #define MOUSE_CLICK 2
|
||||
|
||||
function VT100(container) {
|
||||
if (typeof linkifyURLs == 'undefined' && linkifyURLs > 0) {
|
||||
this.urlRE = null;
|
||||
} else {
|
||||
this.urlRE = new RegExp(
|
||||
// Known URL protocol are "http", "https", and "ftp".
|
||||
'(?:http|https|ftp)://' +
|
||||
|
||||
// Optionally allow username and passwords.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostname.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'[0-9a-fA-F]{0,4}(?::{1,2}[0-9a-fA-F]{1,4})+|' +
|
||||
'(?!-)[^[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+)' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]*)?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|' +
|
||||
|
||||
(linkifyURLs <= 1 ? '' :
|
||||
// Also support URLs without a protocol (assume "http").
|
||||
// Optional username and password.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostnames must end with a well-known top-level domain or must be
|
||||
// numeric.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'localhost|' +
|
||||
'(?:(?!-)[^.[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+[.]){2,}' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+))' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]{0,4})?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|') +
|
||||
|
||||
// In addition, support e-mail address. Optionally, recognize "mailto:"
|
||||
'(?:mailto:)' + (linkifyURLs <= 1 ? '' : '?') +
|
||||
|
||||
// Username:
|
||||
'[-_.+a-zA-Z0-9]+@' +
|
||||
|
||||
// Hostname.
|
||||
'(?!-)[-a-zA-Z0-9]+(?:[.](?!-)[-a-zA-Z0-9]+)?[.]' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+)' +
|
||||
|
||||
// Optional arguments
|
||||
'(?:[?][^/,.) ]+)?');
|
||||
}
|
||||
this.initializeElements(container);
|
||||
this.initializeAnsiColors();
|
||||
this.maxScrollbackLines = 500;
|
||||
|
@ -695,12 +771,72 @@ VT100.prototype.mouseEvent = function(event, type) {
|
|||
return true;
|
||||
};
|
||||
|
||||
VT100.prototype.replaceChar = function(s, ch, repl) {
|
||||
for (var i = -1;;) {
|
||||
i = s.indexOf(ch, i + 1);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
s = s.substr(0, i) + repl + s.substr(i + 1);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
VT100.prototype.htmlEscape = function(s) {
|
||||
return this.replaceChar(this.replaceChar(this.replaceChar(
|
||||
s, '&', '&'), '<', '<'), '"', '"');
|
||||
};
|
||||
|
||||
VT100.prototype.getTextContent = function(elem) {
|
||||
return elem.textContent ||
|
||||
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
|
||||
};
|
||||
|
||||
VT100.prototype.setTextContent = function(elem, s) {
|
||||
// Check if we find any URLs in the text. If so, automatically convert them
|
||||
// to links.
|
||||
if (this.urlRE && this.urlRE.test(s)) {
|
||||
var inner = '';
|
||||
for (;;) {
|
||||
var consumed = 0;
|
||||
if (RegExp.leftContext != null) {
|
||||
inner += this.htmlEscape(RegExp.leftContext);
|
||||
consumed += RegExp.leftContext.length;
|
||||
}
|
||||
var url = this.htmlEscape(RegExp.lastMatch);
|
||||
var fullUrl = url;
|
||||
|
||||
// If no protocol was specified, try to guess a reasonable one.
|
||||
if (url.indexOf('http://') < 0 && url.indexOf('https://') < 0 &&
|
||||
url.indexOf('ftp://') < 0 && url.indexOf('mailto:') < 0) {
|
||||
var slash = url.indexOf('/');
|
||||
var at = url.indexOf('@');
|
||||
var question = url.indexOf('?');
|
||||
if (at > 0 &&
|
||||
(at < question || question < 0) &&
|
||||
(slash < 0 || (question > 0 && slash > question))) {
|
||||
fullUrl = 'mailto:' + url;
|
||||
} else {
|
||||
fullUrl = (url.indexOf('ftp.') == 0 ? 'ftp://' : 'http://') +
|
||||
url;
|
||||
}
|
||||
}
|
||||
|
||||
inner += '<a target="vt100Link" href="' + fullUrl +
|
||||
'">' + url + '</a>';
|
||||
consumed += RegExp.lastMatch.length;
|
||||
s = s.substr(consumed);
|
||||
if (!this.urlRE.test(s)) {
|
||||
if (RegExp.rightContext != null) {
|
||||
inner += this.htmlEscape(RegExp.rightContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
elem.innerHTML = inner;
|
||||
return;
|
||||
}
|
||||
|
||||
// Updating the content of an element is an expensive operation. It actually
|
||||
// pays off to first check whether the element is still unchanged.
|
||||
if (typeof elem.textContent == 'undefined') {
|
||||
|
@ -1500,7 +1636,7 @@ VT100.prototype.toggleBell = function() {
|
|||
};
|
||||
|
||||
VT100.prototype.about = function() {
|
||||
alert("VT100 Terminal Emulator " + "2.8 (revision 133)" +
|
||||
alert("VT100 Terminal Emulator " + "2.8 (revision 134)" +
|
||||
"\nCopyright 2008-2009 by Markus Gutschke\n" +
|
||||
"For more information check http://shellinabox.com");
|
||||
};
|
||||
|
|
|
@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
|
|||
};
|
||||
|
||||
ShellInABox.prototype.about = function() {
|
||||
alert("Shell In A Box version " + "2.8 (revision 133)" +
|
||||
alert("Shell In A Box version " + "2.8 (revision 134)" +
|
||||
"\nCopyright 2008-2009 by Markus Gutschke\n" +
|
||||
"For more information check http://shellinabox.com" +
|
||||
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?
|
||||
|
|
|
@ -84,6 +84,7 @@ static int noBeep = 0;
|
|||
static int numericHosts = 0;
|
||||
static int enableSSL = 1;
|
||||
static int enableSSLMenu = 1;
|
||||
static int linkifyURLs = 1;
|
||||
static char *certificateDir;
|
||||
static int certificateFd = -1;
|
||||
static HashMap *externalFiles;
|
||||
|
@ -522,10 +523,12 @@ static int shellInABoxHttpHandler(HttpConnection *http, void *arg,
|
|||
char *stateVars = stringPrintf(NULL,
|
||||
"serverSupportsSSL = %s;\n"
|
||||
"disableSSLMenu = %s;\n"
|
||||
"suppressAllAudio = %s;\n\n",
|
||||
"suppressAllAudio = %s;\n"
|
||||
"linkifyURLs = %d;\n\n",
|
||||
enableSSL ? "true" : "false",
|
||||
!enableSSLMenu ? "true" : "false",
|
||||
noBeep ? "true" : "false");
|
||||
noBeep ? "true" : "false",
|
||||
linkifyURLs);
|
||||
int stateVarsLength = strlen(stateVars);
|
||||
int contentLength = stateVarsLength +
|
||||
(addr(vt100End) - addr(vt100Start)) +
|
||||
|
@ -596,6 +599,7 @@ static void usage(void) {
|
|||
" -f, --static-file=URL:FILE serve static file from URL path\n"
|
||||
" -g, --group=GID switch to this group (default: %s)\n"
|
||||
" -h, --help print this message\n"
|
||||
" --linkify=[none|normal|agressive] default is \"normal\"\n"
|
||||
" --localhost-only only listen on 127.0.0.1\n"
|
||||
" --no-beep suppress all audio output\n"
|
||||
" -n, --numeric do not resolve hostnames\n"
|
||||
|
@ -666,6 +670,7 @@ static void parseArgs(int argc, char * const argv[]) {
|
|||
{ "debug", 0, 0, 'd' },
|
||||
{ "static-file", 1, 0, 'f' },
|
||||
{ "group", 1, 0, 'g' },
|
||||
{ "linkify", 1, 0, 0 },
|
||||
{ "localhost-only", 0, 0, 0 },
|
||||
{ "no-beep", 0, 0, 0 },
|
||||
{ "numeric", 0, 0, 'n' },
|
||||
|
@ -784,6 +789,18 @@ static void parseArgs(int argc, char * const argv[]) {
|
|||
fatal("Duplicate --group option.");
|
||||
}
|
||||
runAsGroup = parseGroup(optarg, NULL);
|
||||
} else if (!idx--) {
|
||||
// Linkify
|
||||
if (!strcmp(optarg, "none")) {
|
||||
linkifyURLs = 0;
|
||||
} else if (!strcmp(optarg, "normal")) {
|
||||
linkifyURLs = 1;
|
||||
} else if (!strcmp(optarg, "aggressive")) {
|
||||
linkifyURLs = 2;
|
||||
} else {
|
||||
fatal("Invalid argument for --linkify. Must be "
|
||||
"\"none\", \"normal\", or \"aggressive\".");
|
||||
}
|
||||
} else if (!idx--) {
|
||||
// Localhost Only
|
||||
localhostOnly = 1;
|
||||
|
|
|
@ -58,6 +58,7 @@ shellinaboxd \- publish command line shell through AJAX interface
|
|||
[\ \fB-f\fP\ | \fB--static-file=\fP\fIurl\fP:\fIfile\fP\ ]
|
||||
[\ \fB-g\fP\ | \fB--group=\fP\fIgid\fP\ ]
|
||||
[\ \fB-h\fP\ | \fB--help\fP\ ]
|
||||
[\ \fB--linkify\fP=[\fBnone\fP|\fBnormal\fP|\fBaggressive\fP]\ ]
|
||||
[\ \fB--localhost-only\fP\ ]
|
||||
[\ \fB--no-beep\fP\ ]
|
||||
[\ \fB-n\fP\ | \fB--numeric\fP\ ]
|
||||
|
@ -252,6 +253,17 @@ runs as.
|
|||
\fB-h\fP\ |\ \fB--help\fP
|
||||
Display a brief usage message showing the valid command line parameters.
|
||||
.TP
|
||||
\fB--linkify\fP=[\fBnone\fP|\fBnormal\fP|\fBaggressive\fP]
|
||||
the daemon attempts to recognize URLs in the terminal output and makes them
|
||||
clickable. This is not neccessarily a fool-proof process and both false
|
||||
negatives and false positives are possible. By default, only URLs starting
|
||||
with a well known protocol of
|
||||
.BR http:// ,\ https:// ,\ ftp:// ,\ or\ mailto:
|
||||
are recognized. In
|
||||
.B aggressive
|
||||
mode, anything that looks like a hostname, URL or e-mail address is
|
||||
recognized, even if not preceded by a protocol.
|
||||
.TP
|
||||
\fB--localhost-only\fP
|
||||
Normally,
|
||||
.B shellinaboxd
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
#vt100 a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#vt100 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#vt100 #reconnect {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
|
|
@ -96,6 +96,82 @@
|
|||
// #define MOUSE_CLICK 2
|
||||
|
||||
function VT100(container) {
|
||||
if (typeof linkifyURLs == 'undefined' && linkifyURLs > 0) {
|
||||
this.urlRE = null;
|
||||
} else {
|
||||
this.urlRE = new RegExp(
|
||||
// Known URL protocol are "http", "https", and "ftp".
|
||||
'(?:http|https|ftp)://' +
|
||||
|
||||
// Optionally allow username and passwords.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostname.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'[0-9a-fA-F]{0,4}(?::{1,2}[0-9a-fA-F]{1,4})+|' +
|
||||
'(?!-)[^[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+)' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]*)?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|' +
|
||||
|
||||
(linkifyURLs <= 1 ? '' :
|
||||
// Also support URLs without a protocol (assume "http").
|
||||
// Optional username and password.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostnames must end with a well-known top-level domain or must be
|
||||
// numeric.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'localhost|' +
|
||||
'(?:(?!-)[^.[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+[.]){2,}' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+))' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]{0,4})?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|') +
|
||||
|
||||
// In addition, support e-mail address. Optionally, recognize "mailto:"
|
||||
'(?:mailto:)' + (linkifyURLs <= 1 ? '' : '?') +
|
||||
|
||||
// Username:
|
||||
'[-_.+a-zA-Z0-9]+@' +
|
||||
|
||||
// Hostname.
|
||||
'(?!-)[-a-zA-Z0-9]+(?:[.](?!-)[-a-zA-Z0-9]+)?[.]' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+)' +
|
||||
|
||||
// Optional arguments
|
||||
'(?:[?][^/,.) ]+)?');
|
||||
}
|
||||
this.initializeElements(container);
|
||||
this.initializeAnsiColors();
|
||||
this.maxScrollbackLines = 500;
|
||||
|
@ -695,12 +771,72 @@ VT100.prototype.mouseEvent = function(event, type) {
|
|||
return true;
|
||||
};
|
||||
|
||||
VT100.prototype.replaceChar = function(s, ch, repl) {
|
||||
for (var i = -1;;) {
|
||||
i = s.indexOf(ch, i + 1);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
s = s.substr(0, i) + repl + s.substr(i + 1);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
VT100.prototype.htmlEscape = function(s) {
|
||||
return this.replaceChar(this.replaceChar(this.replaceChar(
|
||||
s, '&', '&'), '<', '<'), '"', '"');
|
||||
};
|
||||
|
||||
VT100.prototype.getTextContent = function(elem) {
|
||||
return elem.textContent ||
|
||||
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
|
||||
};
|
||||
|
||||
VT100.prototype.setTextContent = function(elem, s) {
|
||||
// Check if we find any URLs in the text. If so, automatically convert them
|
||||
// to links.
|
||||
if (this.urlRE && this.urlRE.test(s)) {
|
||||
var inner = '';
|
||||
for (;;) {
|
||||
var consumed = 0;
|
||||
if (RegExp.leftContext != null) {
|
||||
inner += this.htmlEscape(RegExp.leftContext);
|
||||
consumed += RegExp.leftContext.length;
|
||||
}
|
||||
var url = this.htmlEscape(RegExp.lastMatch);
|
||||
var fullUrl = url;
|
||||
|
||||
// If no protocol was specified, try to guess a reasonable one.
|
||||
if (url.indexOf('http://') < 0 && url.indexOf('https://') < 0 &&
|
||||
url.indexOf('ftp://') < 0 && url.indexOf('mailto:') < 0) {
|
||||
var slash = url.indexOf('/');
|
||||
var at = url.indexOf('@');
|
||||
var question = url.indexOf('?');
|
||||
if (at > 0 &&
|
||||
(at < question || question < 0) &&
|
||||
(slash < 0 || (question > 0 && slash > question))) {
|
||||
fullUrl = 'mailto:' + url;
|
||||
} else {
|
||||
fullUrl = (url.indexOf('ftp.') == 0 ? 'ftp://' : 'http://') +
|
||||
url;
|
||||
}
|
||||
}
|
||||
|
||||
inner += '<a target="vt100Link" href="' + fullUrl +
|
||||
'">' + url + '</a>';
|
||||
consumed += RegExp.lastMatch.length;
|
||||
s = s.substr(consumed);
|
||||
if (!this.urlRE.test(s)) {
|
||||
if (RegExp.rightContext != null) {
|
||||
inner += this.htmlEscape(RegExp.rightContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
elem.innerHTML = inner;
|
||||
return;
|
||||
}
|
||||
|
||||
// Updating the content of an element is an expensive operation. It actually
|
||||
// pays off to first check whether the element is still unchanged.
|
||||
if (typeof elem.textContent == 'undefined') {
|
||||
|
@ -1500,7 +1636,7 @@ VT100.prototype.toggleBell = function() {
|
|||
};
|
||||
|
||||
VT100.prototype.about = function() {
|
||||
alert("VT100 Terminal Emulator " + "2.8 (revision 133)" +
|
||||
alert("VT100 Terminal Emulator " + "2.8 (revision 134)" +
|
||||
"\nCopyright 2008-2009 by Markus Gutschke\n" +
|
||||
"For more information check http://shellinabox.com");
|
||||
};
|
||||
|
|
|
@ -96,6 +96,82 @@
|
|||
#define MOUSE_CLICK 2
|
||||
|
||||
function VT100(container) {
|
||||
if (typeof linkifyURLs == 'undefined' && linkifyURLs > 0) {
|
||||
this.urlRE = null;
|
||||
} else {
|
||||
this.urlRE = new RegExp(
|
||||
// Known URL protocol are "http", "https", and "ftp".
|
||||
'(?:http|https|ftp)://' +
|
||||
|
||||
// Optionally allow username and passwords.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostname.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'[0-9a-fA-F]{0,4}(?::{1,2}[0-9a-fA-F]{1,4})+|' +
|
||||
'(?!-)[^[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+)' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]*)?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|' +
|
||||
|
||||
(linkifyURLs <= 1 ? '' :
|
||||
// Also support URLs without a protocol (assume "http").
|
||||
// Optional username and password.
|
||||
'(?:[^:@/ ]*(?::[^@/ ]*)?@)?' +
|
||||
|
||||
// Hostnames must end with a well-known top-level domain or must be
|
||||
// numeric.
|
||||
'(?:[1-9][0-9]{0,2}(?:[.][1-9][0-9]{0,2}){3}|' +
|
||||
'localhost|' +
|
||||
'(?:(?!-)[^.[!"#$%&\'()*+,/:;<=>?@\\^_`{|}~\u0000- \u009F]+[.]){2,}' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+))' +
|
||||
|
||||
// Port
|
||||
'(?::[1-9][0-9]{0,4})?' +
|
||||
|
||||
// Path.
|
||||
'(?:/[^/,.) ]*)*|') +
|
||||
|
||||
// In addition, support e-mail address. Optionally, recognize "mailto:"
|
||||
'(?:mailto:)' + (linkifyURLs <= 1 ? '' : '?') +
|
||||
|
||||
// Username:
|
||||
'[-_.+a-zA-Z0-9]+@' +
|
||||
|
||||
// Hostname.
|
||||
'(?!-)[-a-zA-Z0-9]+(?:[.](?!-)[-a-zA-Z0-9]+)?[.]' +
|
||||
'(?:com|net|org|edu|gov|aero|asia|biz|cat|coop|info|int|jobs|mil|mobi|' +
|
||||
'museum|name|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|' +
|
||||
'au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|' +
|
||||
'ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|' +
|
||||
'dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|' +
|
||||
'gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|' +
|
||||
'ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|' +
|
||||
'lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|' +
|
||||
'mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|' +
|
||||
'pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|' +
|
||||
'sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|' +
|
||||
'tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|' +
|
||||
'yu|za|zm|zw|arpa|[Xx][Nn]--[-a-zA-Z0-9]+)' +
|
||||
|
||||
// Optional arguments
|
||||
'(?:[?][^/,.) ]+)?');
|
||||
}
|
||||
this.initializeElements(container);
|
||||
this.initializeAnsiColors();
|
||||
this.maxScrollbackLines = 500;
|
||||
|
@ -695,12 +771,72 @@ VT100.prototype.mouseEvent = function(event, type) {
|
|||
return true;
|
||||
};
|
||||
|
||||
VT100.prototype.replaceChar = function(s, ch, repl) {
|
||||
for (var i = -1;;) {
|
||||
i = s.indexOf(ch, i + 1);
|
||||
if (i < 0) {
|
||||
break;
|
||||
}
|
||||
s = s.substr(0, i) + repl + s.substr(i + 1);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
VT100.prototype.htmlEscape = function(s) {
|
||||
return this.replaceChar(this.replaceChar(this.replaceChar(
|
||||
s, '&', '&'), '<', '<'), '"', '"');
|
||||
};
|
||||
|
||||
VT100.prototype.getTextContent = function(elem) {
|
||||
return elem.textContent ||
|
||||
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
|
||||
};
|
||||
|
||||
VT100.prototype.setTextContent = function(elem, s) {
|
||||
// Check if we find any URLs in the text. If so, automatically convert them
|
||||
// to links.
|
||||
if (this.urlRE && this.urlRE.test(s)) {
|
||||
var inner = '';
|
||||
for (;;) {
|
||||
var consumed = 0;
|
||||
if (RegExp.leftContext != null) {
|
||||
inner += this.htmlEscape(RegExp.leftContext);
|
||||
consumed += RegExp.leftContext.length;
|
||||
}
|
||||
var url = this.htmlEscape(RegExp.lastMatch);
|
||||
var fullUrl = url;
|
||||
|
||||
// If no protocol was specified, try to guess a reasonable one.
|
||||
if (url.indexOf('http://') < 0 && url.indexOf('https://') < 0 &&
|
||||
url.indexOf('ftp://') < 0 && url.indexOf('mailto:') < 0) {
|
||||
var slash = url.indexOf('/');
|
||||
var at = url.indexOf('@');
|
||||
var question = url.indexOf('?');
|
||||
if (at > 0 &&
|
||||
(at < question || question < 0) &&
|
||||
(slash < 0 || (question > 0 && slash > question))) {
|
||||
fullUrl = 'mailto:' + url;
|
||||
} else {
|
||||
fullUrl = (url.indexOf('ftp.') == 0 ? 'ftp://' : 'http://') +
|
||||
url;
|
||||
}
|
||||
}
|
||||
|
||||
inner += '<a target="vt100Link" href="' + fullUrl +
|
||||
'">' + url + '</a>';
|
||||
consumed += RegExp.lastMatch.length;
|
||||
s = s.substr(consumed);
|
||||
if (!this.urlRE.test(s)) {
|
||||
if (RegExp.rightContext != null) {
|
||||
inner += this.htmlEscape(RegExp.rightContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
elem.innerHTML = inner;
|
||||
return;
|
||||
}
|
||||
|
||||
// Updating the content of an element is an expensive operation. It actually
|
||||
// pays off to first check whether the element is still unchanged.
|
||||
if (typeof elem.textContent == 'undefined') {
|
||||
|
|
Loading…
Add table
Reference in a new issue