mirror of
https://github.com/coderaiser/cloudcmd.git
synced 2026-07-21 02:29:23 +00:00
feature(console) update to v2.8.0
This commit is contained in:
parent
dd5370074f
commit
0bea992779
25 changed files with 16121 additions and 196 deletions
|
|
@ -132,13 +132,15 @@ var CloudCmd, Util, DOM, CloudFunc, $;
|
|||
Util.time(Name + ' load');
|
||||
|
||||
var lDir = CloudCmd.LIBDIRCLIENT + 'console/',
|
||||
cssPath = lDir + 'css/',
|
||||
jsPath = lDir + 'lib/',
|
||||
lCSS = [
|
||||
lDir + 'jqconsole.css',
|
||||
lDir + 'ansi.css'
|
||||
cssPath + 'jqconsole.css',
|
||||
cssPath + 'ansi.css'
|
||||
],
|
||||
lAllCSS = CloudFunc.getJoinURL(lCSS),
|
||||
lFiles = [
|
||||
lDir + 'jqconsole.js',
|
||||
jsPath + 'jqconsole.js',
|
||||
lAllCSS
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ task 'watch', 'Build and watch the CoffeeScript source files', ->
|
|||
|
||||
task 'build', 'Build minified file with uglify', ->
|
||||
console.log 'building...'
|
||||
exec 'uglifyjs -o jqconsole.min.js lib/jqconsole.js', (err, res)->
|
||||
exec 'uglifyjs -m -o jqconsole.min.js lib/jqconsole.js', (err, res)->
|
||||
if err
|
||||
console.error 'failed with', err
|
||||
else
|
||||
|
|
|
|||
|
|
@ -66,3 +66,11 @@ info.
|
|||
|
||||
2013.1.26 Version 2.7.7
|
||||
* Support for middle click paste on linux. #47.
|
||||
|
||||
2013.8.5 Version 2.7.8
|
||||
* Fix issue #51.
|
||||
|
||||
2014.2.3 Version 2.8.0
|
||||
* Remove browser sniffing. Fix #37 #42 #53
|
||||
* Update android support. Fix #41
|
||||
* Add wrapper div for padding/styling of console. Fix #40
|
||||
|
|
|
|||
|
|
@ -134,8 +134,7 @@ Takes two arguments:
|
|||
Sets the number of spaces inserted when indenting and removed when unindenting.
|
||||
Takes one argument:
|
||||
|
||||
* __int__ *width*: The code of the key pressing which (when Ctrl is held) will
|
||||
trigger this shortcut.
|
||||
* __int__ *width*: The number of spaces in each indentation level.
|
||||
|
||||
|
||||
Example:
|
||||
|
|
@ -720,4 +719,8 @@ further customization.
|
|||
##Contributors
|
||||
|
||||
[Max Shawabkeh](http://max99x.com/)
|
||||
[Amjad Masad](http://twitter.com/amjad_masad)
|
||||
[Amjad Masad](http://twitter.com/amasad)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](http://opensource.org/licenses/MIT)
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
.jqconsole-ansi-bold {
|
||||
/* font-weight: bold; */
|
||||
}
|
||||
|
|
@ -121,10 +120,10 @@
|
|||
color: red;
|
||||
}
|
||||
.jqconsole-ansi-color-green {
|
||||
color: #65b04b;
|
||||
color: green;
|
||||
}
|
||||
.jqconsole-ansi-color-yellow {
|
||||
color: #fed563;
|
||||
color: yellow;
|
||||
}
|
||||
.jqconsole-ansi-color-blue {
|
||||
color: rgb(49,123,249);
|
||||
|
|
@ -146,10 +145,10 @@
|
|||
background-color: red;
|
||||
}
|
||||
.jqconsole-ansi-background-color-green {
|
||||
background-color: #65b04b;
|
||||
background-color: green;
|
||||
}
|
||||
.jqconsole-ansi-background-color-yellow {
|
||||
background-color: #fed563;
|
||||
background-color: yellow;
|
||||
}
|
||||
.jqconsole-ansi-background-color-blue {
|
||||
background-color: blue;
|
||||
78
lib/client/console/demos/echo.html
Normal file
78
lib/client/console/demos/echo.html
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
/* The console container element */
|
||||
#console {
|
||||
height: 400px;
|
||||
width: 750px;
|
||||
position:relative;
|
||||
background-color: black;
|
||||
border: 2px solid #CCC;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
}
|
||||
/* The inner console element. */
|
||||
.jqconsole {
|
||||
padding: 10px;
|
||||
}
|
||||
/* The cursor. */
|
||||
.jqconsole-cursor {
|
||||
background-color: gray;
|
||||
}
|
||||
/* The cursor color when the console looses focus. */
|
||||
.jqconsole-blurred .jqconsole-cursor {
|
||||
background-color: #666;
|
||||
}
|
||||
/* The current prompt text color */
|
||||
.jqconsole-prompt {
|
||||
color: #0d0;
|
||||
}
|
||||
/* The command history */
|
||||
.jqconsole-old-prompt {
|
||||
color: #0b0;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* The text color when in input mode. */
|
||||
.jqconsole-input {
|
||||
color: #dd0;
|
||||
}
|
||||
/* Previously entered input. */
|
||||
.jqconsole-old-input {
|
||||
color: #bb0;
|
||||
font-weight: normal;
|
||||
}
|
||||
/* The text color of the output. */
|
||||
.jqconsole-output {
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="console"></div>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../lib/jqconsole.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
var jqconsole = $('#console').jqconsole('Hi\n', '>>> ');
|
||||
var startPrompt = function () {
|
||||
// Start the prompt with history enabled.
|
||||
jqconsole.Prompt(true, function (input) {
|
||||
// Output input with the class jqconsole-output.
|
||||
jqconsole.Write(input + '\n', 'jqconsole-output');
|
||||
// Restart the prompt.
|
||||
startPrompt();
|
||||
});
|
||||
};
|
||||
startPrompt();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
120
lib/client/console/demos/index.html
Normal file
120
lib/client/console/demos/index.html
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="../css/ansi.css" type="text/css" media="all" />
|
||||
<style>
|
||||
html, body {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#console {
|
||||
height: 400px;
|
||||
width: 750px;
|
||||
position:relative;
|
||||
background-color: black;
|
||||
border: 2px solid #CCC;
|
||||
margin: 0 auto;
|
||||
margin-top: 50px;
|
||||
}
|
||||
.jqconsole {
|
||||
padding: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.jqconsole-cursor {
|
||||
background-color: #999;
|
||||
}
|
||||
.jqconsole-blurred .jqconsole-cursor {
|
||||
background-color: #666;
|
||||
}
|
||||
.jqconsole-prompt {
|
||||
color: #0d0;
|
||||
}
|
||||
.jqconsole-old-prompt {
|
||||
color: #0b0;
|
||||
font-weight: normal;
|
||||
}
|
||||
.jqconsole-input {
|
||||
color: #dd0;
|
||||
}
|
||||
.jqconsole-old-input {
|
||||
color: #bb0;
|
||||
font-weight: normal;
|
||||
}
|
||||
.brace {
|
||||
color: #00FFFF;
|
||||
}
|
||||
.paran {
|
||||
color: #FF00FF;
|
||||
}
|
||||
.bracket {
|
||||
color: #FFFF00;
|
||||
}
|
||||
.jqconsole-composition {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="console"></div>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../lib/jqconsole.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
// Creating the console.
|
||||
var header = 'Welcome to JQConsole!\n' +
|
||||
'Use jqconsole.Write() to write and ' +
|
||||
'jqconsole.Input() to read.\n';
|
||||
window.jqconsole = $('#console').jqconsole(header, 'JS> ');
|
||||
|
||||
// Abort prompt on Ctrl+Z.
|
||||
jqconsole.RegisterShortcut('Z', function() {
|
||||
jqconsole.AbortPrompt();
|
||||
handler();
|
||||
});
|
||||
// Move to line start Ctrl+A.
|
||||
jqconsole.RegisterShortcut('A', function() {
|
||||
jqconsole.MoveToStart();
|
||||
handler();
|
||||
});
|
||||
// Move to line end Ctrl+E.
|
||||
jqconsole.RegisterShortcut('E', function() {
|
||||
jqconsole.MoveToEnd();
|
||||
handler();
|
||||
});
|
||||
jqconsole.RegisterMatching('{', '}', 'brace');
|
||||
jqconsole.RegisterMatching('(', ')', 'paran');
|
||||
jqconsole.RegisterMatching('[', ']', 'bracket');
|
||||
// Handle a command.
|
||||
var handler = function(command) {
|
||||
if (command) {
|
||||
try {
|
||||
jqconsole.Write('==> ' + window.eval(command) + '\n');
|
||||
} catch (e) {
|
||||
jqconsole.Write('ERROR: ' + e.message + '\n');
|
||||
}
|
||||
}
|
||||
jqconsole.Prompt(true, handler, function(command) {
|
||||
// Continue line if can't compile the command.
|
||||
try {
|
||||
Function(command);
|
||||
} catch (e) {
|
||||
if (/[\[\{\(]$/.test(command)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
// Initiate the first prompt.
|
||||
handler();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "jqconsole",
|
||||
"version": "2.7.7",
|
||||
"version": "2.8.0",
|
||||
"title": "Feature complete web terminal.",
|
||||
"author": {
|
||||
"name": "Amjad Masad",
|
||||
|
|
|
|||
23
lib/client/console/karma.conf.js
Normal file
23
lib/client/console/karma.conf.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
module.exports = function(config) {
|
||||
config.set({
|
||||
frameworks: ["mocha"],
|
||||
files: [
|
||||
'test/vendor/*.js',
|
||||
'lib/*.js',
|
||||
'test/setup.coffee',
|
||||
'test/ansi-test.coffee',
|
||||
'test/jqconsole-test.coffee',
|
||||
'test/prompt-test.coffee',
|
||||
'test/shortcuts-test.coffee',
|
||||
'test/history-test.coffee',
|
||||
],
|
||||
browsers: ['Chrome'],
|
||||
reporters: ['dots'],
|
||||
coffeePreprocessor: {
|
||||
// options passed to the coffee compiler
|
||||
options: {
|
||||
bare: false,
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -1,72 +1,9 @@
|
|||
// Generated by CoffeeScript 1.3.3
|
||||
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
Copyrights 2011, the repl.it project.
|
||||
Licensed under the MIT license
|
||||
*/
|
||||
// Limit scope pollution from any deprecated API
|
||||
(function() {
|
||||
|
||||
var matched, browser;
|
||||
|
||||
// Use of jQuery.browser is frowned upon.
|
||||
// More details: http://api.jquery.com/jQuery.browser
|
||||
// jQuery.uaMatch maintained for back-compat
|
||||
jQuery.uaMatch = function( ua ) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
|
||||
/(msie) ([\w.]+)/.exec( ua ) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
|
||||
matched = jQuery.uaMatch( navigator.userAgent );
|
||||
browser = {};
|
||||
|
||||
if ( matched.browser ) {
|
||||
browser[ matched.browser ] = true;
|
||||
browser.version = matched.version;
|
||||
}
|
||||
|
||||
// Chrome is Webkit, but Webkit is also Safari.
|
||||
if ( browser.chrome ) {
|
||||
browser.webkit = true;
|
||||
} else if ( browser.webkit ) {
|
||||
browser.safari = true;
|
||||
}
|
||||
|
||||
jQuery.browser = browser;
|
||||
|
||||
jQuery.sub = function() {
|
||||
function jQuerySub( selector, context ) {
|
||||
return new jQuerySub.fn.init( selector, context );
|
||||
}
|
||||
jQuery.extend( true, jQuerySub, this );
|
||||
jQuerySub.superclass = this;
|
||||
jQuerySub.fn = jQuerySub.prototype = this();
|
||||
jQuerySub.fn.constructor = jQuerySub;
|
||||
jQuerySub.sub = this.sub;
|
||||
jQuerySub.fn.init = function init( selector, context ) {
|
||||
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
|
||||
context = jQuerySub( context );
|
||||
}
|
||||
|
||||
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
|
||||
};
|
||||
jQuerySub.fn.init.prototype = jQuerySub.fn;
|
||||
var rootjQuerySub = jQuerySub(document);
|
||||
return jQuerySub;
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var $, Ansi, CLASS_ANSI, CLASS_BLURRED, CLASS_CURSOR, CLASS_HEADER, CLASS_INPUT, CLASS_OLD_PROMPT, CLASS_PREFIX, CLASS_PROMPT, DEFAULT_INDENT_WIDTH, DEFAULT_PROMPT_CONINUE_LABEL, DEFAULT_PROMPT_LABEL, EMPTY_DIV, EMPTY_SELECTOR, EMPTY_SPAN, ESCAPE_CHAR, ESCAPE_SYNTAX, E_KEYPRESS, JQConsole, KEY_BACKSPACE, KEY_DELETE, KEY_DOWN, KEY_END, KEY_ENTER, KEY_HOME, KEY_LEFT, KEY_PAGE_DOWN, KEY_PAGE_UP, KEY_RIGHT, KEY_TAB, KEY_UP, NEWLINE, STATE_INPUT, STATE_OUTPUT, STATE_PROMPT, spanHtml,
|
||||
|
|
@ -142,24 +79,16 @@ Licensed under the MIT license
|
|||
ESCAPE_SYNTAX = /\[(\d*)(?:;(\d*))*m/;
|
||||
|
||||
Ansi = (function() {
|
||||
|
||||
Ansi.prototype.COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'];
|
||||
|
||||
function Ansi() {
|
||||
this.stylize = __bind(this.stylize, this);
|
||||
|
||||
this._closeSpan = __bind(this._closeSpan, this);
|
||||
|
||||
this._openSpan = __bind(this._openSpan, this);
|
||||
|
||||
this.getClasses = __bind(this.getClasses, this);
|
||||
|
||||
this._style = __bind(this._style, this);
|
||||
|
||||
this._color = __bind(this._color, this);
|
||||
|
||||
this._remove = __bind(this._remove, this);
|
||||
|
||||
this._append = __bind(this._append, this);
|
||||
this.klasses = [];
|
||||
}
|
||||
|
|
@ -344,27 +273,16 @@ Licensed under the MIT license
|
|||
};
|
||||
|
||||
JQConsole = (function() {
|
||||
|
||||
function JQConsole(container, header, prompt_label, prompt_continue_label) {
|
||||
this.container = container;
|
||||
function JQConsole(outer_container, header, prompt_label, prompt_continue_label) {
|
||||
this._HideComposition = __bind(this._HideComposition, this);
|
||||
|
||||
this._ShowComposition = __bind(this._ShowComposition, this);
|
||||
|
||||
this._UpdateComposition = __bind(this._UpdateComposition, this);
|
||||
|
||||
this._EndComposition = __bind(this._EndComposition, this);
|
||||
|
||||
this._StartComposition = __bind(this._StartComposition, this);
|
||||
|
||||
this._CheckComposition = __bind(this._CheckComposition, this);
|
||||
|
||||
this._ProcessMatch = __bind(this._ProcessMatch, this);
|
||||
|
||||
this._HandleKey = __bind(this._HandleKey, this);
|
||||
|
||||
this._HandleChar = __bind(this._HandleChar, this);
|
||||
|
||||
this.isMobile = !!navigator.userAgent.match(/iPhone|iPad|iPod|Android/i);
|
||||
this.isIos = !!navigator.userAgent.match(/iPhone|iPad|iPod/i);
|
||||
this.isAndroid = !!navigator.userAgent.match(/Android/i);
|
||||
|
|
@ -382,26 +300,41 @@ Licensed under the MIT license
|
|||
this.history_new = '';
|
||||
this.history_active = false;
|
||||
this.shortcuts = {};
|
||||
this.$console = $('<pre class="jqconsole"/>').appendTo(this.container);
|
||||
this.$container = $('<div/>').appendTo(outer_container);
|
||||
this.$container.css({
|
||||
'top': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0,
|
||||
'position': 'absolute',
|
||||
'overflow': 'auto'
|
||||
});
|
||||
this.$console = $('<pre class="jqconsole"/>').appendTo(this.$container);
|
||||
this.$console.css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
margin: 0,
|
||||
overflow: 'auto'
|
||||
'margin': 0,
|
||||
'position': 'relative',
|
||||
'min-height': '100%',
|
||||
'box-sizing': 'border-box',
|
||||
'-moz-box-sizing': 'border-box',
|
||||
'-webkit-box-sizing': 'border-box'
|
||||
});
|
||||
this.$console_focused = true;
|
||||
this.$input_container = $(EMPTY_DIV).appendTo(this.container);
|
||||
this.$input_container = $(EMPTY_DIV).appendTo(this.$container);
|
||||
this.$input_container.css({
|
||||
position: 'relative',
|
||||
position: 'absolute',
|
||||
width: 1,
|
||||
height: 0,
|
||||
overflow: 'hidden'
|
||||
});
|
||||
this.$input_source = $('<textarea/>');
|
||||
this.$input_source.attr('wrap', 'off').css({
|
||||
this.$input_source = this.isAndroid ? $('<input/>') : $('<textarea/>');
|
||||
this.$input_source.attr({
|
||||
wrap: 'off',
|
||||
autocapitalize: 'off',
|
||||
autocorrect: 'off',
|
||||
spellcheck: 'false',
|
||||
autocomplete: 'off'
|
||||
});
|
||||
this.$input_source.css({
|
||||
position: 'absolute',
|
||||
width: 2
|
||||
});
|
||||
|
|
@ -421,7 +354,7 @@ Licensed under the MIT license
|
|||
this._InitPrompt();
|
||||
this._SetupEvents();
|
||||
this.Write(this.header, CLASS_HEADER);
|
||||
$(this.container).data('jqconsole', this);
|
||||
$(outer_container).data('jqconsole', this);
|
||||
}
|
||||
|
||||
JQConsole.prototype.ResetHistory = function() {
|
||||
|
|
@ -455,7 +388,7 @@ Licensed under the MIT license
|
|||
this.$input_container.detach();
|
||||
this.$console.html('');
|
||||
this.$prompt.appendTo(this.$console);
|
||||
this.$input_container.appendTo(this.container);
|
||||
this.$input_container.appendTo(this.$container);
|
||||
this.Write(this.header, CLASS_HEADER);
|
||||
return void 0;
|
||||
};
|
||||
|
|
@ -469,8 +402,7 @@ Licensed under the MIT license
|
|||
return this.history_index = this.history.length;
|
||||
};
|
||||
|
||||
/*------------------------ Shortcut Methods -----------------------------
|
||||
*/
|
||||
/*------------------------ Shortcut Methods -----------------------------*/
|
||||
|
||||
|
||||
JQConsole.prototype._CheckKeyCode = function(key_code) {
|
||||
|
|
@ -529,8 +461,7 @@ Licensed under the MIT license
|
|||
return void 0;
|
||||
};
|
||||
|
||||
/*---------------------- END Shortcut Methods ---------------------------
|
||||
*/
|
||||
/*---------------------- END Shortcut Methods ---------------------------*/
|
||||
|
||||
|
||||
JQConsole.prototype.GetColumn = function() {
|
||||
|
|
@ -777,8 +708,7 @@ Licensed under the MIT license
|
|||
return void 0;
|
||||
};
|
||||
|
||||
/*------------------------ Private Methods -------------------------------
|
||||
*/
|
||||
/*------------------------ Private Methods -------------------------------*/
|
||||
|
||||
|
||||
JQConsole.prototype._CheckInputQueue = function() {
|
||||
|
|
@ -811,8 +741,7 @@ Licensed under the MIT license
|
|||
};
|
||||
|
||||
JQConsole.prototype._SetupEvents = function() {
|
||||
var cb, paste_event,
|
||||
_this = this;
|
||||
var _this = this;
|
||||
if (this.isMobile) {
|
||||
this.$console.click(function(e) {
|
||||
e.preventDefault();
|
||||
|
|
@ -865,8 +794,7 @@ Licensed under the MIT license
|
|||
};
|
||||
return setTimeout(addClass, 100);
|
||||
});
|
||||
paste_event = $.browser.opera ? 'input' : 'paste';
|
||||
this.$input_source.bind(paste_event, function() {
|
||||
this.$input_source.bind('paste', function() {
|
||||
var handlePaste;
|
||||
handlePaste = function() {
|
||||
if (_this.in_composition) {
|
||||
|
|
@ -881,21 +809,17 @@ Licensed under the MIT license
|
|||
this.$input_source.keypress(this._HandleChar);
|
||||
this.$input_source.keydown(this._HandleKey);
|
||||
this.$input_source.keydown(this._CheckComposition);
|
||||
if ($.browser.mozilla != null) {
|
||||
this.$input_source.bind('compositionstart', this._StartComposition);
|
||||
this.$input_source.bind('compositionend', this._EndCommposition);
|
||||
this.$input_source.bind('text', this._UpdateComposition);
|
||||
}
|
||||
if ($.browser.opera != null) {
|
||||
cb = function() {
|
||||
if (_this.in_composition) {
|
||||
return;
|
||||
}
|
||||
if (_this.$input_source.val().length) {
|
||||
return _this._StartComposition();
|
||||
}
|
||||
};
|
||||
return setInterval(cb, 200);
|
||||
this.$input_source.bind('compositionstart', this._StartComposition);
|
||||
this.$input_source.bind('compositionend', function(e) {
|
||||
return setTimeout((function() {
|
||||
return _this._EndComposition(e);
|
||||
}), 0);
|
||||
});
|
||||
if (this.isAndroid) {
|
||||
this.$input_source.bind('input', this._StartComposition);
|
||||
return this.$input_source.bind('input', this._UpdateComposition);
|
||||
} else {
|
||||
return this.$input_source.bind('text', this._UpdateComposition);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -908,16 +832,6 @@ Licensed under the MIT license
|
|||
if (char_code === 8 || char_code === 9 || char_code === 13) {
|
||||
return false;
|
||||
}
|
||||
if ($.browser.mozilla) {
|
||||
if (event.keyCode || event.altKey) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ($.browser.opera) {
|
||||
if (event.altKey) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
this.$prompt_left.text(this.$prompt_left.text() + String.fromCharCode(char_code));
|
||||
this._ScrollToEnd();
|
||||
return false;
|
||||
|
|
@ -949,10 +863,10 @@ Licensed under the MIT license
|
|||
this._MoveDown();
|
||||
break;
|
||||
case KEY_PAGE_UP:
|
||||
this._ScrollUp();
|
||||
this._ScrollPage('up');
|
||||
break;
|
||||
case KEY_PAGE_DOWN:
|
||||
this._ScrollDown();
|
||||
this._ScrollPage('down');
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
|
|
@ -991,10 +905,10 @@ Licensed under the MIT license
|
|||
this.MoveToEnd(false);
|
||||
break;
|
||||
case KEY_PAGE_UP:
|
||||
this._ScrollUp();
|
||||
this._ScrollPage('up');
|
||||
break;
|
||||
case KEY_PAGE_DOWN:
|
||||
this._ScrollDown();
|
||||
this._ScrollPage('down');
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
|
|
@ -1048,6 +962,7 @@ Licensed under the MIT license
|
|||
JQConsole.prototype._HandleEnter = function(shift) {
|
||||
var continuation, text,
|
||||
_this = this;
|
||||
this._EndComposition();
|
||||
if (shift) {
|
||||
return this._InsertNewLine(true);
|
||||
} else {
|
||||
|
|
@ -1301,52 +1216,49 @@ Licensed under the MIT license
|
|||
return _results;
|
||||
};
|
||||
|
||||
JQConsole.prototype._ScrollUp = function() {
|
||||
JQConsole.prototype._ScrollPage = function(dir) {
|
||||
var target;
|
||||
target = this.$console[0].scrollTop - this.$console.height();
|
||||
return this.$console.stop().animate({
|
||||
scrollTop: target
|
||||
}, 'fast');
|
||||
};
|
||||
|
||||
JQConsole.prototype._ScrollDown = function() {
|
||||
var target;
|
||||
target = this.$console[0].scrollTop + this.$console.height();
|
||||
return this.$console.stop().animate({
|
||||
target = this.$container[0].scrollTop;
|
||||
if (dir === 'up') {
|
||||
target -= this.$container.height();
|
||||
} else {
|
||||
target += this.$container.height();
|
||||
}
|
||||
return this.$container.stop().animate({
|
||||
scrollTop: target
|
||||
}, 'fast');
|
||||
};
|
||||
|
||||
JQConsole.prototype._ScrollToEnd = function() {
|
||||
var cont,
|
||||
_this = this;
|
||||
this.$console.scrollTop(this.$console[0].scrollHeight);
|
||||
cont = function() {
|
||||
var doc_height, line_height, optimal_pos, pos, rel_pos, screen_left, screen_top;
|
||||
line_height = _this.$prompt_cursor.height();
|
||||
screen_top = _this.$window.scrollTop();
|
||||
screen_left = _this.$window.scrollLeft();
|
||||
doc_height = document.documentElement.clientHeight;
|
||||
pos = _this.$prompt_cursor.offset();
|
||||
rel_pos = _this.$prompt_cursor.position();
|
||||
_this.$input_container.css({
|
||||
left: rel_pos.left,
|
||||
top: rel_pos.top
|
||||
});
|
||||
optimal_pos = pos.top - (2 * line_height);
|
||||
if (_this.isMobile && (typeof orientation !== "undefined" && orientation !== null)) {
|
||||
if (screen_top < pos.top || screen_top > pos.top) {
|
||||
return _this.$window.scrollTop(optimal_pos);
|
||||
}
|
||||
} else {
|
||||
if (screen_top + doc_height < pos.top) {
|
||||
return _this.$window.scrollTop(pos.top - doc_height + line_height);
|
||||
} else if (screen_top > optimal_pos) {
|
||||
return _this.$window.scrollTop(pos.top);
|
||||
}
|
||||
var pos;
|
||||
this.$container.scrollTop(this.$container[0].scrollHeight);
|
||||
pos = this.$prompt_cursor.position();
|
||||
this.$input_container.css({
|
||||
left: pos.left,
|
||||
top: pos.top
|
||||
});
|
||||
return setTimeout(this.ScrollWindowToPrompt.bind(this), 50);
|
||||
};
|
||||
|
||||
JQConsole.prototype.ScrollWindowToPrompt = function() {
|
||||
var doc_height, line_height, optimal_pos, pos, screen_left, screen_top;
|
||||
line_height = this.$prompt_cursor.height();
|
||||
screen_top = this.$window.scrollTop();
|
||||
screen_left = this.$window.scrollLeft();
|
||||
doc_height = document.documentElement.clientHeight;
|
||||
pos = this.$prompt_cursor.offset();
|
||||
optimal_pos = pos.top - (2 * line_height);
|
||||
if (this.isMobile && (typeof orientation !== "undefined" && orientation !== null)) {
|
||||
if (screen_top < pos.top || screen_top > pos.top) {
|
||||
return this.$window.scrollTop(optimal_pos);
|
||||
}
|
||||
};
|
||||
return setTimeout(cont, 0);
|
||||
} else {
|
||||
if (screen_top + doc_height < pos.top) {
|
||||
return this.$window.scrollTop(pos.top - doc_height + line_height);
|
||||
} else if (screen_top > optimal_pos) {
|
||||
return this.$window.scrollTop(pos.top);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JQConsole.prototype._SelectPromptLabel = function(continuation) {
|
||||
|
|
@ -1511,9 +1423,6 @@ Licensed under the MIT license
|
|||
JQConsole.prototype._CheckComposition = function(e) {
|
||||
var key;
|
||||
key = e.keyCode || e.which;
|
||||
if (($.browser.opera != null) && this.in_composition) {
|
||||
this._UpdateComposition();
|
||||
}
|
||||
if (key === 229) {
|
||||
if (this.in_composition) {
|
||||
return this._UpdateComposition();
|
||||
|
|
@ -1524,17 +1433,23 @@ Licensed under the MIT license
|
|||
};
|
||||
|
||||
JQConsole.prototype._StartComposition = function() {
|
||||
this.$input_source.bind(E_KEYPRESS, this._EndComposition);
|
||||
if (this.in_composition) {
|
||||
return;
|
||||
}
|
||||
this.in_composition = true;
|
||||
this._ShowComposition();
|
||||
return setTimeout(this._UpdateComposition, 0);
|
||||
};
|
||||
|
||||
JQConsole.prototype._EndComposition = function() {
|
||||
this.$input_source.unbind(E_KEYPRESS, this._EndComposition);
|
||||
this.in_composition = false;
|
||||
if (!this.in_composition) {
|
||||
return;
|
||||
}
|
||||
this._HideComposition();
|
||||
return this.$input_source.val('');
|
||||
this.$prompt_left.text(this.$prompt_left.text() + this.$composition.text());
|
||||
this.$composition.text('');
|
||||
this.$input_source.val('');
|
||||
return this.in_composition = false;
|
||||
};
|
||||
|
||||
JQConsole.prototype._UpdateComposition = function(e) {
|
||||
40
lib/client/console/package.json
Normal file
40
lib/client/console/package.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "jq-console",
|
||||
"version": "2.8.0",
|
||||
"description": "Feature complete web terminal",
|
||||
"main": "jqconsole.min.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/karma/bin/karma start --single-run"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/replit/jq-console.git"
|
||||
},
|
||||
"keywords": [
|
||||
"jq-consoel",
|
||||
"console",
|
||||
"terminal"
|
||||
],
|
||||
"author": "amasad",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/replit/jq-console/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"karma-coffee-preprocessor": "~0.1.2",
|
||||
"mocha": "~1.17.1",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"karma-chrome-launcher": "~0.1.2",
|
||||
"karma-firefox-launcher": "~0.1.3",
|
||||
"karma-html2js-preprocessor": "~0.1.0",
|
||||
"karma-jasmine": "~0.1.5",
|
||||
"requirejs": "~2.1.10",
|
||||
"karma-requirejs": "~0.2.1",
|
||||
"karma-phantomjs-launcher": "~0.1.1",
|
||||
"karma": "~0.10.9",
|
||||
"karma-mocha": "~0.1.1"
|
||||
}
|
||||
}
|
||||
50
lib/client/console/test/ansi-test.coffee
Normal file
50
lib/client/console/test/ansi-test.coffee
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
Ansi = $().jqconsole.Ansi
|
||||
|
||||
CssPre = 'jqconsole-ansi-'
|
||||
|
||||
describe 'Ansi', ->
|
||||
describe '#_style', ->
|
||||
ansi = null
|
||||
beforeEach -> ansi = new Ansi()
|
||||
|
||||
it 'applies and replaces font', ->
|
||||
ansi._style '11'
|
||||
assert.deepEqual ["#{CssPre}fonts-1"], ansi.klasses
|
||||
ansi._style '19'
|
||||
assert.deepEqual ["#{CssPre}fonts-9"], ansi.klasses
|
||||
|
||||
it 'applies and replaces color', ->
|
||||
ansi._style '31'
|
||||
assert.deepEqual ["#{CssPre}color-#{ansi._color(1)}"], ansi.klasses
|
||||
ansi._style '37'
|
||||
assert.deepEqual ["#{CssPre}color-#{ansi._color(7)}"], ansi.klasses
|
||||
ansi._style '39'
|
||||
assert.deepEqual [], ansi.klasses
|
||||
|
||||
it 'applies and replaces background-color', ->
|
||||
ansi._style '41'
|
||||
assert.deepEqual ["#{CssPre}background-color-#{ansi._color(1)}"], ansi.klasses
|
||||
ansi._style '47'
|
||||
assert.deepEqual ["#{CssPre}background-color-#{ansi._color(7)}"], ansi.klasses
|
||||
ansi._style '49'
|
||||
assert.deepEqual [], ansi.klasses
|
||||
|
||||
describe '#stylize', ->
|
||||
ansi = null
|
||||
beforeEach -> ansi = new Ansi()
|
||||
|
||||
it 'appends a styles', ->
|
||||
html = ansi.stylize 'test\x1B[1mhello'
|
||||
assert.equal html, "<span class=\"\">test</span><span class=\"#{CssPre}bold\">hello</span>"
|
||||
|
||||
it 'appends multiple styles', ->
|
||||
html = ansi.stylize 'test\x1B[1;2mhello'
|
||||
assert.equal html, "<span class=\"\">test</span><span class=\"#{CssPre}bold #{CssPre}lighter\">hello</span>"
|
||||
|
||||
it 'appends multiple styles at different intervals', ->
|
||||
html = ansi.stylize 'test\x1B[1mhello\x1B[2mhi'
|
||||
assert.equal html, "<span class=\"\">test</span><span class=\"#{CssPre}bold\">hello</span><span class=\"#{CssPre}bold #{CssPre}lighter\">hi</span>"
|
||||
html = ansi.stylize 'a\x1B[53mb\x1B[21mc\x1B[md'
|
||||
assert.equal html, "<span class=\"#{CssPre}bold #{CssPre}lighter\">a</span><span class=\"#{CssPre}bold #{CssPre}lighter #{CssPre}overline\">b</span><span class=\"#{CssPre}overline\">c</span><span class=\"\">d</span>"
|
||||
|
||||
|
||||
49
lib/client/console/test/history-test.coffee
Normal file
49
lib/client/console/test/history-test.coffee
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{jqconsole, typer: {typeA, keyDown, type}} = jqconsoleSetup()
|
||||
|
||||
describe 'History', ->
|
||||
describe '#GetHistory', ->
|
||||
it 'gets the history', ->
|
||||
jqconsole.Prompt true, ->
|
||||
typeA()
|
||||
keyDown 13
|
||||
deepEqual ['a'], jqconsole.GetHistory()
|
||||
|
||||
describe '#SetHistory', ->
|
||||
it 'sets history', ->
|
||||
h = ['a', 'b']
|
||||
jqconsole.SetHistory h
|
||||
deepEqual h, jqconsole.GetHistory()
|
||||
|
||||
describe '#ResetHistory', ->
|
||||
it 'resets the history', ->
|
||||
jqconsole.ResetHistory()
|
||||
deepEqual jqconsole.history, []
|
||||
|
||||
describe 'History interaction in the prompt', ->
|
||||
it 'gets the prev history item', ->
|
||||
jqconsole.Prompt true, ->
|
||||
type 'foo'
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
keyDown 13
|
||||
jqconsole.Prompt true, ->
|
||||
equal jqconsole.GetPromptText(), ''
|
||||
keyDown 38
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
jqconsole.AbortPrompt()
|
||||
|
||||
it 'gets the next history item', ->
|
||||
jqconsole.Prompt true, ->
|
||||
type 'foo'
|
||||
keyDown 13
|
||||
jqconsole.Prompt true, ->
|
||||
type 'bar'
|
||||
keyDown 13
|
||||
jqconsole.Prompt true, ->
|
||||
keyDown 38
|
||||
equal jqconsole.GetPromptText(), 'bar'
|
||||
keyDown 38
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
keyDown 40
|
||||
equal jqconsole.GetPromptText(), 'bar'
|
||||
keyDown 40
|
||||
equal jqconsole.GetPromptText(), ''
|
||||
37
lib/client/console/test/index.html
Normal file
37
lib/client/console/test/index.html
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mocha</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="vendor/mocha.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="vendor/mocha.js"></script>
|
||||
<script>mocha.setup('bdd')</script>
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="../lib/jqconsole.js"></script>
|
||||
<script src="vendor/assert.js"></script>
|
||||
<script src="vendor/coffeescript.js"></script>
|
||||
|
||||
<script>
|
||||
var tests = [ 'setup.coffee'
|
||||
, 'ansi-test.coffee'
|
||||
, 'jqconsole-test.coffee'
|
||||
, 'prompt-test.coffee'
|
||||
, 'shortcuts-test.coffee'
|
||||
, 'history-test.coffee'
|
||||
]
|
||||
tests.forEach(function (test) {
|
||||
CoffeeScript.load(test, start)
|
||||
})
|
||||
function start () {
|
||||
if (start.called == null) start.called = 0;
|
||||
if (++start.called == tests.length) {
|
||||
mocha.run();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
29
lib/client/console/test/jqconsole-test.coffee
Normal file
29
lib/client/console/test/jqconsole-test.coffee
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
describe 'JQConsole', ->
|
||||
{$container, jqconsole} = jqconsoleSetup()
|
||||
describe '#constructor', ->
|
||||
|
||||
it 'instantiates', ->
|
||||
equal jqconsole.header, 'header'
|
||||
equal jqconsole.prompt_label_main, 'prompt_label'
|
||||
equal jqconsole.prompt_label_continue, 'prompt_continue'
|
||||
equal jqconsole.indent_width, 2
|
||||
equal jqconsole.GetState(), 'output'
|
||||
deepEqual jqconsole.input_queue, []
|
||||
deepEqual jqconsole.history, []
|
||||
ok jqconsole.$console.length
|
||||
ok jqconsole.$console instanceof jQuery
|
||||
equal $container.text().trim(), 'header'
|
||||
strictEqual $container.data('jqconsole'), jqconsole
|
||||
ok jqconsole.$prompt.length
|
||||
ok jqconsole.$input_source.length
|
||||
|
||||
it 'setup events', (done)->
|
||||
counter = 0
|
||||
jqconsole.$input_source.focus ->
|
||||
counter++
|
||||
jqconsole.$console.mouseup()
|
||||
fn = ->
|
||||
ok counter
|
||||
done()
|
||||
setTimeout fn, 10
|
||||
394
lib/client/console/test/prompt-test.coffee
Normal file
394
lib/client/console/test/prompt-test.coffee
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
{jqconsole, createScroll, typer: {typeA, keyDown, type}} = jqconsoleSetup()
|
||||
|
||||
describe 'Prompt Interaction', ->
|
||||
describe '#Prompt', ->
|
||||
after ->
|
||||
jqconsole.AbortPrompt()
|
||||
|
||||
it 'inits prompt and auto-focuses', ->
|
||||
counter = 0
|
||||
jqconsole.$input_source.focus ->
|
||||
counter++
|
||||
resultCb = ->
|
||||
jqconsole.Prompt true, resultCb
|
||||
equal jqconsole.GetState(), 'prompt'
|
||||
ok counter
|
||||
ok jqconsole.history_active
|
||||
strictEqual jqconsole.input_callback, resultCb
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label'
|
||||
|
||||
describe '#AbortPrompt', ->
|
||||
it 'aborts the prompt', ->
|
||||
jqconsole.Prompt true, ->
|
||||
jqconsole.AbortPrompt()
|
||||
equal jqconsole.$prompt.text().trim(), ''
|
||||
|
||||
it 'restarts queued prompts', ->
|
||||
aCb = ->
|
||||
jqconsole.Prompt false, aCb
|
||||
bCb = ->
|
||||
jqconsole.Prompt true, bCb
|
||||
strictEqual jqconsole.input_callback, aCb
|
||||
strictEqual jqconsole.history_active, false
|
||||
jqconsole.AbortPrompt()
|
||||
strictEqual jqconsole.input_callback, bCb
|
||||
strictEqual jqconsole.history_active, true
|
||||
jqconsole.AbortPrompt()
|
||||
|
||||
describe '#GetPromptText', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'gets the current prompt text', ->
|
||||
type 'foo'
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_labelfoo'
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
|
||||
it 'gets the current prompt text with the label', ->
|
||||
type 'foo'
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_labelfoo'
|
||||
equal jqconsole.GetPromptText(true), 'prompt_labelfoo'
|
||||
|
||||
describe '#ClearPromptText', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'Clears the current prompt text', ->
|
||||
type 'foo'
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
jqconsole.ClearPromptText()
|
||||
equal jqconsole.GetPromptText(), ''
|
||||
|
||||
it 'Clears prompt text with label', ->
|
||||
type 'foo'
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
jqconsole.ClearPromptText true
|
||||
equal jqconsole.GetPromptText(true), ''
|
||||
|
||||
describe '#SetPromptText', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'sets the current prompt text', ->
|
||||
type 'bar'
|
||||
jqconsole.SetPromptText('foo')
|
||||
equal jqconsole.GetPromptText(), 'foo'
|
||||
|
||||
describe 'Moving', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'moves to the left', ->
|
||||
type 'xyz'
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xy'
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), 'x'
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), ''
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), ''
|
||||
|
||||
it 'moves to the right', ->
|
||||
type 'xyz'
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), 'x'
|
||||
keyDown 39
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xy'
|
||||
keyDown 39
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
keyDown 39
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
|
||||
it 'moves to the prev line when at the first char of the line moving left', ->
|
||||
type 'xyz'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'abc'
|
||||
equal jqconsole.$prompt_left.text().trim(), 'abc'
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
|
||||
it 'moves to the next line when at the last char of the line moving right', ->
|
||||
type 'xyz'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'abc'
|
||||
equal jqconsole.$prompt_left.text().trim(), 'abc'
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
keyDown 39
|
||||
equal jqconsole.$prompt_right.text().trim(), 'abc'
|
||||
|
||||
it 'moves to the start of the word', ->
|
||||
type 'xyz abc'
|
||||
keyDown 37, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'abc'
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
|
||||
it 'moves to the end of the word', ->
|
||||
type 'xyz abc'
|
||||
keyDown 37, metaKey: on
|
||||
keyDown 37, metaKey: on
|
||||
keyDown 39, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'abc'
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
|
||||
it 'moves to the end of the word', ->
|
||||
type 'xyz abc'
|
||||
keyDown 37, metaKey: on
|
||||
keyDown 37, metaKey: on
|
||||
keyDown 39, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'abc'
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz'
|
||||
|
||||
it 'moves to the start of the line', ->
|
||||
type 'xyz abc'
|
||||
keyDown 36
|
||||
equal jqconsole.$prompt_right.text().trim(), 'xyz abc'
|
||||
|
||||
it 'moves to the end of the line', ->
|
||||
type 'xyz abc'
|
||||
keyDown 36
|
||||
equal jqconsole.$prompt_right.text().trim(), 'xyz abc'
|
||||
keyDown 35
|
||||
equal jqconsole.$prompt_right.text().trim(), ''
|
||||
equal jqconsole.$prompt_left.text().trim(), 'xyz abc'
|
||||
|
||||
it 'moves to the start of the prompt', ->
|
||||
type 'xyz abc'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'hafm olim'
|
||||
keyDown 36, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'xyz abc'
|
||||
equal jqconsole.$prompt_after.text().trim(), 'prompt_continuehafm olim'
|
||||
|
||||
it 'moves to the end of the prompt', ->
|
||||
type 'xyz abc'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'hafm olim'
|
||||
keyDown 36, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'xyz abc'
|
||||
equal jqconsole.$prompt_after.text().trim(), 'prompt_continuehafm olim'
|
||||
keyDown 35, metaKey: on
|
||||
equal jqconsole.$prompt_left.text().trim(), 'hafm olim'
|
||||
equal jqconsole.$prompt_before.text().trim(), 'prompt_labelxyz abc'
|
||||
|
||||
it 'moves up one line', ->
|
||||
type 'xyz'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'a'
|
||||
keyDown 38, shiftKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'yz'
|
||||
|
||||
it 'moves down one line', ->
|
||||
type 'xyz'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'a'
|
||||
# Meta key also works.
|
||||
keyDown 38, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'yz'
|
||||
keyDown 40, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), ''
|
||||
|
||||
it 'respects the column when moving vertically', ->
|
||||
type 'xyz'
|
||||
keyDown 13, shiftKey: on
|
||||
type 'ab'
|
||||
keyDown 38, shiftKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'z'
|
||||
keyDown 40, shiftKey: on
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_right.text().trim(), 'ab'
|
||||
keyDown 38, shiftKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), 'xyz'
|
||||
|
||||
describe 'Control Keys', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'handles enter', ->
|
||||
jqconsole.AbortPrompt()
|
||||
counter = 0
|
||||
jqconsole.Prompt true, -> counter++
|
||||
typeA()
|
||||
keyDown 13
|
||||
ok counter
|
||||
equal jqconsole.$console.find('.jqconsole-old-prompt').last().text().trim(), 'prompt_labela'
|
||||
# Restart the prompt for other tests.
|
||||
jqconsole.Prompt true, ->
|
||||
|
||||
it 'handles shift+enter', ->
|
||||
keyDown 13, shiftKey: on
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label \nprompt_continue'
|
||||
|
||||
it 'handles tab', ->
|
||||
typeA()
|
||||
keyDown 9
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label a'
|
||||
|
||||
it 'handles shift+tab', ->
|
||||
typeA()
|
||||
keyDown 9, shiftKey: on
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_labela'
|
||||
|
||||
it 'backspace', ->
|
||||
typeA()
|
||||
keyDown 8
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label'
|
||||
|
||||
it 'cntrl+backspace', ->
|
||||
typeA()
|
||||
typeA()
|
||||
keyDown 8, metaKey: on
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label'
|
||||
|
||||
it 'deletes a char', ->
|
||||
type 'xyz'
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_right.text().trim(), 'z'
|
||||
keyDown 46
|
||||
equal jqconsole.$prompt_right.text().trim(), ''
|
||||
|
||||
it 'deletes a word', ->
|
||||
type 'xyz abc'
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
keyDown 37
|
||||
equal jqconsole.$prompt_right.text().trim(), 'abc'
|
||||
keyDown 46, metaKey: on
|
||||
equal jqconsole.$prompt_right.text().trim(), ''
|
||||
|
||||
describe 'scrolling', ->
|
||||
console_height = null
|
||||
_fast = null
|
||||
|
||||
before ->
|
||||
jQuery.fx.speeds.fast = 10
|
||||
after ->
|
||||
jQuery.fx.speeds.fast = _fast
|
||||
|
||||
beforeEach ->
|
||||
jqconsole.Reset()
|
||||
jqconsole.Prompt true, ->
|
||||
# Make sure the console has a scroll.
|
||||
{ console_height } = createScroll()
|
||||
|
||||
it 'scrolls up', (done) ->
|
||||
before = jqconsole.$container[0].scrollTop
|
||||
keyDown 33
|
||||
cb = ->
|
||||
equal jqconsole.$container[0].scrollTop, before - console_height
|
||||
done()
|
||||
# * 2 is some arbitrary number otherwise it fails.
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
|
||||
it 'scrolls up twice', (done) ->
|
||||
before = jqconsole.$container[0].scrollTop
|
||||
keyDown 33
|
||||
cb = ->
|
||||
keyDown 33
|
||||
cb = ->
|
||||
equal jqconsole.$container[0].scrollTop, before - (console_height * 2)
|
||||
done()
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
# * 2 is some arbitrary number otherwise it fails.
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
|
||||
it 'scrolls down', (done) ->
|
||||
before = jqconsole.$container[0].scrollTop
|
||||
keyDown 33
|
||||
cb = ->
|
||||
keyDown 34
|
||||
cb = ->
|
||||
equal jqconsole.$container[0].scrollTop, before
|
||||
done()
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
# * 2 is some arbitrary number otherwise it fails.
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
|
||||
describe 'Typing', ->
|
||||
beforeEach -> jqconsole.Prompt true, ->
|
||||
afterEach -> jqconsole.AbortPrompt()
|
||||
|
||||
it 'handles chars', ->
|
||||
str = ''
|
||||
test = (ch) ->
|
||||
str += ch
|
||||
e = $.Event('keypress')
|
||||
e.which = ch.charCodeAt(0)
|
||||
jqconsole.$input_source.trigger e
|
||||
equal jqconsole.$prompt.text().trim(), 'prompt_label' + str
|
||||
|
||||
test 'a'
|
||||
test 'Z'
|
||||
test '$'
|
||||
test 'ƒ'
|
||||
|
||||
it 'scrolls all the way down when typing', (done) ->
|
||||
createScroll()
|
||||
keyDown 33
|
||||
cb = ->
|
||||
before = jqconsole.$container[0].scrollTop
|
||||
type('a')
|
||||
cb = ->
|
||||
notEqual jqconsole.$container[0].scrollTop, before
|
||||
done()
|
||||
setTimeout cb, 0
|
||||
setTimeout cb, jQuery.fx.speeds.fast * 2
|
||||
|
||||
describe 'Multiline', ->
|
||||
beforeEach ->
|
||||
if jqconsole.GetState() is 'prompt'
|
||||
jqconsole.AbortPrompt()
|
||||
|
||||
it 'executes multiline callback', (done) ->
|
||||
jqconsole.Prompt true, (-> ), ->
|
||||
done()
|
||||
type('foo')
|
||||
keyDown 13
|
||||
|
||||
it 'indents', ->
|
||||
jqconsole.Prompt true, (-> ), ->
|
||||
return 2
|
||||
type('foo')
|
||||
keyDown 13
|
||||
equal jqconsole.GetState(), 'prompt'
|
||||
equal jqconsole.GetPromptText(), 'foo\n '
|
||||
|
||||
it 'keeps indentation on shift+enter', ->
|
||||
jqconsole.Prompt true, (-> ), ->
|
||||
return 2
|
||||
type('foo')
|
||||
keyDown 9
|
||||
keyDown 13, shiftKey: on
|
||||
equal jqconsole.GetState(), 'prompt'
|
||||
equal jqconsole.GetPromptText(), ' foo\n '
|
||||
|
||||
it 'unindents', ->
|
||||
jqconsole.Prompt true, (-> ), ->
|
||||
return -2
|
||||
type('foo')
|
||||
keyDown 9
|
||||
keyDown 13
|
||||
equal jqconsole.GetPromptText(), ' foo\n'
|
||||
|
||||
it 'skip indent callback', (done) ->
|
||||
jqconsole.Prompt true, done.bind(null, null), ->
|
||||
return false
|
||||
type('foo')
|
||||
keyDown 13
|
||||
|
||||
it 'handles async treatment', (done) ->
|
||||
jqconsole.Prompt true, done.bind(null, null), ((text, cb) -> cb false), on
|
||||
type('foo')
|
||||
keyDown 13
|
||||
|
||||
|
||||
|
||||
44
lib/client/console/test/setup.coffee
Normal file
44
lib/client/console/test/setup.coffee
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
window.equal = assert.equal
|
||||
window.notEqual = assert.notEqual
|
||||
window.deepEqual = assert.deepEqual
|
||||
window.strictEqual = assert.strictEqual
|
||||
window.ok = assert.ok
|
||||
JQConsole = $().jqconsole.JQConsole
|
||||
|
||||
window.jqconsoleSetup = ->
|
||||
$container = $('<div/>').css
|
||||
height: '100px'
|
||||
widht: '200px'
|
||||
position: 'relative'
|
||||
$container.appendTo('body')
|
||||
jqconsole = new JQConsole($container, 'header', 'prompt_label', 'prompt_continue')
|
||||
typer =
|
||||
typeA: ->
|
||||
e = $.Event('keypress')
|
||||
e.which = 'a'.charCodeAt(0)
|
||||
jqconsole.$input_source.trigger e
|
||||
|
||||
keyDown: (code, options = {}) ->
|
||||
e = $.Event('keydown')
|
||||
e.which = code
|
||||
e[k] = v for k, v of options
|
||||
jqconsole.$input_source.trigger e
|
||||
|
||||
type: (str) ->
|
||||
type = (chr) ->
|
||||
e = $.Event('keypress')
|
||||
e.which = chr.charCodeAt(0)
|
||||
jqconsole.$input_source.trigger(e)
|
||||
type chr for chr in str
|
||||
|
||||
createScroll = ->
|
||||
line_height = jqconsole.$prompt.height()
|
||||
console_height = jqconsole.$container.height()
|
||||
lines_per_page = Math.ceil(console_height / line_height)
|
||||
for i in [0..lines_per_page * 5]
|
||||
jqconsole.SetPromptText('foo')
|
||||
jqconsole._HandleEnter()
|
||||
jqconsole.Prompt true, ->
|
||||
{line_height, console_height, lines_per_page}
|
||||
|
||||
{$container, jqconsole, typer, createScroll}
|
||||
60
lib/client/console/test/shortcuts-test.coffee
Normal file
60
lib/client/console/test/shortcuts-test.coffee
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
{jqconsole, typer: {keyDown}} = jqconsoleSetup()
|
||||
|
||||
describe 'Shortcuts', ->
|
||||
describe '#RegisterShortcut', ->
|
||||
# Fails in v2.7.7
|
||||
it 'throws if callback not function', ->
|
||||
assert.throws ->
|
||||
jqconsole.RegisterShortcut 'b', 'c'
|
||||
|
||||
it 'registers shortcut by string', ->
|
||||
cb = ->
|
||||
jqconsole.RegisterShortcut 'a', cb
|
||||
deepEqual jqconsole.shortcuts['a'.charCodeAt(0)], [cb]
|
||||
deepEqual jqconsole.shortcuts['A'.charCodeAt(0)], [cb]
|
||||
|
||||
it 'registers shortcut by charcode', ->
|
||||
cb = ->
|
||||
jqconsole.RegisterShortcut 'c'.charCodeAt(0), cb
|
||||
deepEqual jqconsole.shortcuts['c'.charCodeAt(0)], [cb]
|
||||
deepEqual jqconsole.shortcuts['C'.charCodeAt(0)], [cb]
|
||||
|
||||
it 'shortcuts must be ascii', ->
|
||||
assert.throws ->
|
||||
jqconsole.RegisterShortcut 'ƒ', ->
|
||||
|
||||
describe '#UnRegisterShortcut', ->
|
||||
|
||||
it 'removes all callback for a shortcut', ->
|
||||
cb = ->
|
||||
jqconsole.RegisterShortcut 'a', cb
|
||||
jqconsole.UnRegisterShortcut 'a'
|
||||
deepEqual jqconsole.shortcuts['a'.charCodeAt(0)], undefined
|
||||
|
||||
it 'removes specific callback', ->
|
||||
aCb = ->
|
||||
bCb = ->
|
||||
jqconsole.RegisterShortcut 'a', aCb
|
||||
jqconsole.RegisterShortcut 'a', bCb
|
||||
jqconsole.UnRegisterShortcut 'a', aCb
|
||||
deepEqual jqconsole.shortcuts['a'.charCodeAt(0)], [bCb]
|
||||
|
||||
describe '#ResetShortcuts', ->
|
||||
|
||||
it 'resets all shortcuts', ->
|
||||
cb1 = ->
|
||||
cb2 = ->
|
||||
jqconsole.RegisterShortcut 'a', cb1
|
||||
jqconsole.RegisterShortcut 'b', cb2
|
||||
jqconsole.ResetShortcuts()
|
||||
deepEqual jqconsole.shortcuts, {}
|
||||
|
||||
describe 'Invoking Shortcuts', ->
|
||||
it 'invokes shortcuts', ->
|
||||
jqconsole.Prompt true, ->
|
||||
counter = 0
|
||||
jqconsole.RegisterShortcut 'a', ->
|
||||
strictEqual this, jqconsole
|
||||
counter++
|
||||
keyDown 'a'.charCodeAt(0), metaKey: on
|
||||
ok counter
|
||||
369
lib/client/console/test/vendor/assert.js
vendored
Normal file
369
lib/client/console/test/vendor/assert.js
vendored
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
// http://wiki.commonjs.org/wiki/Unit_Testing/1.0
|
||||
//
|
||||
// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
|
||||
//
|
||||
// Copyright (c) 2011 Jxck
|
||||
//
|
||||
// Originally from node.js (http://nodejs.org)
|
||||
// Copyright Joyent, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the 'Software'), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(function(global) {
|
||||
|
||||
// Object.create compatible in IE
|
||||
var create = Object.create || function(p) {
|
||||
if (!p) throw Error('no type');
|
||||
function f() {};
|
||||
f.prototype = p;
|
||||
return new f();
|
||||
};
|
||||
|
||||
// UTILITY
|
||||
var util = {
|
||||
inherits: function(ctor, superCtor) {
|
||||
ctor.super_ = superCtor;
|
||||
ctor.prototype = create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var pSlice = Array.prototype.slice;
|
||||
|
||||
// 1. The assert module provides functions that throw
|
||||
// AssertionError's when particular conditions are not met. The
|
||||
// assert module must conform to the following interface.
|
||||
|
||||
var assert = ok;
|
||||
|
||||
global['assert'] = assert;
|
||||
|
||||
if (typeof module === 'object' && typeof module.exports === 'object') {
|
||||
module.exports = assert;
|
||||
};
|
||||
|
||||
// 2. The AssertionError is defined in assert.
|
||||
// new assert.AssertionError({ message: message,
|
||||
// actual: actual,
|
||||
// expected: expected })
|
||||
|
||||
assert.AssertionError = function AssertionError(options) {
|
||||
this.name = 'AssertionError';
|
||||
this.message = options.message || (options.actual + ' ' + options.operator + ' ' +options.expected)
|
||||
this.actual = options.actual;
|
||||
this.expected = options.expected;
|
||||
this.operator = options.operator;
|
||||
var stackStartFunction = options.stackStartFunction || fail;
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, stackStartFunction);
|
||||
}
|
||||
};
|
||||
util.inherits(assert.AssertionError, Error);
|
||||
|
||||
function replacer(key, value) {
|
||||
if (value === undefined) {
|
||||
return '' + value;
|
||||
}
|
||||
if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) {
|
||||
return value.toString();
|
||||
}
|
||||
if (typeof value === 'function' || value instanceof RegExp) {
|
||||
return value.toString();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function truncate(s, n) {
|
||||
if (typeof s == 'string') {
|
||||
return s.length < n ? s : s.slice(0, n);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
assert.AssertionError.prototype.toString = function() {
|
||||
if (this.message) {
|
||||
return [this.name + ':', this.message].join(' ');
|
||||
} else {
|
||||
return [
|
||||
this.name + ':',
|
||||
truncate(JSON.stringify(this.actual, replacer), 128),
|
||||
this.operator,
|
||||
truncate(JSON.stringify(this.expected, replacer), 128)
|
||||
].join(' ');
|
||||
}
|
||||
};
|
||||
|
||||
// assert.AssertionError instanceof Error
|
||||
|
||||
assert.AssertionError.__proto__ = Error.prototype;
|
||||
|
||||
// At present only the three keys mentioned above are used and
|
||||
// understood by the spec. Implementations or sub modules can pass
|
||||
// other keys to the AssertionError's constructor - they will be
|
||||
// ignored.
|
||||
|
||||
// 3. All of the following functions must throw an AssertionError
|
||||
// when a corresponding condition is not met, with a message that
|
||||
// may be undefined if not provided. All assertion methods provide
|
||||
// both the actual and expected values to the assertion error for
|
||||
// display purposes.
|
||||
|
||||
function fail(actual, expected, message, operator, stackStartFunction) {
|
||||
throw new assert.AssertionError({
|
||||
message: message,
|
||||
actual: actual,
|
||||
expected: expected,
|
||||
operator: operator,
|
||||
stackStartFunction: stackStartFunction
|
||||
});
|
||||
}
|
||||
|
||||
// EXTENSION! allows for well behaved errors defined elsewhere.
|
||||
assert.fail = fail;
|
||||
|
||||
// 4. Pure assertion tests whether a value is truthy, as determined
|
||||
// by !!guard.
|
||||
// assert.ok(guard, message_opt);
|
||||
// This statement is equivalent to assert.equal(true, !!guard,
|
||||
// message_opt);. To test strictly for the value true, use
|
||||
// assert.strictEqual(true, guard, message_opt);.
|
||||
|
||||
function ok(value, message) {
|
||||
if (!!!value) fail(value, true, message, '==', assert.ok);
|
||||
}
|
||||
assert.ok = ok;
|
||||
|
||||
// 5. The equality assertion tests shallow, coercive equality with
|
||||
// ==.
|
||||
// assert.equal(actual, expected, message_opt);
|
||||
|
||||
assert.equal = function equal(actual, expected, message) {
|
||||
if (actual != expected) fail(actual, expected, message, '==', assert.equal);
|
||||
};
|
||||
|
||||
// 6. The non-equality assertion tests for whether two objects are not equal
|
||||
// with != assert.notEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notEqual = function notEqual(actual, expected, message) {
|
||||
if (actual == expected) {
|
||||
fail(actual, expected, message, '!=', assert.notEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 7. The equivalence assertion tests a deep equality relation.
|
||||
// assert.deepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.deepEqual = function deepEqual(actual, expected, message) {
|
||||
if (!_deepEqual(actual, expected)) {
|
||||
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function _deepEqual(actual, expected) {
|
||||
// 7.1. All identical values are equivalent, as determined by ===.
|
||||
if (actual === expected) {
|
||||
return true;
|
||||
|
||||
// } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
|
||||
// if (actual.length != expected.length) return false;
|
||||
//
|
||||
// for (var i = 0; i < actual.length; i++) {
|
||||
// if (actual[i] !== expected[i]) return false;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
//
|
||||
// 7.2. If the expected value is a Date object, the actual value is
|
||||
// equivalent if it is also a Date object that refers to the same time.
|
||||
} else if (actual instanceof Date && expected instanceof Date) {
|
||||
return actual.getTime() === expected.getTime();
|
||||
|
||||
// 7.3 If the expected value is a RegExp object, the actual value is
|
||||
// equivalent if it is also a RegExp object with the same source and
|
||||
// properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
|
||||
} else if (actual instanceof RegExp && expected instanceof RegExp) {
|
||||
return actual.source === expected.source &&
|
||||
actual.global === expected.global &&
|
||||
actual.multiline === expected.multiline &&
|
||||
actual.lastIndex === expected.lastIndex &&
|
||||
actual.ignoreCase === expected.ignoreCase;
|
||||
|
||||
// 7.4. Other pairs that do not both pass typeof value == 'object',
|
||||
// equivalence is determined by ==.
|
||||
} else if (typeof actual != 'object' && typeof expected != 'object') {
|
||||
return actual == expected;
|
||||
|
||||
// 7.5 For all other Object pairs, including Array objects, equivalence is
|
||||
// determined by having the same number of owned properties (as verified
|
||||
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
||||
// (although not necessarily the same order), equivalent values for every
|
||||
// corresponding key, and an identical 'prototype' property. Note: this
|
||||
// accounts for both named and indexed properties on Arrays.
|
||||
} else {
|
||||
return objEquiv(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
function isUndefinedOrNull(value) {
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
function isArguments(object) {
|
||||
return Object.prototype.toString.call(object) == '[object Arguments]';
|
||||
}
|
||||
|
||||
function objEquiv(a, b) {
|
||||
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
||||
return false;
|
||||
// an identical 'prototype' property.
|
||||
if (a.prototype !== b.prototype) return false;
|
||||
//~~~I've managed to break Object.keys through screwy arguments passing.
|
||||
// Converting to array solves the problem.
|
||||
if (isArguments(a)) {
|
||||
if (!isArguments(b)) {
|
||||
return false;
|
||||
}
|
||||
a = pSlice.call(a);
|
||||
b = pSlice.call(b);
|
||||
return _deepEqual(a, b);
|
||||
}
|
||||
try {
|
||||
var ka = Object.keys(a),
|
||||
kb = Object.keys(b),
|
||||
key, i;
|
||||
} catch (e) {//happens when one is a string literal and the other isn't
|
||||
return false;
|
||||
}
|
||||
// having the same number of owned properties (keys incorporates
|
||||
// hasOwnProperty)
|
||||
if (ka.length != kb.length)
|
||||
return false;
|
||||
//the same set of keys (although not necessarily the same order),
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
//~~~cheap key test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
if (ka[i] != kb[i])
|
||||
return false;
|
||||
}
|
||||
//equivalent values for every corresponding key, and
|
||||
//~~~possibly expensive deep test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
key = ka[i];
|
||||
if (!_deepEqual(a[key], b[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 8. The non-equivalence assertion tests for any deep inequality.
|
||||
// assert.notDeepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
||||
if (_deepEqual(actual, expected)) {
|
||||
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 9. The strict equality assertion tests strict equality, as determined by ===.
|
||||
// assert.strictEqual(actual, expected, message_opt);
|
||||
|
||||
assert.strictEqual = function strictEqual(actual, expected, message) {
|
||||
if (actual !== expected) {
|
||||
fail(actual, expected, message, '===', assert.strictEqual);
|
||||
}
|
||||
};
|
||||
|
||||
// 10. The strict non-equality assertion tests for strict inequality, as
|
||||
// determined by !==. assert.notStrictEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
||||
if (actual === expected) {
|
||||
fail(actual, expected, message, '!==', assert.notStrictEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function expectedException(actual, expected) {
|
||||
if (!actual || !expected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (expected instanceof RegExp) {
|
||||
return expected.test(actual);
|
||||
} else if (actual instanceof expected) {
|
||||
return true;
|
||||
} else if (expected.call({}, actual) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _throws(shouldThrow, block, expected, message) {
|
||||
var actual;
|
||||
|
||||
if (typeof expected === 'string') {
|
||||
message = expected;
|
||||
expected = null;
|
||||
}
|
||||
|
||||
try {
|
||||
block();
|
||||
} catch (e) {
|
||||
actual = e;
|
||||
}
|
||||
|
||||
message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
|
||||
(message ? ' ' + message : '.');
|
||||
|
||||
if (shouldThrow && !actual) {
|
||||
fail('Missing expected exception' + message);
|
||||
}
|
||||
|
||||
if (!shouldThrow && expectedException(actual, expected)) {
|
||||
fail('Got unwanted exception' + message);
|
||||
}
|
||||
|
||||
if ((shouldThrow && actual && expected &&
|
||||
!expectedException(actual, expected)) || (!shouldThrow && actual)) {
|
||||
throw actual;
|
||||
}
|
||||
}
|
||||
|
||||
// 11. Expected to throw an error:
|
||||
// assert.throws(block, Error_opt, message_opt);
|
||||
|
||||
assert.throws = function(block, /*optional*/error, /*optional*/message) {
|
||||
_throws.apply(this, [true].concat(pSlice.call(arguments)));
|
||||
};
|
||||
|
||||
// EXTENSION! This is annoying to write outside this module.
|
||||
assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {
|
||||
_throws.apply(this, [false].concat(pSlice.call(arguments)));
|
||||
};
|
||||
|
||||
assert.ifError = function(err) { if (err) {throw err;}};
|
||||
|
||||
})(this);
|
||||
12
lib/client/console/test/vendor/coffeescript.js
vendored
Normal file
12
lib/client/console/test/vendor/coffeescript.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9111
lib/client/console/test/vendor/jquery-2.1.0.js
vendored
Normal file
9111
lib/client/console/test/vendor/jquery-2.1.0.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
241
lib/client/console/test/vendor/mocha.css
vendored
Normal file
241
lib/client/console/test/vendor/mocha.css
vendored
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
@charset "utf-8";
|
||||
|
||||
body {
|
||||
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
padding: 60px 50px;
|
||||
}
|
||||
|
||||
#mocha ul, #mocha li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#mocha ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#mocha h1, #mocha h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#mocha h1 {
|
||||
margin-top: 15px;
|
||||
font-size: 1em;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
#mocha h1 a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#mocha h1 a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#mocha .suite .suite h1 {
|
||||
margin-top: 0;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha h2 {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#mocha .suite {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
#mocha .test {
|
||||
margin-left: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#mocha .test.pending:hover h2::after {
|
||||
content: '(pending)';
|
||||
font-family: arial;
|
||||
}
|
||||
|
||||
#mocha .test.pass.medium .duration {
|
||||
background: #C09853;
|
||||
}
|
||||
|
||||
#mocha .test.pass.slow .duration {
|
||||
background: #B94A48;
|
||||
}
|
||||
|
||||
#mocha .test.pass::before {
|
||||
content: '✓';
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
color: #00d6b2;
|
||||
}
|
||||
|
||||
#mocha .test.pass .duration {
|
||||
font-size: 9px;
|
||||
margin-left: 5px;
|
||||
padding: 2px 5px;
|
||||
color: white;
|
||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-ms-border-radius: 5px;
|
||||
-o-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#mocha .test.pass.fast .duration {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha .test.pending {
|
||||
color: #0b97c4;
|
||||
}
|
||||
|
||||
#mocha .test.pending::before {
|
||||
content: '◦';
|
||||
color: #0b97c4;
|
||||
}
|
||||
|
||||
#mocha .test.fail {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
#mocha .test.fail pre {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#mocha .test.fail::before {
|
||||
content: '✖';
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
#mocha .test pre.error {
|
||||
color: #c00;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#mocha .test pre {
|
||||
display: block;
|
||||
float: left;
|
||||
clear: left;
|
||||
font: 12px/1.5 monaco, monospace;
|
||||
margin: 5px;
|
||||
padding: 15px;
|
||||
border: 1px solid #eee;
|
||||
border-bottom-color: #ddd;
|
||||
-webkit-border-radius: 3px;
|
||||
-webkit-box-shadow: 0 1px 3px #eee;
|
||||
-moz-border-radius: 3px;
|
||||
-moz-box-shadow: 0 1px 3px #eee;
|
||||
}
|
||||
|
||||
#mocha .test h2 {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#mocha .test a.replay {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
right: 0;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
display: block;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
line-height: 15px;
|
||||
text-align: center;
|
||||
background: #eee;
|
||||
font-size: 15px;
|
||||
-moz-border-radius: 15px;
|
||||
border-radius: 15px;
|
||||
-webkit-transition: opacity 200ms;
|
||||
-moz-transition: opacity 200ms;
|
||||
transition: opacity 200ms;
|
||||
opacity: 0.3;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#mocha .test:hover a.replay {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#mocha-report.pass .test.fail {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha-report.fail .test.pass {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#mocha-error {
|
||||
color: #c00;
|
||||
font-size: 1.5 em;
|
||||
font-weight: 100;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
#mocha-stats {
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 10px;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
#mocha-stats .progress {
|
||||
float: right;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
#mocha-stats em {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#mocha-stats a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#mocha-stats a:hover {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
#mocha-stats li {
|
||||
display: inline-block;
|
||||
margin: 0 5px;
|
||||
list-style: none;
|
||||
padding-top: 11px;
|
||||
}
|
||||
|
||||
code .comment { color: #ddd }
|
||||
code .init { color: #2F6FAD }
|
||||
code .string { color: #5890AD }
|
||||
code .keyword { color: #8A6343 }
|
||||
code .number { color: #2F6FAD }
|
||||
|
||||
@media screen and (max-device-width: 480px) {
|
||||
body {
|
||||
padding: 60px 0px;
|
||||
}
|
||||
|
||||
#stats {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
5341
lib/client/console/test/vendor/mocha.js
vendored
Normal file
5341
lib/client/console/test/vendor/mocha.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue