/*!*
* @file : Ptty.jquery.js
* @ver : 0.0.3
* @Author : Patxi Pierce
* @url : http://code.patxipierce.com/jquery-plugin/ptty/
* @desc : Ptty (Pachanka's teletype). A terminal emulator plugin for jQuery.
* @note : Based on wterm.js by Venkatakrishnan Ganesh.
* @license: Copyright 2014 Patxi Pierce <mail@patxipierce.com>
* This work is free. You can redistribute it and/or modify it under the
* terms of the Do What The Fuck You Want To Public License, Version 2,
* as published by Sam Hocevar. See the COPYING file for more details.
* */
( function( $ ) {
var version = '0.0.3-frdl.2.1';
var clisetup = require('http://'+frdl.route('HOST_CDN_PUBLIC_FRDL')+'/cdn/frdl/flow/components/webfan/cli/clisetup/clisetup');
var sequence = [];
var _$ = '';
var get_defaults = function() {
return {
url : window.location.pathname,
method : 'POST',
param : 'cmd',
tty_class : 'cmd_terminal',
ps : '',
theme : 'boring',
width : '100%',
height : '100%',
welcome : 'Ptty v.' + version,
placeholder : '*',
not_found : '<div> CMD: Command Not Found </div>',
error_prefix : 'An Error Occured: ',
autocomplete : true,
history : true,
history_max : 800,
charset : 'UTF-8',
enctype : 'multipart/form-data',
autofocus : true
};
};
var dispatch = {};
var callbacks = {};
var history = [ ];
var cmd_opts = {
cmd_name : null,
cmd_class : null,
cmd_ps : null,
cmd_in : null,
cmd_out : null,
cmd_quiet : null,
cmd_token : null,
cmd_query : null,
};
var native_commands = function(options){
var settings = get_defaults();
$.extend( true, settings, options );
$.register_command(
'clear',
'Cleans the screen leaving a new command prompt ready.',
'clear [no options]',
function() {
$('.' + settings.tty_class + '_content').html( '' );
return { type : 'print', out : '', quiet : 'clear' };
}
);
$.register_command(
'history',
'Shows list of typed in commands.',
'history [no options]',
function() {
var hist_out = '';
if(settings.history && history.length > 0){
var i, tmp;
for( i in history ) {
tmp = history[i];
hist_out += '<li>' + tmp + '</li>';
}
hist_out = '<ul class="ve-li">' + hist_out + '</ul>';
}
return { type : 'print', out : hist_out };
}
);
$.register_command(
'help',
'Displays a list of useful information.',
'help [ [-a | --all] | [command] ]',
function(tokens) {
var help_out = '';
if(typeof tokens[1] === 'string' && tokens[1].length > 0){
var cmd_to_show = $.trim(tokens[1]);
if(cmd_to_show == '-a' || cmd_to_show == '--all'){
help_out = 'Available commands are:</br><ul class="ve-li">';
for( i in dispatch ){
help_out += '<li><p><b>'+i+'</b> - '+dispatch[i].desc+'</br>';
help_out += 'Usage: '+dispatch[i].usage+'</p></li>';
}
help_out += '</ul>'+"\n";
}else if(typeof dispatch[cmd_to_show] !== 'undefined'){
help_out = '<b>'+cmd_to_show+'</b> - '+dispatch[cmd_to_show].desc+'</br>';
help_out += 'Usage: '+dispatch[cmd_to_show].usage+"\n";
}else{
help_out = 'help:</br>The "' + cmd_to_show + '" option does not exist.'+"\n";
}
}else{
help_out = 'Use "help [comand name]" to display specific info about a command.</br>'+"\n";
help_out += 'Available commands are:</br><ul class="sq-li">';
for( i in dispatch ){
help_out += '<li>'+i+'</li>';
}
help_out += '</ul>'+"\n";
}
return { type : 'print', out : help_out };
}
);
$.register_command(
'$',
'Assign contents to the shortcut: $',
'$ [ [command] | [no options] ]',
function(tokens) {
var t = tokens;
t.shift();
$.set_shortcut_main(t.join(' '));
return { type : 'print', out : 'Shortcut $ assigned to "' + _$ + '"'};
}
);
};
$.fn.Ptty = function( options ) {
var settings = get_defaults();
$.extend( true, settings, options );
return this.each( function() {
var element = $( this );
var hcurrent = null;
element.addClass( settings.tty_class ).addClass( settings.tty_class +'_theme_'+ settings.theme );
if( settings.width && settings.height ){
element.css( { width: settings.width, height: settings.height } );
}
element.html( '' ).append( '<div class="'+settings.tty_class+'_loading"><span></span></div>'
+ '<div class="' + settings.tty_class + '_content"><div>' + settings.welcome + '</div></div>'
+ '<div class="' + settings.tty_class + '_prompt"><span class="' + settings.tty_class + '_ps">'
+ '<span class="' + settings.tty_class + '_active">' + settings.ps + '</span> </span>'
+ '<form accept-charset="'+settings.charset+'" enctype="'+settings.enctype+'">'
+ '<input type="text" autocomplete="off" /><input type="password" />'
+ '<span class="upl_container hide"><input type="file" /><a href="javascript:void(0)" '
+ 'onclick="$(this).parent().addClass(\'hide\').siblings(\'input[type=text]\').show();">Cancel</a></span>'
+ '</form><progress class="' + settings.tty_class + '_progress"></progress></div>');
var prompt = element.find( 'span.' + settings.tty_class + '_active' );
var input_form = element.find( 'div:last form' );
var input = input_form.find( 'input' );
var txt_input = input_form.find( 'input[type=text]' );
var psw_input = input_form.find( 'input[type=password]' );
var upl_input = input_form.find( 'input[type=file]' );
var content = element.find( 'div.' + settings.tty_class + '_content' );
var loading = element.find( 'div.' + settings.tty_class + '_loading' );
var cdispatch = null;
var saved = { ac_save : null, h_save : null };
if(settings.autofocus){
txt_input.focus();
}
element.bind('select focus click', function(){
if(txt_input.is(':visible')){
txt_input.focus();
}else if(psw_input.is(':visible')){
psw_input.focus();
}
});
prompt.removeAttr('disabled');
native_commands(options);
var update_content = function( p, command, output ) {
var command_class = cmd_opts.cmd_class;
if( command_class === null ){
command_class = (cdispatch) ? settings.tty_class + '_sub' : settings.tty_class + '_ps';
}
if( cmd_opts.cmd_in !== null ) command = cmd_opts.cmd_in;
if( cmd_opts.cmd_out !== null ) output = cmd_opts.cmd_out;
if( cmd_opts.cmd_quiet == 'clear' ){
content.html('');
p = '';
}else if( cmd_opts.cmd_quiet == 'password'){
command = Array(command.length + 1).join(settings.placeholder);
p = '<span class="' + command_class + '"><span>' + p + '</span> ' + command + '</span>';
}else if( cmd_opts.cmd_quiet == 'blank' ){
p = '<span class="' + command_class + '"><span>' + p + '</span> </span>';
}else if( cmd_opts.cmd_quiet == 'output' ){
p = '';
}else{
p = '<span class="' + command_class + '"><span>' + p + '</span> ' + command + '</span>';
}
content.append( '<div>' + p + '<div>' + output + '</div></div>' );
loading.fadeOut(100);
prompt.removeAttr('disabled').show();
};
var get_prompt = function() {
var ps = (cdispatch) ? cdispatch.ps : settings.ps;
return (cmd_opts.cmd_ps !== null) ? cmd_opts.cmd_ps : ps;
};
var set_prompt = function(ps) {
if( cmd_opts.cmd_class === null ){
cmd_opts.cmd_class = ( cdispatch ) ? settings.tty_class + '_sub' : settings.tty_class + '_ps';
}
if( ps === null ) ps = (cdispatch) ? cdispatch.ps : settings.ps;
prompt.html(ps);
return ps;
};
var cmd_do_ajax = function(key, value, ajax_url){
var ajax_data = { cmd : value };
if(cmd_opts.cmd_query !== null) ajax_data['cmd_query'] = cmd_opts.cmd_query;
if(cmd_opts.cmd_in !== null) ajax_data['cmd'] = cmd_opts.cmd_in;
if(cmd_opts.cmd_token !== null) ajax_data['cmd_token'] = cmd_opts.cmd_token;
if(ajax_url === false || ajax_url == '' || typeof ajax_url === 'undefined'){
ajax_url = (dispatch[key].type_of) ? dispatch[key].type_of : settings.url;
}
$.ajax({
type: settings.method,
url: ajax_url,
data: ajax_data
})
.done(function( data ){
data['ajax_url'] = ajax_url;
data = data || '';
cmd_callback( value, data );
})
.fail(function() {
update_content(
get_prompt(),
value,
'<div>' + settings.error_prefix + ' Invalid server response. </div>'
);
});
};
var cmd_execute = function( key, value, tokens, ajax_url ) {
if( key == '' ) {
update_content( get_prompt(), value, '');
}else if( cdispatch !== null ){
cmd_custom_dispatch( key, value, tokens );
}else if(typeof dispatch[key] === 'undefined'){
/*
update_content( get_prompt(), value, settings.not_found.replace( 'CMD', tokens[0] ));
*/
if('webfan'!==tokens[0] && 'webfan'!==tokens[1]){
tokens = ['webfan'].concat(tokens);
return cmd_execute('webfan', 'webfan '+value, tokens, ajax_url);
}
update_content( get_prompt(), value, settings.not_found.replace( 'CMD', tokens[0] ));
}else if( typeof dispatch[key].type_of === 'object' ) {
cmd_custom_dispatch( key, value, tokens );
}else if( typeof dispatch[key].type_of === 'string' ) {
cmd_do_ajax( key, value, ajax_url);
}else if( typeof dispatch[key].type_of === 'function' ) {
cmd_dispatch_js( dispatch[key].type_of, tokens, value );
}else{
cmd_do_ajax( key, value, settings.url );
}
};
$.cliExec = function( cmd, shell ) {
/*/ var tokens = cmd.split(' '); */
var tokens = clisetup.parseArgs(cmd, true);
if('' !== get_prompt() )exit_subroutine();
if('undefined' !== typeof shell && null !== shell && '' !== shell){
cmd_execute( shell, shell);
}
cmd_execute( tokens[0], cmd, tokens );
};
var start_subroutine = function(key){
cdispatch = dispatch[ key ].type_of;
prompt.html(cdispatch.ps);
element.find( 'div:last span:first' )
.toggleClass(settings.tty_class + '_ps '+settings.tty_class + '_sub');
cmd_opts.cmd_name = key;
cmd_opts.cmd_ps = settings.ps;
cmd_opts.cmd_class = settings.tty_class + '_ps';
saved.ac_save = settings.autocomplete;
settings.autocomplete = false;
saved.h_save = history;
history = [ ];
};
var exit_subroutine = function(){
prompt.html('');
element.find( 'div:last span:first' )
.toggleClass(settings.tty_class + '_ps '+settings.tty_class + '_sub');
cmd_opts.cmd_ps = (cmd_opts.cmd_ps !== null) ? cmd_opts.cmd_ps : cdispatch.ps;
cmd_opts.cmd_class = settings.tty_class+'_sub';
cmd_opts.cmd_name = null;
cmd_opts.cmd_token = null;
cmd_opts.cmd_query = null;
settings.autocomplete = ( saved.ac_save ) ? saved.ac_save : false;
history = ( saved.h_save ) ? saved.h_save : [ ];
cdispatch = null;
};
var cmd_custom_dispatch = function( key, value, tokens ) {
var hook = settings.url;
if(cdispatch == null){
start_subroutine(key);
hook = cdispatch.start_hook;
}else if(cdispatch){
if(key == 'quit' || key == 'exit') {
hook = cdispatch.exit_hook;
exit_subroutine();
}else{
hook = cdispatch.dispatch_method;
}
}
if(typeof hook === 'string'){
cmd_do_ajax( key, value, hook);
}else if(typeof hook === 'function'){
cmd_dispatch_js( hook, tokens, value );
}
};
var cmd_dispatch_js = function( js_func, tokens, value ) {
return cmd_callback( value, js_func( tokens ) );
};
var cmd_callback = function( value, data ) {
data = data || '';
var cbk = { ps : get_prompt(), output : '' };
switch ( data.type ){
case 'prompt':
if(!cmd_opts.cmd_token){
var token1 = Math.random().toString(36).substr(2),
token2 = Math.random().toString(36).substr(2),
token3 = Math.random().toString(36).substr(2);
cmd_opts.cmd_token = token1+token2+token3;
}
break;
case 'password':
txt_input.hide();
psw_input.show().focus();
break;
case 'upload':
if(typeof data.upload_multiple != 'undefined') upl_input.attr('multiple', 'multiple');
if(typeof data.upload_accept != 'undefined') upl_input.attr('accept', data.upload_accept);
txt_input.hide();
upl_input.parent().removeClass('hide');
upl_input.bind('change', function(){
upl_input.parent().addClass('hide');
txt_input.show();
if(upl_input.val() != ''){
cmd_upload( this.files , data );
}
upl_input.attr('accept', '');
upl_input.attr('multiple', '');
upl_input.val('');
});
break;
default:
data.type = 'print';
break;
}
if( value == 'exit' || value == 'quit' ){
cbk.ps = cmd_opts.cmd_ps;
cmd_opts.cmd_ps = null;
}
cmd_opts.cmd_ps = ( typeof data.ps !== 'undefined' ) ? set_prompt(data.ps) : null;
if( typeof data.class !== 'undefined' ) cmd_opts.cmd_class = data.class;
if( typeof data.in !== 'undefined' ) cmd_opts.cmd_in = data.in;
if( typeof data.out !== 'undefined' ) cbk.output = cmd_opts.cmd_out = data.out;
if( typeof data.quiet !== 'undefined' ) cmd_opts.cmd_quiet = data.quiet;
if( typeof data.token !== 'undefined' ) cmd_opts.cmd_token = data.token;
if( typeof data.query !== 'undefined' ) cmd_opts.cmd_query = data.query;
update_content( cbk.ps, value, cbk.output);
if( typeof data.exit !== 'undefined' && cdispatch ){
exit_subroutine();
cmd_opts.cmd_ps = null;
}
if(typeof data.callback !== 'undefined'){
try{
if( typeof callbacks[data.callback] === 'function' ){
cbk.output = callbacks[data.callback]( data );
}else{
throw( settings.error_prefix + ' ' + data.callback + ' callback unknown.');
}
} catch ( e ) {
}
}
};
var scroll_to_bottom = function(){
var tries = 0, old_height = new_height = element.height();
var intervalId = setInterval(function() {
if( old_height != new_height ){
clearInterval(intervalId);
element.animate({ scrollTop: new_height }, 'slow');
}else if(tries >= 30){
clearInterval(intervalId);
element.animate({ scrollTop: new_height }, 'slow');
}else{
new_height = content.height();
tries++;
}
}, 50);
};
var progress_handler = function(e){
if(e.lengthComputable){
var progress = $('.'+settings.tty_class + '_progress');
progress.attr({
value : e.loaded,
max : e.total
});
}
};
var cmd_upload = function(files, data){
var files_selected = '';
var progress = $('.'+settings.tty_class + '_progress');
if(typeof data.upload_to !== 'undefined'){
var ajax_url = data.upload_to;
}else{
var ajax_url = (cdispatch !== null) ? cdispatch.dispatch_method : settings.url;
}
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("file_" + i, files[i]);
files_selected += ' '+files[i].name;
};
for ( var key in data ) {
formData.append(key, data[key]);
};
progress.show();
$.ajax({
url: ajax_url,
type: 'POST',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
myXhr.upload.addEventListener('progress', progress_handler, false);
}
return myXhr;
},
data: formData,
cache: false,
contentType: false,
processData: false
})
.done(function(response){
console.log('Uploaded:'+files_selected+' to '+ajax_url);
console.log(response);
})
.fail(function(){
console.log('Error uploading.');
})
.always(function(){
progress.hide();
});
};
input_form.submit( function( e ) {
e.preventDefault(); e.stopPropagation();
var value = txt_input.val().trim();
var save_to_history = (value.charAt(0) == ' ') ? false : true;
value = $.trim( $( '<div/>' ).text( value ).html() );
if(psw_input.val().length){
value = psw_input.val();
psw_input.val( '' );
}
if(upl_input.val().length){
value = upl_input.val();
upl_input.val( '' );
}
for (var opt in cmd_opts) {
if(opt !== 'cmd_name' && opt !== 'cmd_ps' && opt !== 'cmd_query' && opt !== 'cmd_token'){
cmd_opts[opt] = null;
}
};
cmd_opts.cmd_in = value;
if( cmd_opts.cmd_query !== null ) value = cmd_opts.cmd_query + value;
// var tokens = value.split( /\s+/ );
/*
var tokens_2 = $.grep( value.match(/((-{1,2})?\S+\s?)?(["']((?:\\.|[^"\\])*)["'])?|\S+/g), function (n) { return $.trim(n) });
alert(JSON.stringify(tokens_2));
alert(JSON.stringify(tokens));
*/
var tokens = clisetup.parseArgs(value, true);
var key = tokens[0];
if( settings.history && (typeof dispatch[key] !== 'undefined' || cdispatch)
&& save_to_history && value.length && cmd_opts.cmd_quiet === null ) {
if( history.length > settings.history_entries ){
history.shift();
}
history.push( $.trim($('<div/>').html(value).text()) );
}
hcurrent = 0;
loading.show();
prompt.attr('disabled', 'disabled').hide();
cmd_execute( key, value, tokens );
txt_input.val( '' );
txt_input.focus();
scroll_to_bottom();
});
txt_input.keydown( function( e ) {
var keycode = e.keyCode;
switch( keycode ) {
/* LEER(32) + SHIFT(16) + $ (52) + LEER */
case 32:
var tok = '<:>$SHORTCUTREPLAC$<:>';
if((/* sequence.length===0 || */ sequence[2] === 32) && ((e.shiftKey && sequence[0] === 52) /* || (sequence[1] === 16 && sequence[0] === 52)*/) ){
Dom.insertAtCursor(e.target, tok + _$, 'deleteSelected', '');
e.target.value = str_replace('$' + tok, '', e.target.value );
}
break;
/* tab */
case 9:
e.preventDefault();
if( settings.autocomplete ) {
var commands = [ ];
var current_value = $.trim( txt_input.val() );
if( current_value.match( /^[^\s]{0,}$/ ) ) {
for( i in dispatch ) {
if( current_value == '' ) {
commands.push( i );
} else if( i.indexOf( current_value ) == 0 ) {
commands.push( i );
}
}
if( commands.length > 1 ) {
update_content(
get_prompt(),
current_value,
'<ul class="sq-li"><li>'+commands.join( '</li><li>' )+'</li></ul>'
);
} else if( commands.length == 1 ) {
txt_input.val( commands.pop() + ' ' );
}
}
}
scroll_to_bottom();
break;
/* arrows */
case 38:
e.preventDefault();
if( settings.history ) {
hcurrent = ( hcurrent === null || hcurrent == 0 ) ? history.length - 1 : hcurrent - 1;
txt_input.val( history[ hcurrent ] );
}
break;
case 40:
e.preventDefault();
if( settings.history ) {
if( hcurrent === null || hcurrent === (history.length - 1 ) ){
txt_input.val( '' );
break;
}
hcurrent++;
txt_input.val( history[ hcurrent ] );
}
break;
/* ENTER */
case 13:
e.preventDefault();
input_form.submit();
scroll_to_bottom();
txt_input.focus();
sequence = [];
break;
}
sequence.unshift(keycode);
while(sequence.length > 256){
sequence.pop();
}
});
psw_input.keydown( function( e ) {
if( psw_input.is(':visible') ){
var keycode = e.keyCode;
switch( keycode ) {
case 13:
e.preventDefault();
input_form.submit();
psw_input.hide();
txt_input.show();
scroll_to_bottom();
txt_input.focus();
break;
}
}
});
$(document).keydown(function(e){
var keycode = e.keyCode;
switch( keycode ) {
case 27:
if(txt_input.is(':visible')) {
txt_input.focus();
}else if(psw_input.is(':visible')){
psw_input.focus();
}
break;
}
});
});
};
$.register_command = function( command, cmd_desc, cmd_usage, dispatch_method ){
var ret = false;
if( typeof dispatch_method === 'string' || typeof dispatch_method === 'object' || typeof dispatch_method === 'function' ){
dispatch[ command ] = {desc : cmd_desc, usage : cmd_usage, type_of : dispatch_method};
ret = true;
}
return ret;
};
$.register_callback = function(cbk_name, cbk_method){
var ret = false;
if( typeof cbk_method === 'string' || typeof cbk_method === 'object' || typeof cbk_method === 'function' ){
callbacks[ cbk_name ] = cbk_method;
ret = true;
}
return ret;
};
$.flush_commands = function(options) {
dispatch = {};
$.set_command_option(options);
native_commands(options);
};
$.set_command_option = function( option_obj ){
$.extend( true, cmd_opts, option_obj );
};
$.get_command_option = function(option_arr){
var out = {};
for(var opt in option_arr){
if(typeof cmd_opts[opt] !== 'undefined'){
out[opt] = cmd_opts[opt];
}
}
return out;
};
$.set_shortcut_main = function(txt){
_$ = txt;
};
})( jQuery );
|