%PDF- %PDF-
Direktori : /var/www/projetos/spanish.ongrace.com/wp-content/plugins/wp-maintenance-mode/assets/js/ |
Current File : /var/www/projetos/spanish.ongrace.com/wp-content/plugins/wp-maintenance-mode/assets/js/bot.js |
/* global jQuery, botVars */ const DEBUG = false; // User info retrieved from chats is store in this object const context = {}; // Cache conversation position let conversationPos; // Cache conversation status let conversationStarted = false; /* --------------- Utility Functions --------------- */ /** * Cast string * * @param value * @return string */ function _phpCastString( value ) { const type = typeof value; switch ( type ) { case 'boolean': return value ? '1' : ''; case 'string': return value; case 'number': if ( isNaN( value ) ) { return 'NAN'; } if ( ! isFinite( value ) ) { return ( value < 0 ? '-' : '' ) + 'INF'; } return value + ''; case 'undefined': return ''; case 'object': if ( Array.isArray( value ) ) { return 'Array'; } if ( value !== null ) { return 'Object'; } return ''; case 'function': // fall through default: throw new Error( 'Unsupported value type' ); } } /** * Strip tags from a string * * big thanks to http://locutus.io/php/strings/strip_tags/ * * @param string input * @param string allowed * @param input * @param allowed * @return string */ function stripTags( input, allowed ) { // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>) allowed = ( ( ( allowed || '' ) + '' ).toLowerCase().match( /<[a-z][a-z0-9]*>/g ) || [] ).join( '' ); const tags = /<\/?([a-z0-9]*)\b[^>]*>?/gi; const commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi; let after = _phpCastString( input ); // removes tha '<' char at the end of the string to replicate PHP's behaviour after = ( after.substring( after.length - 1 ) === '<' ) ? after.substring( 0, after.length - 1 ) : after; // recursively remove tags to ensure that the returned string doesn't contain forbidden tags after previous passes (e.g. '<<bait/>switch/>') while ( true ) { const before = after; after = before.replace( commentsAndPhpTags, '' ).replace( tags, function( $0, $1 ) { return allowed.indexOf( '<' + $1.toLowerCase() + '>' ) > -1 ? $0 : ''; } ); // return once no more tags are removed if ( before === after ) { return after; } } } function renderStatement( statement ) { // Strip html tags from statement statement = stripTags( statement ); jQuery( '.chat-container' ).append( '<div class="chat-message-wrapper"><p class="chat-message">' + statement + '</p></div>' ); } function showTyping() { jQuery( '.chat-container' ).append( '<div class="typing-wrapper"><p class="chat-message typing"><span class="dot"></span><span class="dot"></span><span class="dot"></span></p></div>' ); } function hideTyping() { jQuery( '.typing-wrapper' ).remove(); } const chatWrapper = jQuery( '.bot-chat-wrapper' ); function scrollToBottom() { chatWrapper.animate( { scrollTop: 600, }, 'slow' ); } /** * Input checking * * @param msg */ function inputError( msg ) { jQuery( '.bot-error p' ).text( msg ); jQuery( '.bot-error' ) .animate( { bottom: '20px' }, 500 ) .delay( 3000 ) .animate( { bottom: '-70px' }, 500 ); } function checkInput( option ) { let input = jQuery( '.bot-container input[type=text]' ).val(); // Strip html tags from input input = stripTags( input ); if ( input.length > 2 ) { showResponse( option ); } else { inputError( botVars.validationName ); } return false; } function checkEmail( option ) { const input = jQuery( '.bot-container input[type=email]' ).val(); const regex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; const result = regex.test( String( input.toLowerCase() ) ); if ( input.length > 7 && result === true ) { // Add new entry to our db const botSubscribeForm = jQuery( '.bot_subscribe_form' ).serialize(); const subscribeBotData = 'action=wpmm_add_subscriber&' + botSubscribeForm; jQuery.post( wpmmVars.ajaxURL, subscribeBotData, function( response ) { if ( ! response.success ) { alert( response.data ); return false; } }, 'json' ); showResponse( option ); } else { inputError( botVars.validationEmail ); } return false; } function clearChat() { jQuery( '.chat-container' ).empty(); } function clearFooter() { jQuery( '.choices' ).empty(); jQuery( '.input' ).empty(); } /* ------------------------ Setup Conversation Data ------------------------ */ function startConversation( conv, pos ) { /* We need this to maintain backward compatibility because we moved startConversation() from /views/maintenance.php to bot.js */ if ( conversationStarted ) { return false; } conversationStarted = true; clearFooter(); clearChat(); // Set conversation position // 'conversation' is in the global scope conversationPos = conv; // Load conversation data jQuery.getScript( botVars.uploadsBaseUrl + 'data.js', function( data ) { // Show first bot statement showStatement( pos ); } ); } /* ------------------- Show Bot Statement ------------------- */ function showStatement( pos ) { // Where are we in conversationData? const node = conversationData[ conversationPos ][ pos ]; // If there is a side effect execute that within the context if ( 'sideeffect' in node && jQuery.type( node.sideeffect === 'function' ) ) { node.sideeffect( context ); } // Wrap the statements in an array (if they're not already) let statements; if ( jQuery.type( node.statement ) === 'array' ) { statements = node.statement; } else if ( jQuery.type( node.statement ) === 'string' ) { statements = [ node.statement ]; } else if ( jQuery.type( node.statement ) === 'function' ) { statements = node.statement( context ); } if ( pos === 1.5 || pos === 1.6 ) { jQuery( '.avatar-notice' ).remove(); } /* ------------------------ Render Bot Statement(s) ------------------------ Run this function over each statement */ async.eachSeries( statements, function( item, callback ) { // Emulate typing then scroll to bottom showTyping(); scrollToBottom(); let delay = 900; if ( DEBUG || ! jQuery( '.bot-chat-wrapper' )[ 0 ] ) { delay = 0; } setTimeout( function() { hideTyping(); renderStatement( item ); scrollToBottom(); callback(); }, delay ); }, /* ---------------------- Render User Option(s) ---------------------- This is the final callback of the series */ function( err ) { /* ---------------------------- If User Option is Button(s) ---------------------------- */ if ( 'options' in node ) { jQuery( '.input' ).hide(); jQuery( '.choices' ).show(); // Get the options' data const options = node.options; // If there are options render them // Otherwise this is the end if ( options.length > 0 ) { // Pause 750ms, then render options setTimeout( function() { for ( let i = 0; i < options.length; i++ ) { const option = options[ i ]; var extraClass; var clickFunction; // Check option for a consequence if ( option.consequence === null ) { // The consequence is null meaning this is a branch we won't be exploring // The button is given class 'disabled' and does nothing on click clickFunction = null; extraClass = 'disabled'; } else { // Else, click function (showResponse) is binded to it clickFunction = function( option ) { showResponse( option ); }.bind( null, option ); extraClass = ''; } // Render button const button = jQuery( '<p/>', { text: option.choice, class: 'chat-message user', click: clickFunction, } ).appendTo( '.choices' ); } }, 750 ); } /* ------------------------ If User Option is Input ------------------------ */ } else if ( 'input' in node ) { jQuery( '.input' ).show(); jQuery( '.choices' ).hide(); var option = node.input; /* Render Input --------------- */ // Create a form to hold our input and submit button var form = jQuery( '<form/>', { submit: checkInput.bind( null, option ), } ); // Create a user bubble, append to form var inputBubble = jQuery( '<p/>', { class: 'chat-message user', } ).appendTo( form ); // Create an input, append to user bubble var input = jQuery( '<input/>', { type: 'text', placeholder: botVars.typeName, name: option.name, autocomplete: 'off', required: true, } ).appendTo( inputBubble ); // Create an input button, append to user bubble var button = jQuery( '<a/>', { text: botVars.send, click: checkInput.bind( null, option ), } ).appendTo( inputBubble ); // Append form to div.input form.appendTo( '.input' ); // Focus on the input we just put into the DOM async.nextTick( function() { input.focus(); } ); /* ------------------------ If User Option is Email ------------------------ */ } else if ( 'email' in node ) { jQuery( '.input' ).show(); jQuery( '.choices' ).hide(); var option = node.email; /* Render Input --------------- */ // Create a form to hold our input and submit button var form = jQuery( '<form/>', { class: 'bot_subscribe_form', submit: checkEmail.bind( null, option ), } ); // Create a user bubble, append to form var inputBubble = jQuery( '<p/>', { class: 'chat-message user', } ).appendTo( form ); // Create hidden input, append to user bubble var input = jQuery( '<input/>', { type: 'hidden', name: '_wpnonce', value: botVars.wpnonce, } ).appendTo( inputBubble ); // Create email input, append to user bubble var input = jQuery( '<input/>', { type: 'email', placeholder: botVars.typeEmail, name: option.email, autocomplete: 'off', } ).appendTo( inputBubble ); // Create an input button, append to user bubble var button = jQuery( '<a/>', { text: botVars.send, // "class": "user-email-trigger", click: checkEmail.bind( null, option ), } ).appendTo( inputBubble ); // Append form to div.input form.appendTo( '.input' ); // Focus on the input we just put into the DOM async.nextTick( function() { input.focus(); } ); } scrollToBottom(); } ); } /* --------------------- Render User Response --------------------- */ function showResponse( option ) { // If there was an input element, put that into the global context let feedback = ''; if ( 'name' in option ) { context[ option.name ] = jQuery( '.bot-container input[type=text]' ).val(); feedback = context[ option.name ]; } else if ( 'email' in option ) { context[ option.email ] = jQuery( '.bot-container input[type=email]' ).val(); feedback = context[ option.email ]; } else { feedback = option.choice; } clearFooter(); // Strip html tags from feedback feedback = stripTags( feedback ); // Show what the user chose jQuery( '.chat-container' ).append( '<p class="chat-message user">' + feedback + '</p>' ); if ( 'consequence' in option ) { showStatement( option.consequence ); } else { // xxx } } /* ------------------- Initialize Conversation ------------------- */ let isOpen = false; jQuery( '.bot-avatar' ).on( 'click', function() { const chatWrap = jQuery( '.bot-chat-wrapper' )[ 0 ]; if ( ! isOpen ) { isOpen = true; startConversation( 'homepage', 1 ); } if ( chatWrap.style.display !== 'none' ) { jQuery( '.avatar-notice' ).show(); jQuery( '.bot-chat-wrapper' ).hide(); } else { jQuery( '.bot-chat-wrapper' ).show(); jQuery( '.avatar-notice' ).hide(); } } );