File: js/ptty.js

Recommend this page to a friend!
  Classes of Till Wehowski   Widget CLI   js/ptty.js   Download  
File: js/ptty.js
Role: Class source
Content type: text/plain
Description: Class source
Class: Widget CLI
Process commands entered by the user
Author: By
Last change:
Date: 7 years ago
Size: 30,598 bytes
 

Contents

Class file image Download
/*!* * @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>&nbsp;</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>&nbsp;' + command + '</span>'; }else if( cmd_opts.cmd_quiet == 'blank' ){ p = '<span class="' + command_class + '"><span>' + p + '</span>&nbsp;</span>'; }else if( cmd_opts.cmd_quiet == 'output' ){ p = ''; }else{ p = '<span class="' + command_class + '"><span>' + p + '</span>&nbsp;' + 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 );