OwlCyberSecurity - MANAGER
Edit File: ai-form-view.js
(function ( $ ) { 'use strict'; window.vc.AiFormView = Backbone.View.extend( { events: { 'click .vc_ai-generate-button': 'generateContent', 'change [name="contentType"]': 'changeContentType', 'input [name="prompt"]': 'changePrompt', 'click [data-vc-ui-element="button-save"]': 'insertContent', 'click .wpb-copy-output': 'copyContent' }, seconds: 0, minutes: 0, timerInterval: null, isGenerating: false, maxWaitingCacheInterval: 900000, maxPromptLength: 2000, initialize: function ( options ) { this.toggleModalPromoClass( options.data.type ); this.$el.find( '.vc_ui-helper-modal-ai-preloader' ).after( options.data.content ); this.setFormElements(); $('.edit-form-info').initializeTooltips(); }, render: function ( options ) { if (this.timerInterval) { this.clearTimer(); } this.toggleModalPromoClass( options.type ); this.$form.after( options.content ); this.$form.remove(); this.setFormElements(); return this; }, setFormElements: function () { this.$form = this.$el.find( '.vc_ui-panel-content-container' ); this.$generate_button = this.$el.find( '.vc_ai-generate-button' ); this.$close_button = this.$el.find( '[data-vc-ui-element="button-close"]' ); this.$insert_button = this.$el.find( '[data-vc-ui-element="button-save"]' ); this.$generated_content = this.$el.find( '.wpb_ai-generated-content' ); this.$prompt_field = this.$el.find( '[name="prompt"]' ); this.$generate_placeholder = this.$el.find( '.vc_ui-helper-modal-ai-placeholder' ); this.$generate_placeholder_timer = this.$generate_placeholder.find( '.vc_ai-timer' ); this.initialButtonText = this.$generate_button.text().trim(); this.contentType = this.$el.find( '[name="contentType"]' ).val(); if ( 'new_content' === this.contentType && !this.$prompt_field.val().trim() ) { this.disableButton(); } }, generateContent: function ( e ) { e.preventDefault(); var _this = this; // trim the prompt field value if user has set it programmatically var promptWords = this.$prompt_field.val().split( ' ' ); if ( this.maxPromptLength < promptWords.length ) { this.$prompt_field.val(promptWords.slice(0, this.maxPromptLength).join( ' ' )); } var init_data = this.$form.find(':visible:not([style*="display: none"]), [name="prompt"], input[type="hidden"]').serializeArray(); var cache_id = this.getUniqueCacheId(); init_data.push( {name: 'cacheId', value: cache_id} ); this.$generated_content.val(''); var data = { action: 'wpb_ai_api_get_response', data: init_data, _vcnonce: window.vcAdminNonce }; this.isGenerating = true; this.$generate_placeholder.removeClass( 'vc_ui-hidden' ); this.timerInterval = setInterval( this.updateTimer.bind( this ), 1000 ); // we break first request if you do not get response in 20 seconds. // if we do not get response in 20 seconds then we save response data in cache on the remote server // and then process another bunch of ajax requests to check if cache is ready $.ajax( { type: 'POST', url: window.ajaxurl, timeout: 20000, data: data } ).done( function ( response ) { if ( !_this.isGenerating ) { return false; } if ( true === response.success ) { _this.$generated_content.val( response.data ); _this.resetButton( true ); _this.$insert_button.show(); _this.tokenUsageUpdate(); _this.toggleCopyButton(); } else { // error returned by wpbakery server api if ( response && response.data && response.data[0] && response.data[0].code && response.data[0].message ) { console.error( response.data[0].code, response.data[0].message ); _this.resetButton( false ); var message = response.data[0].message.replace(/\\/g, ''); _this.showErrorMessage( message ); } else { console.error( _this.getLocale().ai_response_error ); _this.resetButton( false ); _this.showErrorMessage( _this.getLocale().ai_response_error ); } } } ).fail( function ( response ) { if ( !_this.isGenerating ) { return false; } if ( response && !response.statusText ) { console.error( _this.getLocale().ai_response_error ); _this.resetButton( false ); _this.showErrorMessage( _this.getLocale().ai_response_error ); return; } if ( 'timeout' !== response.statusText ) { console.error( _this.getLocale().ai_response_error ); _this.resetButton( false ); _this.showErrorMessage( _this.getLocale().ai_response_error ); return; } var data = { action: 'wpb_ai_generate_content_check_cache', data: { type: 'generate-text', messaged_data: true, cacheId: cache_id }, _vcnonce: window.vcAdminNonce }; // we create a timer to check if cache is ready every 10 seconds for 5 minutes var timeouts = []; for (var time_interval = 10000; time_interval <= _this.maxWaitingCacheInterval; time_interval += 10000) { createTimeout(time_interval); } function createTimeout(interval) { timeouts.push(setTimeout(function () { var output_value = _this.$generated_content.val(); if (output_value) { // stop all other timeouts related to cache checking for (var i = 0; i < timeouts.length; i++) { if ('stop_cache_timeouts' === output_value) { _this.$generated_content.val(''); } clearTimeout(timeouts[i]); } } else { _this.processCachedRequest(_this, data, interval); } }, interval)); } }); }, processCachedRequest: function ( _this, data, time_interval ) { // last timer is pass then it mean that we still do not have a content if ( this.maxWaitingCacheInterval === time_interval ) { console.error( _this.getLocale().ai_response_error ); _this.resetButton( false ); _this.showErrorMessage( _this.getLocale().ai_response_error ); } else { // any other timer then last we process request to check cache $.ajax( { type: 'POST', url: window.ajaxurl, timeout: 10000, data: data } ).done( function ( response ) { if ( !_this.isGenerating ) { return false; } if ( true === response.success && response.data && 'cache_in_process' !== response.data ) { _this.$generated_content.val( response.data ); _this.resetButton( true ); _this.$insert_button.show(); } // we have a cache response but first request that created cache was failed if ( false === response.success && response && response.data && response.data[0] && response.data[0].code && response.data[0].message ) { _this.$generated_content.val( 'stop_cache_timeouts' ); _this.resetButton( false ); var message = response.data[0].message.replace(/\\/g, ''); _this.showErrorMessage( message ); } } ); } }, tokenUsageUpdate: function () { var data = { action: 'wpb_ai_get_token_usage', data: {}, _vcnonce: window.vcAdminNonce }; var _this = this; $.ajax( { type: 'POST', url: window.ajaxurl, data: data } ).done( function ( response ) { var is_token_text = undefined !== response.data.tokens_left && undefined !== response.data.tokens_total; if ( true === response.success && is_token_text ) { var token_usage_text = _this.getLocale().ai_credit_usage + response.data.tokens_left + ' / ' + response.data.tokens_total; $('.vc-ai-tokens-usage').text(token_usage_text); } else { // error returned by wpbakery server api var is_error_message = response && response.data && response.data[0] && response.data[0].code && response.data[0].message; if ( is_error_message ) { console.error( response.data[0].message ); _this.showErrorMessage( response.data[0].message ); } else { console.error( _this.getLocale().ai_response_error ); _this.showErrorMessage( _this.getLocale().ai_response_error ); } } } ).fail( function ( response ) { console.error( _this.getLocale().ai_response_error ); _this.resetButton(); _this.showErrorMessage( _this.getLocale().ai_response_error ); }); }, getUniqueCacheId: function () { return Date.now().toString( 36 ) + Math.random().toString( 36 ).slice( 2 ); }, disableButton: function () { this.$generate_button.prop( 'disabled', function ( _, val ) { return !val; } ); this.isGenerateDisabled = true; }, resetButton: function ( isGenerated ) { var buttonText = isGenerated ? 'Regenerate' : this.initialButtonText; this.$generate_button.removeAttr( 'disabled style' ); this.$generate_button.text( buttonText ); this.$generate_button.blur(); this.clearTimer(); }, clearTimer: function () { this.$generate_placeholder.addClass( 'vc_ui-hidden' ); this.$generate_placeholder_timer.text( '00:00' ); clearInterval( this.timerInterval ); this.seconds = 0; this.minutes = 0; this.isGenerating = false; }, updateTimer: function () { this.seconds++; if ( 60 === this.seconds ) { this.seconds = 0; this.minutes++; } var formattedMinutes = String( this.minutes ).padStart( 2, '0' ); var formattedSeconds = String( this.seconds ).padStart( 2, '0' ); this.$generate_placeholder_timer.text( formattedMinutes + ':' + formattedSeconds ); }, changeContentType: function ( e ) { this.contentType = e.target.value; var elementData = this.$el.data(); // hide form fields that do not match selected content type var formFieldOptionalityList = $(e.target).find('option:selected').attr('data-form-fields-optionality'); formFieldOptionalityList = formFieldOptionalityList ? formFieldOptionalityList.split('|') : []; this.hideFormFields( formFieldOptionalityList ); // Set all form fields to default values except content type this.$form.trigger('reset'); this.$form.find( '[name="contentType"]' ).val(this.contentType); // set the value of the "prompt" textarea with existing field value if ( 'improve_existing' === e.target.value || 'translate' === e.target.value ) { this.$generate_button.text( this.getLocale().regenerate ); var existingContent = elementData.element.val(); if ( 'textarea_raw_html' === elementData.param_type ) { existingContent = rawurldecode( base64_decode( existingContent.trim() ) ); } else if ( 'textarea_html' === elementData.param_type ) { existingContent = window.tinymce.get( elementData.element.attr( 'id' ) ).getContent(); } this.$form.find('[name="prompt"]').val(existingContent); this.resetButton( true ); } else { this.$generate_button.text( this.getLocale().generate ); this.$form.find('[name="prompt"]').val(''); this.disableButton(); } }, changePrompt: function ( e ) { if ( this.isGenerateDisabled && e.target.value ) { this.resetButton( false ); this.isGenerateDisabled = false; } else if ( !e.target.value && !this.isGenerateDisabled ) { this.disableButton(); } // trim prompt value if it exceeds maxPromptLength var promptWords = e.target.value.split( ' ' ); if (promptWords.length > this.maxPromptLength) { e.target.value = promptWords.slice(0, this.maxPromptLength).join( ' ' ); } }, showErrorMessage: function ( message ) { window.vc.showMessage( message, 'error', 10000, '#vc_ui-helper-modal-ai .vc_ui-panel-window-inner' ); }, insertContent: function () { var generatedContent = this.$generated_content.val(); if ( !generatedContent ) { return false; } var currentParamData = this.$el.data(); var aiFields = [ 'textarea', 'textfield', 'textarea_raw_html' ]; var aceEditorFields = [ 'wpb_css_editor', 'wpb_js_header_editor', 'wpb_js_footer_editor' ]; if ( 'textarea_html' === currentParamData.param_type || 'content' === currentParamData.fieldId ) { var $textareaElement = currentParamData.element; var textareaId = $textareaElement.attr( 'id' ); if ( 'new_content' === this.contentType ) { var currentTextareaValue = $textareaElement.val(); generatedContent = currentTextareaValue + ' ' + generatedContent; } var tinyMCE = window.tinymce.get( textareaId ); if (tinyMCE) { tinyMCE.setContent( generatedContent ); } $textareaElement.val( generatedContent ).trigger('input').trigger('change').trigger('blur'); } else if ( aiFields.includes( currentParamData.param_type ) ) { var $inputElement = currentParamData.element; if ( 'new_content' === this.contentType ) { var currentInputValue = $inputElement.val(); generatedContent = currentInputValue + ' ' + generatedContent; } $inputElement.val( generatedContent ).trigger('input').trigger('change').trigger('blur'); } else if ( currentParamData.fieldId ) { if ( aceEditorFields.includes( currentParamData.fieldId ) ) { var aceEditor = window.ace.edit( currentParamData.fieldId ); var currentValue = aceEditor.getValue(); var $codeTextarea = $(aceEditor.container).find('textarea'); var emptySpace = ''; if(currentValue !== '') { emptySpace = '\n\n'; } generatedContent = currentValue + emptySpace + generatedContent; aceEditor.setValue( generatedContent ); $codeTextarea.trigger('input').trigger('change').trigger('blur'); } else if ( currentParamData.element && currentParamData.element.length ) { if ( 'new_content' === this.contentType ) { var currentElementValue = currentParamData.element.val(); generatedContent = currentElementValue + ' ' + generatedContent; } currentParamData.element.val(generatedContent).trigger('input').trigger('change').trigger('blur'); } } this.$close_button.click(); }, toggleModalPromoClass: function ( type ) { if ( 'promo' === type ) { this.$el.addClass( 'vc_modal-ai-container--promo' ); } else { this.$el.removeClass( 'vc_modal-ai-container--promo' ); } }, hideFormFields: function ( optionalityList ) { // hide form fields that do not match selected content type this.$form.find('div[data-optional-form-field]').each(function () { var $formField = $(this); var formFieldSlug = $formField.attr('data-optional-form-field'); if ( optionalityList.includes( formFieldSlug ) ) { $formField.show(); } else { $formField.hide(); } }); }, getLocale: function () { if ( window.i18nLocale ) { return window.i18nLocale; } else { return window.i18nLocaleSettings; } }, toggleCopyButton: function () { var $copyButton = this.$el.find( '.wpb-copy-output' ); if ( this.$generated_content.val() ) { $copyButton.removeClass('disabled'); } else { $copyButton.addClass('disabled'); } }, copyContent: function ( e ) { e.preventDefault(); var content = this.$generated_content.val(); if ( !content ) { return false; } try { window.vc.utils.copyTextToClipboard( content ); vc.showMessage( this.getLocale().copied, 'success', 2000, '#vc_ui-helper-modal-ai .vc_ui-panel-window-inner' ); } catch ( error ) { console.error( 'Unable to copy content:', error ); } } }); })( window.jQuery );