Changeset 3307540
- Timestamp:
- 06/06/2025 01:22:10 PM (9 months ago)
- Location:
- ai-app-onsite
- Files:
-
- 124 added
- 30 edited
-
tags/1.2.3 (added)
-
tags/1.2.3/ai-app-onsite.php (added)
-
tags/1.2.3/assets (added)
-
tags/1.2.3/assets/css (added)
-
tags/1.2.3/assets/css/ai-app-onsite-form-style.css (added)
-
tags/1.2.3/assets/css/ai-app-onsite-style.css (added)
-
tags/1.2.3/assets/css/bootstrap.min.css (added)
-
tags/1.2.3/assets/css/fontawesome.min.css (added)
-
tags/1.2.3/assets/css/index.php (added)
-
tags/1.2.3/assets/index.php (added)
-
tags/1.2.3/assets/js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-admin.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-app-preview.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-app-properties.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-blockword.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-email-settings.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-field-selector.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-form-block.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-model-settings.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-openai-api.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-plugin-settings.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-prompt-editor.js (added)
-
tags/1.2.3/assets/js/ai-app-onsite-reset-localstorage.js (added)
-
tags/1.2.3/assets/js/bootstrap.min.js (added)
-
tags/1.2.3/assets/js/choice.min.js (added)
-
tags/1.2.3/assets/js/index.php (added)
-
tags/1.2.3/assets/js/jspdf.umd.min.js (added)
-
tags/1.2.3/assets/js/popper.min.js (added)
-
tags/1.2.3/assets/js/sweetalert2.all.min.js (added)
-
tags/1.2.3/assets/media (added)
-
tags/1.2.3/assets/media/AlappOnsite-API-Key-logo.png (added)
-
tags/1.2.3/assets/media/add-color-icon.png (added)
-
tags/1.2.3/assets/media/api-key-icon.png (added)
-
tags/1.2.3/assets/media/app-logo.png (added)
-
tags/1.2.3/assets/media/app-logo1.png (added)
-
tags/1.2.3/assets/media/applogo.png (added)
-
tags/1.2.3/assets/media/banned-icon.png (added)
-
tags/1.2.3/assets/media/bg-color-icon.png (added)
-
tags/1.2.3/assets/media/calendar-icon.png (added)
-
tags/1.2.3/assets/media/chevron-blue.png (added)
-
tags/1.2.3/assets/media/chevron-grey.png (added)
-
tags/1.2.3/assets/media/clapperboard-blue.png (added)
-
tags/1.2.3/assets/media/clapperboard-grey.png (added)
-
tags/1.2.3/assets/media/code-browser-grey.png (added)
-
tags/1.2.3/assets/media/code-icon-placeholder.png (added)
-
tags/1.2.3/assets/media/copy-icon-success.png (added)
-
tags/1.2.3/assets/media/copy-icon.png (added)
-
tags/1.2.3/assets/media/delete-icon.png (added)
-
tags/1.2.3/assets/media/disc-blue.png (added)
-
tags/1.2.3/assets/media/disc-grey.png (added)
-
tags/1.2.3/assets/media/download-icon.png (added)
-
tags/1.2.3/assets/media/email-icon.png (added)
-
tags/1.2.3/assets/media/email.jpg (added)
-
tags/1.2.3/assets/media/engine-icon.png (added)
-
tags/1.2.3/assets/media/eye-grey.png (added)
-
tags/1.2.3/assets/media/file-icon.png (added)
-
tags/1.2.3/assets/media/folder-icon.png (added)
-
tags/1.2.3/assets/media/font-color-icon.png (added)
-
tags/1.2.3/assets/media/grab-icon.png (added)
-
tags/1.2.3/assets/media/index.php (added)
-
tags/1.2.3/assets/media/objective-icon.png (added)
-
tags/1.2.3/assets/media/pen-icon.png (added)
-
tags/1.2.3/assets/media/penalty-icon.png (added)
-
tags/1.2.3/assets/media/preview-icon-blue.png (added)
-
tags/1.2.3/assets/media/preview-icon-grey.png (added)
-
tags/1.2.3/assets/media/profile-img.png (added)
-
tags/1.2.3/assets/media/promt-icon-blue.png (added)
-
tags/1.2.3/assets/media/promt-icon-grey.png (added)
-
tags/1.2.3/assets/media/response-icon.png (added)
-
tags/1.2.3/assets/media/settings-blue.png (added)
-
tags/1.2.3/assets/media/settings-grey.png (added)
-
tags/1.2.3/assets/media/shortcode-icon.png (added)
-
tags/1.2.3/assets/media/temprature-icon.png (added)
-
tags/1.2.3/assets/media/text-color-icon.png (added)
-
tags/1.2.3/assets/media/token-icon.png (added)
-
tags/1.2.3/assets/media/upload-file-icon.png (added)
-
tags/1.2.3/assets/media/user-icon.png (added)
-
tags/1.2.3/assets/webfonts (added)
-
tags/1.2.3/assets/webfonts/fa-brands-400.ttf (added)
-
tags/1.2.3/assets/webfonts/fa-brands-400.woff2 (added)
-
tags/1.2.3/assets/webfonts/fa-regular-400.ttf (added)
-
tags/1.2.3/assets/webfonts/fa-regular-400.woff2 (added)
-
tags/1.2.3/assets/webfonts/fa-solid-900.ttf (added)
-
tags/1.2.3/assets/webfonts/fa-solid-900.woff2 (added)
-
tags/1.2.3/assets/webfonts/fa-v4compatibility.ttf (added)
-
tags/1.2.3/assets/webfonts/fa-v4compatibility.woff2 (added)
-
tags/1.2.3/assets/webfonts/index.php (added)
-
tags/1.2.3/handler (added)
-
tags/1.2.3/handler/ai-app-onsite-app-license.php (added)
-
tags/1.2.3/handler/ai-app-onsite-app-preview.php (added)
-
tags/1.2.3/handler/ai-app-onsite-app-properties.php (added)
-
tags/1.2.3/handler/ai-app-onsite-email-settings.php (added)
-
tags/1.2.3/handler/ai-app-onsite-field-selector.php (added)
-
tags/1.2.3/handler/ai-app-onsite-model-settings.php (added)
-
tags/1.2.3/handler/ai-app-onsite-openAi-api.php (added)
-
tags/1.2.3/handler/ai-app-onsite-plugin-settings.php (added)
-
tags/1.2.3/handler/ai-app-onsite-prompt-editor.php (added)
-
tags/1.2.3/handler/ai-app-onsite-user-stats.php (added)
-
tags/1.2.3/handler/index.php (added)
-
tags/1.2.3/includes (added)
-
tags/1.2.3/includes/class-ai-app-onsite-admin.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-app-preview.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-app-properties.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-db-handler.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-email-settings.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-field-selector.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-model-settings.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-plugin-settings.php (added)
-
tags/1.2.3/includes/class-ai-app-onsite-prompt-editor.php (added)
-
tags/1.2.3/includes/index.php (added)
-
tags/1.2.3/includes/svn.code-workspace (added)
-
tags/1.2.3/index.php (added)
-
tags/1.2.3/readme.md (added)
-
tags/1.2.3/readme.txt (added)
-
trunk/ai-app-onsite.php (modified) (16 diffs)
-
trunk/assets/css/ai-app-onsite-form-style.css (modified) (2 diffs)
-
trunk/assets/css/ai-app-onsite-style.css (modified) (6 diffs)
-
trunk/assets/css/index.php (added)
-
trunk/assets/index.php (added)
-
trunk/assets/js/ai-app-onsite-admin.js (modified) (13 diffs)
-
trunk/assets/js/ai-app-onsite-app-preview.js (modified) (14 diffs)
-
trunk/assets/js/ai-app-onsite-app-properties.js (modified) (7 diffs)
-
trunk/assets/js/ai-app-onsite-field-selector.js (modified) (14 diffs)
-
trunk/assets/js/ai-app-onsite-model-settings.js (modified) (13 diffs)
-
trunk/assets/js/ai-app-onsite-openai-api.js (modified) (4 diffs)
-
trunk/assets/js/ai-app-onsite-plugin-settings.js (modified) (2 diffs)
-
trunk/assets/js/ai-app-onsite-prompt-editor.js (modified) (8 diffs)
-
trunk/assets/js/ai-app-onsite-reset-localstorage.js (modified) (2 diffs)
-
trunk/assets/js/index.php (added)
-
trunk/assets/media/index.php (added)
-
trunk/assets/webfonts/index.php (added)
-
trunk/handler/ai-app-onsite-app-license.php (added)
-
trunk/handler/ai-app-onsite-app-preview.php (modified) (13 diffs)
-
trunk/handler/ai-app-onsite-app-properties.php (modified) (6 diffs)
-
trunk/handler/ai-app-onsite-field-selector.php (modified) (8 diffs)
-
trunk/handler/ai-app-onsite-model-settings.php (modified) (7 diffs)
-
trunk/handler/ai-app-onsite-openAi-api.php (modified) (3 diffs)
-
trunk/handler/ai-app-onsite-plugin-settings.php (modified) (10 diffs)
-
trunk/handler/ai-app-onsite-prompt-editor.php (modified) (6 diffs)
-
trunk/handler/ai-app-onsite-user-stats.php (modified) (1 diff)
-
trunk/handler/index.php (added)
-
trunk/includes/class-ai-app-onsite-admin.php (modified) (5 diffs)
-
trunk/includes/class-ai-app-onsite-app-preview.php (modified) (5 diffs)
-
trunk/includes/class-ai-app-onsite-app-properties.php (modified) (6 diffs)
-
trunk/includes/class-ai-app-onsite-db-handler.php (modified) (8 diffs)
-
trunk/includes/class-ai-app-onsite-field-selector.php (modified) (3 diffs)
-
trunk/includes/class-ai-app-onsite-model-settings.php (modified) (3 diffs)
-
trunk/includes/class-ai-app-onsite-plugin-settings.php (modified) (1 diff)
-
trunk/includes/class-ai-app-onsite-prompt-editor.php (modified) (2 diffs)
-
trunk/includes/index.php (added)
-
trunk/includes/svn.code-workspace (added)
-
trunk/index.php (added)
-
trunk/readme.md (modified) (2 diffs)
-
trunk/readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ai-app-onsite/trunk/ai-app-onsite.php
r3281194 r3307540 4 4 * Plugin Name: AI App Onsite 5 5 * Description: AIappOnsite - AI Web App Creator WP Plugin allows users to create their own AI-powered web app and launch it on their own site with no additional development needed. AI App Onsite web app creator is an AI web app builder for WordPress. 6 * Version: 1.2. 26 * Version: 1.2.3 7 7 * Author: By AIappOnsite 8 8 * Author URI: https://aiapponsite.com/ … … 12 12 */ 13 13 14 15 14 16 // Enqueue WordPress's jQuery 15 17 function ai_app_onsite_enqueue_scripts() … … 19 21 add_action('wp_enqueue_scripts', 'ai_app_onsite_enqueue_scripts'); 20 22 23 if (version_compare(PHP_VERSION, '7.0', '<')) { 24 add_action('admin_notices', function () { 25 echo '<div class="notice notice-error"><p><strong>AI App Onsite Plugin:</strong> This plugin requires PHP 7.0 or higher. Your server is running PHP ' . PHP_VERSION . '.</p></div>'; 26 }); 27 return; 28 } 29 30 add_filter('cron_schedules', function ($schedules) { 31 $schedules['validatelicense'] = [ 32 'interval' => 86400, 33 'display' => __('Once Everyday'), 34 ]; 35 $schedules['checkpluginversion'] = [ 36 'interval' => 43200, // 12 hours in seconds 37 'display' => __('Twice Daily'), 38 ]; 39 return $schedules; 40 }); 21 41 22 42 … … 26 46 } 27 47 28 // Define plugin constants 29 define('AI_APP_ONSITE_VERSION', '1.2.2'); 48 define('AI_APP_ONSITE_VERSION', '1.4.3'); 30 49 define('AI_APP_ONSITE_PLUGIN_DIR', plugin_dir_path(__FILE__)); 31 50 define('AI_APP_ONSITE_PLUGIN_URL', plugin_dir_url(__FILE__)); 32 51 52 53 if ( ! function_exists( 'ai_app_onsite_get_version_meta' ) ) { 54 function ai_app_onsite_get_version_meta() { 55 $response = wp_remote_get( 'https://aiapponsite.com/prod/ai-app-onsite-version.php?nocache=' . time()); 56 57 if ( is_wp_error( $response ) ) { 58 error_log( 'Version fetch failed: ' . $response->get_error_message() ); 59 return [ 60 'error' => 'Request failed', 61 'message' => $response->get_error_message(), 62 ]; 63 } 64 65 $body = wp_remote_retrieve_body( $response ); 66 $data = json_decode( $body, true ); 67 68 if ( ! is_array( $data ) ) { 69 error_log( 'Invalid JSON returned from version.php: ' . $body ); 70 return [ 71 'error' => 'Invalid response', 72 'message' => $body, 73 ]; 74 } 75 76 return $data; 77 } 78 } 79 80 81 function ai_app_onsite_is_premium_active() { 82 global $wpdb; 83 $table = $wpdb->prefix . 'ai_app_onsite_license_settings'; 84 85 // Check if 'key_disable_status' column exists 86 $column_exists = $wpdb->get_var( 87 $wpdb->prepare( 88 "SHOW COLUMNS FROM {$table} LIKE %s", 89 'key_disable_status' 90 ) 91 ); 92 93 $columns = 'key_status'; 94 if ( ! empty( $column_exists ) ) { 95 $columns .= ', key_disable_status'; 96 } 97 98 $row = $wpdb->get_row( 99 "SELECT {$columns} FROM {$table} LIMIT 1", 100 ARRAY_A 101 ); 102 103 if ( empty( $row ) ) { 104 return false; 105 } 106 107 if ( 108 isset( $row['key_disable_status'] ) && $row['key_disable_status'] === 'false' && 109 isset( $row['key_status'] ) && $row['key_status'] === 'ACTIVE' && 110 is_dir( AI_APP_ONSITE_PLUGIN_DIR . 'premium' ) 111 ) { 112 return true; 113 } 114 115 return false; 116 } 117 118 function ai_app_onsite_is_premium_disabled() { 119 global $wpdb; 120 $table = $wpdb->prefix . 'ai_app_onsite_license_settings'; 121 122 // Check if 'key_disable_status' column exists 123 $column_exists = $wpdb->get_var( 124 $wpdb->prepare( 125 "SHOW COLUMNS FROM {$table} LIKE %s", 126 'key_disable_status' 127 ) 128 ); 129 130 $columns = 'key_status'; 131 if ( ! empty( $column_exists ) ) { 132 $columns .= ', key_disable_status, license_key'; 133 } 134 135 $row = $wpdb->get_row( 136 "SELECT {$columns} FROM {$table} LIMIT 1", 137 ARRAY_A 138 ); 139 140 if ( empty( $row ) ) { 141 return false; 142 } 143 144 if ( 145 isset( $row['key_disable_status'] ) && $row['key_disable_status'] === 'true' && 146 isset( $row['key_status'] ) && $row['key_status'] === 'ACTIVE' && 147 ! empty( $row['license_key'] ) && 148 is_dir( AI_APP_ONSITE_PLUGIN_DIR . 'premium' ) 149 ) { 150 return true; 151 } 152 153 return false; 154 } 155 156 157 158 function ai_app_onsite_include_path(): string { 159 return plugin_dir_path(__FILE__) . (ai_app_onsite_is_premium_active() ? 'premium/includes/' : 'includes/'); 160 } 161 162 function ai_app_onsite_handler_path(): string { 163 return plugin_dir_path(__FILE__) . (ai_app_onsite_is_premium_active() ? 'premium/handler/' : 'handler/'); 164 } 165 166 function ai_app_onsite_assets_path(): string { 167 return plugin_dir_url(__FILE__) . (ai_app_onsite_is_premium_active() ? 'premium/assets/' : 'assets/'); 168 } 169 33 170 // Include necessary files 34 171 if (! function_exists('ai_app_onsite_init')) { 35 function ai_app_onsite_init() 36 { 37 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-admin.php'; 38 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-plugin-settings.php'; 39 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-app-properties.php'; 40 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-model-settings.php'; 41 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-field-selector.php'; 42 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-prompt-editor.php'; 43 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-app-preview.php'; 44 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-email-settings.php'; 45 46 47 48 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-plugin-settings.php'; 49 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-app-properties.php'; 50 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-model-settings.php'; 51 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-field-selector.php'; 52 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-prompt-editor.php'; 53 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-app-preview.php'; 54 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-openAi-api.php'; 55 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-user-stats.php'; 56 require_once AI_APP_ONSITE_PLUGIN_DIR . 'handler/ai-app-onsite-email-settings.php'; 172 function ai_app_onsite_init(): void { 173 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-admin.php'; 174 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-plugin-settings.php'; 175 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-app-properties.php'; 176 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-model-settings.php'; 177 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-field-selector.php'; 178 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-prompt-editor.php'; 179 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-app-preview.php'; 180 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-email-settings.php'; 181 182 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-plugin-settings.php'; 183 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-app-properties.php'; 184 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-model-settings.php'; 185 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-field-selector.php'; 186 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-prompt-editor.php'; 187 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-app-preview.php'; 188 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-app-license.php'; 189 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-openAi-api.php'; 190 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-user-stats.php'; 191 require_once ai_app_onsite_handler_path() . 'ai-app-onsite-email-settings.php'; 57 192 58 193 //$ai_app_onsite = new AI_App_Onsite(); … … 63 198 64 199 if (!function_exists('ai_app_onsite_enqueue_admin_script')) { 65 function ai_app_onsite_enqueue_admin_script($hook) 66 { 200 function ai_app_onsite_enqueue_admin_script($hook): void { 67 201 // Only load on plugin settings page - adjust this to match your plugin's actual settings page slug 68 202 if ($hook !== 'toplevel_page_ai-app-onsite-menu') { … … 71 205 72 206 // Enqueue CSS for admin 73 wp_enqueue_style('ai-app-onsite-style', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/ai-app-onsite-style.css', array(), time());74 wp_enqueue_style('ai-app-onsite-fafa-style', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/fontawesome.min.css', array(), time());207 wp_enqueue_style('ai-app-onsite-style', ai_app_onsite_assets_path() . 'css/ai-app-onsite-style.css', array(), time()); 208 wp_enqueue_style('ai-app-onsite-fafa-style', ai_app_onsite_assets_path() . 'css/fontawesome.min.css', array(), time()); 75 209 76 210 // Check if Bootstrap is already loaded … … 96 230 // Enqueue Bootstrap if not already loaded 97 231 if (!$is_bootstrap_loaded) { 98 wp_register_script('bootstrape-poper-script', AI_APP_ONSITE_PLUGIN_URL . 'assets/js/popper.min.js', array('jquery'), time(), true);232 wp_register_script('bootstrape-poper-script', ai_app_onsite_assets_path() . 'js/popper.min.js', array('jquery'), time(), true); 99 233 wp_enqueue_script('bootstrape-poper-script'); 100 234 101 wp_register_script('bootstrape-script-script', AI_APP_ONSITE_PLUGIN_URL . 'assets/js/bootstrap.min.js', array('jquery'), time(), true);235 wp_register_script('bootstrape-script-script', ai_app_onsite_assets_path() . 'js/bootstrap.min.js', array('jquery'), time(), true); 102 236 wp_enqueue_script('bootstrape-script-script'); 103 237 104 wp_register_style('ai_app_onsite_style_bootstrap', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/bootstrap.min.css', array(), time());238 wp_register_style('ai_app_onsite_style_bootstrap', ai_app_onsite_assets_path() . 'css/bootstrap.min.css', array(), time()); 105 239 wp_enqueue_style('ai_app_onsite_style_bootstrap'); 106 240 } … … 123 257 124 258 foreach ($scripts as $handle => $filename) { 125 wp_register_script($handle, AI_APP_ONSITE_PLUGIN_URL . 'assets/js/' . $filename, array('jquery'), time(), true);259 wp_register_script($handle, ai_app_onsite_assets_path() . 'js/' . $filename, array('jquery'), time(), true); 126 260 wp_enqueue_script($handle); 127 261 } 128 262 129 // Pass the fresh installation flag to JavaScript 130 $is_fresh_install = get_option('ai_app_onsite_fresh_install', false); 263 264 265 // Pass the fresh installation flag to JavaScript 266 $is_fresh_install = get_option('ai_app_onsite_fresh_install', false); 267 131 268 // Localize the main admin script 132 269 wp_localize_script( … … 162 299 { 163 300 // Enqueue your script with time() for cache-busting 164 wp_enqueue_script('ai-app-onsite-openai-api-script', AI_APP_ONSITE_PLUGIN_URL . 'assets/js/ai-app-onsite-openai-api.js', array('jquery'), time(), true);301 wp_enqueue_script('ai-app-onsite-openai-api-script', ai_app_onsite_assets_path() . 'js/ai-app-onsite-openai-api.js', array('jquery'), time(), true); 165 302 166 303 // Localize the script with the AJAX URL … … 192 329 // Enqueue styles with time() for cache-busting 193 330 // Register and enqueue stylesheets for the admin area 194 wp_register_style('ai_app_onsite_form_style', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/ai-app-onsite-form-style.css', array(), time());331 wp_register_style('ai_app_onsite_form_style', ai_app_onsite_assets_path() . 'css/ai-app-onsite-form-style.css', array(), time()); 195 332 wp_enqueue_style('ai_app_onsite_form_style'); 196 333 197 wp_register_style('ai-app-onsite-fafa-style', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/fontawesome.min.css', array(), time());334 wp_register_style('ai-app-onsite-fafa-style', ai_app_onsite_assets_path() . 'css/fontawesome.min.css', array(), time()); 198 335 wp_enqueue_style('ai-app-onsite-fafa-style'); 199 336 // Check if Bootstrap is already loaded … … 219 356 // Enqueue Bootstrap if not already loaded 220 357 if (!$is_bootstrap_loaded) { 221 wp_register_style('ai_app_onsite_style_bootstrap', AI_APP_ONSITE_PLUGIN_URL . 'assets/css/bootstrap.min.css', array(), time());358 wp_register_style('ai_app_onsite_style_bootstrap', ai_app_onsite_assets_path() . 'css/bootstrap.min.css', array(), time()); 222 359 wp_enqueue_style('ai_app_onsite_style_bootstrap'); 223 360 } … … 241 378 242 379 add_option('ai_app_onsite_fresh_install', true); 380 381 /** 382 * To initializes and stores encryption keys and license-server URL to avoid hard-coding in WordPress options. 383 * 384 * - The `ai_app_onsite_encryption_key` is a 256-bit encryption key generated using `random_bytes`. 385 * - The `ai_app_onsite_encryption_iv` is a 16-byte initialization vector (IV) encoded in Base64. 386 * - The `ai_app_onsite_api_key` is a Base64-encoded license server URL string. 387 * 388 * These keys are securely generated and stored using WordPress's `update_option` function. 389 * 390 * Note: This is not obfuscated code. The Base64 encoding of the API key is used for safe storage 391 * and transmission, and it is not intended to hide or obscure the key. This approach ensures 392 * compatibility with systems that may require Base64-encoded strings. 393 */ 394 if (!get_option('ai_app_onsite_encryption_key')) { 395 update_option('ai_app_onsite_encryption_key', bin2hex(random_bytes(32))); // 256-bit key 396 } 397 if (!get_option('ai_app_onsite_encryption_iv')) { 398 update_option('ai_app_onsite_encryption_iv', base64_encode(random_bytes(16))); 399 } 400 if (!get_option('ai_app_onsite_api_key')) { 401 update_option('ai_app_onsite_api_key', 'aHR0cHM6Ly9iZHl6OHJvM3BjLmV4ZWN1dGUtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tL1BST0QvdmFsaWRhdGVLZXk='); 402 } 243 403 244 404 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-db-handler.php'; … … 273 433 } 274 434 275 wp_enqueue_script('plugin-deactivation-intercept', plugins_url('assets/js/ai-app-onsite-reset-localstorage.js', __FILE__), array('jquery'), '1.0', true);435 wp_enqueue_script('plugin-deactivation-intercept', ai_app_onsite_assets_path() . 'js/ai-app-onsite-reset-localstorage.js', array('jquery'), '1.0', true); 276 436 }); 277 278 279 280 437 281 438 … … 285 442 global $wpdb; 286 443 287 require_once AI_APP_ONSITE_PLUGIN_DIR . 'includes/class-ai-app-onsite-db-handler.php';444 require_once ai_app_onsite_include_path() . 'class-ai-app-onsite-db-handler.php'; 288 445 289 446 // Create an instance of the database handler class and pass $wpdb … … 292 449 // Call the method to drop the table 293 450 $result = $db_handler->ai_app_onsite_drop_table(); 451 452 delete_option('ai_app_onsite_encryption_key'); 453 delete_option('ai_app_onsite_encryption_iv'); 454 delete_option('ai_app_onsite_api_key'); 294 455 295 456 // Log the result … … 315 476 316 477 317 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'ai_app_onsite_settings_link'); 318 319 function ai_app_onsite_settings_link($links) 478 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'ai_app_onsite_settings_and_upgrade_links'); 479 function ai_app_onsite_settings_and_upgrade_links($links) 320 480 { 321 481 $settings_link = '<a href="' . admin_url('admin.php?page=ai-app-onsite-menu') . '">Settings</a>'; 322 array_unshift($links, $settings_link); // Add it at the beginning 482 $upgrade_link = '<a href="https://aiapponsite.com/pricing" class="open-new-tab" target="_blank" style="color:#d35400;font-weight:600; text-decoration:none; outline:none; box-shadow:none;">UPGRADE → <span style="background:#d35400;color:#fff;padding:2px 6px;border-radius:8px;font-size:10px;vertical-align:middle;">PLUS</span></a>'; 483 484 485 array_unshift($links, $settings_link); 486 array_push($links, $upgrade_link); 487 323 488 return $links; 324 489 } 490 491 add_action('admin_init', function () { 492 $last_checked = (int) get_option('ai_app_license_last_checked'); 493 $now = time(); 494 if (!$last_checked || ($now - $last_checked) > 3600) { 495 (new AI_APP_ONSITE_App_License_Handler())->ai_app_onsite_app_check_license_cron_callback(); 496 update_option('ai_app_license_last_checked', $now); 497 } 498 }); 499 500 if (!function_exists('ai_app_onsite_get_app_selector')) { 501 function ai_app_onsite_get_app_selector($app_id = 1) { 502 global $wpdb; 503 504 $plugin_settings_table = $wpdb->prefix . 'ai_app_onsite_plugin_settings'; 505 $app_properties_table = $wpdb->prefix . 'ai_app_onsite_app_properties'; 506 507 // Get the current app_selector value 508 $app_selector = $wpdb->get_var( 509 $wpdb->prepare( 510 "SELECT app_selector FROM $plugin_settings_table WHERE app_id = %d", 511 $app_id 512 ) 513 ); 514 515 // Check if app_selector matches app_name in the app_properties table 516 if ($app_selector) { 517 $app_id_from_properties = $wpdb->get_var( 518 $wpdb->prepare( 519 "SELECT id FROM $app_properties_table WHERE app_name = %s OR app_name_show = %s", 520 $app_selector, 521 $app_selector 522 ) 523 ); 524 525 // If a match is found, update app_selector to the id 526 if ($app_id_from_properties) { 527 $wpdb->update( 528 $plugin_settings_table, 529 ['app_selector' => $app_id_from_properties], 530 ['app_id' => $app_id], 531 ['%d'], 532 ['%d'] 533 ); 534 535 $app_selector = $app_id_from_properties; 536 } 537 } 538 539 return $app_selector ?: null; 540 } 541 } -
ai-app-onsite/trunk/assets/css/ai-app-onsite-form-style.css
r3281194 r3307540 201 201 .ai-app-form-wrap #ai-app-motivational-heading h6 { 202 202 font-weight: 700; 203 color: #000; 203 204 } 204 205 … … 208 209 background-color: #f7f7f7; 209 210 padding: 10px; 211 color: #000; 210 212 box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; 211 213 margin-bottom: 25px; -
ai-app-onsite/trunk/assets/css/ai-app-onsite-style.css
r3281194 r3307540 280 280 } 281 281 282 .form-wrapper-license { 283 width: 100%; 284 margin: auto; 285 } 286 282 287 .form-wrapper select, 283 288 input#banned_words { … … 319 324 .fs-regular-12 { 320 325 font-size: 12px; 326 font-weight: 400; 327 line-height: 16px; 328 } 329 330 .fs-regular-10 { 331 font-size: 10px; 321 332 font-weight: 400; 322 333 line-height: 16px; … … 1352 1363 } 1353 1364 1365 .remove-btn:disabled { 1366 border:none; 1367 } 1368 1354 1369 .remove-btn .btn-icon { 1355 1370 margin-right: 2px; … … 1609 1624 background-size: inherit; 1610 1625 background-position: center; 1626 cursor: pointer; 1611 1627 } 1612 1628 … … 1995 2011 background-size: inherit; 1996 2012 background-position: center; 2013 cursor: pointer; 1997 2014 } 1998 2015 … … 2082 2099 background: transparent; 2083 2100 } 2101 .ai-app-onsite-wrap .gold-gradient { 2102 font-size: 14px; 2103 font-weight: bold; 2104 background: linear-gradient(90deg, #FFD700, #FFA500, #FF8C00, #FFD700); 2105 -webkit-background-clip: text; 2106 -webkit-text-fill-color: transparent; 2107 background-clip: text; 2108 color: transparent; 2109 } 2110 .ai-app-onsite-wrap .gold-gradient::after { 2111 background: none; 2112 content: attr(data-heading) / ""; 2113 left: 0; 2114 top: 0; 2115 z-index: -1; 2116 position: absolute; 2117 text-shadow: 2118 -1px 0 1px #c6bb9f, 2119 0 1px 1px #c6bb9f, 2120 5px 5px 10px rgba(0, 0, 0, 0.4), 2121 -5px -5px 10px rgba(0, 0, 0, 0.4); 2122 } 2123 .ai-app-onsite-wrap .app-name { 2124 background-color: #efefef; 2125 pointer-events: none; 2126 } 2127 -
ai-app-onsite/trunk/assets/js/ai-app-onsite-admin.js
r3281194 r3307540 4 4 5 5 // === Save & Restore Tab using Cookie === 6 7 6 document.addEventListener('DOMContentLoaded', function () { 8 7 function getCookie(name) { … … 21 20 22 21 const isFreshInstall = myPluginAjax.isFreshInstall == '1' ? true : false; 23 console.log('isFreshInstall:', isFreshInstall);24 22 25 23 if (isFreshInstall) { … … 31 29 handleTabClick(fallbackTabId); // Activate the default tab 32 30 } 31 32 document.querySelectorAll('a.open-new-tab').forEach(function (link) { 33 link.setAttribute('target', '_blank'); 34 link.setAttribute('rel', 'noopener noreferrer'); 35 }); 36 37 const observer = new MutationObserver(function (mutationsList) { 38 mutationsList.forEach(function (mutation) { 39 mutation.addedNodes.forEach(function (node) { 40 if (node.nodeType === 1) { 41 if (node.matches('a.open-new-tab')) { 42 node.setAttribute('target', '_blank'); 43 node.setAttribute('rel', 'noopener noreferrer'); 44 } else { 45 // Also check any child links inside 46 node.querySelectorAll('a.open-new-tab').forEach(function (link) { 47 link.setAttribute('target', '_blank'); 48 link.setAttribute('rel', 'noopener noreferrer'); 49 }); 50 } 51 } 52 }); 53 }); 54 }); 55 56 observer.observe(document.body, { childList: true, subtree: true }); 33 57 }); 34 58 … … 36 60 37 61 function handleTabClick(tabId) { 38 event.preventDefault();62 // event.preventDefault(); 39 63 40 64 var tab = document.getElementById(tabId); … … 124 148 return; 125 149 } 126 console.log("image deleted");127 150 } else { 128 151 // Handle error response … … 163 186 164 187 function uploadSiteLogo(file) { 165 removeLogoBtn.style.display = 'block';166 188 fileUploadDiv.classList.add('col-md-8'); 167 189 fileUploadDiv.classList.remove('col-md-12'); … … 179 201 if (xhr.readyState === 4) { // Ensure the request is complete 180 202 if (xhr.status === 200) { 181 console.log('Response Text:', xhr.responseText); // Log the raw response text182 183 203 if (xhr.responseText) { // Check if the response text is not empty 184 204 try { … … 187 207 if (app_logo) { 188 208 var previewImage = document.getElementById('previewImage'); 189 previewImage.style.backgroundImage = `url('${app_logo}')`;190 previewImage.style.backgroundSize = 'contain'; // Optional: Adjust background size191 previewImage.style.backgroundRepeat = 'no-repeat'; // Optional: Prevent repetition209 previewImage.style.backgroundImage = `url('${app_logo}')`; 210 previewImage.style.backgroundSize = 'contain'; // Optional: Adjust background size 211 previewImage.style.backgroundRepeat = 'no-repeat'; // Optional: Prevent repetition 192 212 previewImage.style.backgroundPosition = 'center'; // Optional: Center the image 193 previewImage.style.display = 'block'; 194 previewImage.style.width = '350px'; 195 previewImage.style.height = '160px'; 196 previewImage.style.position = 'relative'; 213 previewImage.style.display = 'block'; 214 previewImage.style.width = '350px'; 215 previewImage.style.height = '160px'; 216 previewImage.style.position = 'relative'; 217 removeLogoBtn.style.display = 'block'; 197 218 } 198 219 … … 202 223 var messageContainer = document.getElementById('app-properties-msg-container'); 203 224 if (messageContainer) { 204 var successMessage = 'App Logo Upload Successful';225 var successMessage = 'App Image Uploaded Successful'; 205 226 if (response.success) { 206 227 messageContainer.innerHTML = '<span style="color: green;">' + successMessage + '</span>'; … … 208 229 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 209 230 } 210 console.log(response.data, 'parseInt');211 231 212 232 var previewImage = document.getElementById('previewImage'); 213 previewImage.src = response.data; 214 previewImage.style.display = 'block'; 233 previewImage.src = response.data; 234 previewImage.style.display = 'block'; 235 removeLogoBtn.style.display = 'block'; 215 236 } else { 216 237 console.error('messageContainer element not found'); … … 313 334 // var existingLabel = document.querySelector('.input-group-color .' + e.name); 314 335 315 // console.log('existingLabel', existingLabel);316 317 336 // existingLabel.remove(); 318 337 … … 367 386 var existingLabel = document.querySelector('.input-group-color .' + e.name); 368 387 369 console.log('existingLabel', existingLabel);370 388 371 389 existingLabel.remove(); … … 415 433 var existingLabel = document.querySelector('.input-group-color .' + e.name); 416 434 417 console.log('existingLabel', existingLabel);418 435 419 436 existingLabel.remove(); -
ai-app-onsite/trunk/assets/js/ai-app-onsite-app-preview.js
r3281194 r3307540 8 8 var gutenbergBlock = document.getElementById('openAi-app-gutenberg-block'); 9 9 10 function ai_app_onsite_create_app_preview_form(is_preview_button = false) { 11 var loader = document.getElementById('loader'); 12 13 const appCorner = document.getElementById('app-corner').value; 14 const appHeight = document.getElementById('app-height').value; 15 16 var xhr = new XMLHttpRequest(); 17 18 xhr.onreadystatechange = function () { 19 if (xhr.readyState === 4) { 20 if(is_preview_button){ 21 loader.style.display = 'none'; 22 } 23 24 if (xhr.status === 200) { 25 response = JSON.parse(xhr.responseText); 26 27 if (response.status === '404' || response.status === '400') { 28 formContainer.innerHTML = '<p>' + response.message + '</p>'; 29 openAiAppShortcode.value = ''; 30 testAppContainer.style.display = 'none'; 31 previewActionContainer.style.display = 'none'; 32 shortcodeBox.style.display = 'none'; 33 systemSettingsContainer.style.display = 'none'; 34 return; 35 } else { 36 formContainer.innerHTML = ''; 37 testAppContainer.style.display = 'block'; 38 previewActionContainer.style.display = 'block'; 39 shortcodeBox.style.display = 'flex'; 40 systemSettingsContainer.style.display = 'block'; 41 } 42 // Replace form content 43 formContainer.innerHTML = response?.form_html; 44 45 // Set the data recevied from db 46 ai_app_onsite_set_app_preview_properties_data(response?.appropriates, is_preview_button); 47 48 var parser = new DOMParser(); 49 var doc = parser.parseFromString(response?.form_html, 'text/html'); 50 51 // Find the element with the class 52 var element = doc.querySelector('.ai-app-preview-form-heading'); 53 54 var shortCodeGenerated = doc.querySelector('input[name="short_code_generated"]').value; 55 56 57 // Get the text content of the element 58 var value = element ? element.textContent : null; 59 var gutenberg_block = value; 60 if (gutenberg_block) { 61 gutenberg_block = value; 62 } else { 63 gutenberg_block = 'AI App Onsite'; 64 } 65 66 if (value) { 67 value = value.split(' ').map(function (word) { 68 return word.charAt(0).toLowerCase() + word.slice(1).toLowerCase(); 69 }).join('_'); 70 } else { 71 value = 'aiapp'; 72 } 73 74 openAiAppShortcode.value = `[${shortCodeGenerated}]`; 75 76 const parts = shortCodeGenerated.split("_aiao"); 77 78 gutenbergBlock.value = parts[0] + ' Aiao'; 79 localStorage.setItem('app_Title', parts[0]); 80 localStorage.setItem('app_Title_gutenberg_block', parts[0]); 81 82 testAppContainer.style.display = 'block'; 83 previewActionContainer.style.display = 'block'; 84 shortcodeBox.style.display = 'flex'; 85 systemSettingsContainer.style.display = 'block'; 86 if (formContainer) { 87 // Find the submit button inside the form 88 var submitButton = formContainer.querySelector('button[type="button"]'); 89 if (submitButton) { 90 // Disable the submit button 91 submitButton.disabled = true; 92 } 93 } 94 var messageContainer = document.getElementById('app-properties-msg-container-preview'); 95 if(is_preview_button){ 96 messageContainer.innerHTML = '<span style="color: green;">App Preview has been updated successfully.</span>'; 97 } 98 setTimeout(function () { 99 messageContainer.innerHTML = ''; 100 const appPreviewSettingsFormTracker = trackFormChanges('#app_preview_settings_form'); 101 window.FormChangeRegistry.register('app_preview_settings', appPreviewSettingsFormTracker, 'app-preview'); 102 103 document.getElementById('save_ai_app_app_properties_data').addEventListener('click', function () { 104 appPreviewSettingsFormTracker.reset(); 105 }); 106 }, 1000); 107 } 108 } 109 }; 110 111 xhr.open('POST', myPluginAjax.ajaxurl, true); 112 if(is_preview_button){ 113 loader.style.display = 'flex'; 114 } 115 116 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 117 const postData = new URLSearchParams(); 118 119 var titleColorRadios = document.querySelectorAll('input[type="radio"][name="title-color"]'); 120 var titleColors = []; 121 122 if (titleColorRadios) { 123 titleColorRadios.forEach(function (titleColorRadio) { 124 if (titleColorRadio.checked) { 125 titleColors.push({ "title_color_selected": titleColorRadio.value }); 126 } else { 127 titleColors.push({ "title_color": titleColorRadio.value }); 128 } 129 }); 130 } 131 132 postData.append('title_color', JSON.stringify(titleColors)); 133 134 135 var fontColorRadios = document.querySelectorAll('input[type="radio"][name="font-color"]'); 136 var fontColor = []; 137 138 if (fontColorRadios) { 139 fontColorRadios.forEach(function (fontColorRadio) { 140 if (fontColorRadio.checked) { 141 fontColor.push({ "font_color_selected": fontColorRadio.value }); 142 } else { 143 fontColor.push({ "font_color": fontColorRadio.value }); 144 } 145 }); 146 } 147 148 postData.append('font_color', JSON.stringify(fontColor)); 149 150 var bgColorRadios = document.querySelectorAll('input[type="radio"][name="bg-color"]'); 151 var bgColor = []; 152 153 if (bgColorRadios) { 154 bgColorRadios.forEach(function (bgColorRadio) { 155 if (bgColorRadio.checked) { 156 bgColor.push({ "bg_color_selected": bgColorRadio.value }); 157 } else { 158 bgColor.push({ "bg_color": bgColorRadio.value }); 159 } 160 }); 161 } 162 163 postData.append('background_color', JSON.stringify(bgColor)); 164 postData.append('action', 'ai_app_onsite_create_app_preview_form'); 165 postData.append('app_corner', appCorner); 166 postData.append('app_height', appHeight); 167 postData.append('is_preview_button', is_preview_button) 168 169 xhr.send(postData.toString()); 170 } 171 10 172 function ai_app_onsite_set_app_preview_properties_data(response, is_preview) { 11 173 if (!Array.isArray(response) || response.length === 0) { … … 28 190 29 191 radioInputs.forEach(function (radio) { 192 30 193 var label = radio.closest('label'); 31 194 var colorWithoutHash = radio.value.replace(/^#/, ''); … … 53 216 } 54 217 }); 55 }, 100);218 }, 100); 56 219 57 220 // Define an array of objects containing the variables and their corresponding radio button sets … … 93 256 if (radioButton) { 94 257 radioButton.checked = true; 258 radioButton.setAttribute('checked', 'checked'); 95 259 } 96 260 }); … … 104 268 if (radioButton) { 105 269 radioButton.checked = true; 270 radioButton.setAttribute('checked', 'checked'); 106 271 } else { // If no matching radio button is found, set the variable as the value of an input field 107 272 var element = document.getElementById(variableSet.id); … … 156 321 if (radioButton) { 157 322 radioButton.checked = true; 323 radioButton.setAttribute('checked', 'checked'); 158 324 } 159 325 }); … … 167 333 if (radioButton) { 168 334 radioButton.checked = true; 335 radioButton.setAttribute('checked', 'checked'); 169 336 } else { // If no matching radio button is found, set the variable as the value of an input field 170 337 var element = document.getElementById(variableSet.id); … … 217 384 if (radioButton) { 218 385 radioButton.checked = true; 386 radioButton.setAttribute('checked', 'checked'); 219 387 } 220 388 }); … … 228 396 if (radioButton) { 229 397 radioButton.checked = true; 398 radioButton.setAttribute('checked', 'checked'); 230 399 } else { // If no matching radio button is found, set the variable as the value of an input field 231 400 var element = document.getElementById(variableSet.id); … … 244 413 document.getElementById("app-corner").value = app_corner || "soft-corner"; 245 414 document.getElementById("app-height").value = app_height || "slight-lift"; 415 416 document.getElementById('app-corner').setAttribute('name', 'app_corner'); 417 document.getElementById('app-height').setAttribute('name', 'app_height'); 418 419 246 420 } 247 421 function getSelectedTitleColor(data) { … … 268 442 } 269 443 return null; 270 }271 272 function ai_app_onsite_create_app_preview_form(is_preview_button = false) {273 var loader = document.getElementById('loader');274 275 // const getCheckedValue = (name) => {276 // const inputs = document.querySelectorAll(`input[name="${name}"]:checked`);277 // return inputs.length ? inputs[0].value : '';278 // };279 280 // const titleColor = getCheckedValue('title-color');281 // const fontColor = getCheckedValue('font-color');282 // const backgroundColor = getCheckedValue('bg-color');283 const appCorner = document.getElementById('app-corner').value;284 const appHeight = document.getElementById('app-height').value;285 286 var xhr = new XMLHttpRequest();287 288 xhr.onreadystatechange = function () {289 if (xhr.readyState === 4) {290 if(is_preview_button){291 loader.style.display = 'none';292 }293 294 if (xhr.status === 200) {295 296 //console.log('xhr.responseText', xhr.responseText);297 298 response = JSON.parse(xhr.responseText);299 300 if (response.status === '404' || response.status === '400') {301 formContainer.innerHTML = '<p>No form Field Found Please Create Form Field</p>';302 openAiAppShortcode.value = '';303 testAppContainer.style.display = 'none';304 previewActionContainer.style.display = 'none';305 shortcodeBox.style.display = 'none';306 systemSettingsContainer.style.display = 'none';307 return;308 }309 // Replace form content310 formContainer.innerHTML = response?.form_html;311 312 // Set the data recevied from db313 ai_app_onsite_set_app_preview_properties_data(response?.appropriates, is_preview_button);314 315 var parser = new DOMParser();316 var doc = parser.parseFromString(response?.form_html, 'text/html');317 318 // Find the element with the class319 var element = doc.querySelector('.ai-app-preview-form-heading');320 321 var shortCodeGenerated = doc.querySelector('input[name="short_code_generated"]').value;322 323 324 // Get the text content of the element325 var value = element ? element.textContent : null;326 var gutenberg_block = value;327 if (gutenberg_block) {328 gutenberg_block = value;329 } else {330 gutenberg_block = 'AI App Onsite';331 }332 333 334 if (value) {335 value = value.split(' ').map(function (word) {336 return word.charAt(0).toLowerCase() + word.slice(1).toLowerCase();337 }).join('_');338 } else {339 value = 'aiapp';340 }341 342 openAiAppShortcode.value = `[${shortCodeGenerated}]`;343 344 const parts = shortCodeGenerated.split("_aiao");345 346 gutenbergBlock.value = parts[0] + ' Aiao';347 localStorage.setItem('app_Title', parts[0]);348 localStorage.setItem('app_Title_gutenberg_block', parts[0]);349 350 testAppContainer.style.display = 'block';351 previewActionContainer.style.display = 'block';352 shortcodeBox.style.display = 'flex';353 systemSettingsContainer.style.display = 'block';354 if (formContainer) {355 // Find the submit button inside the form356 var submitButton = formContainer.querySelector('button[type="button"]');357 if (submitButton) {358 // Disable the submit button359 submitButton.disabled = true;360 }361 }362 var messageContainer = document.getElementById('app-properties-msg-container-preview');363 if(is_preview_button){364 messageContainer.innerHTML = '<span style="color: green;">App Preview has been updated successfully.</span>';365 }366 setTimeout(function () {367 messageContainer.innerHTML = '';368 }, 1000);369 } else {370 // Handle error response371 console.error('Error occurred: ' + xhr.responseText);372 373 formContainer.innerHTML = '<p>It looks like some required settings are missing. Please ensure that "App Properties," "Model Settings," and "Form Fields" are configured before previewing the form.</p>';374 openAiAppShortcode.value = '';375 testAppContainer.style.display = 'none';376 previewActionContainer.style.display = 'none';377 shortcodeBox.style.display = 'none';378 systemSettingsContainer.style.display = 'none';379 return;380 }381 }382 };383 384 xhr.open('POST', myPluginAjax.ajaxurl, true);385 if(is_preview_button){386 loader.style.display = 'flex';387 }388 389 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');390 const postData = new URLSearchParams();391 392 var titleColorRadios = document.querySelectorAll('input[type="radio"][name="title-color"]');393 var titleColors = [];394 395 if (titleColorRadios) {396 titleColorRadios.forEach(function (titleColorRadio) {397 if (titleColorRadio.checked) {398 titleColors.push({ "title_color_selected": titleColorRadio.value });399 } else {400 titleColors.push({ "title_color": titleColorRadio.value });401 }402 });403 }404 405 postData.append('title_color', JSON.stringify(titleColors));406 407 408 var fontColorRadios = document.querySelectorAll('input[type="radio"][name="font-color"]');409 var fontColor = [];410 411 if (fontColorRadios) {412 fontColorRadios.forEach(function (fontColorRadio) {413 if (fontColorRadio.checked) {414 fontColor.push({ "font_color_selected": fontColorRadio.value });415 } else {416 fontColor.push({ "font_color": fontColorRadio.value });417 }418 });419 }420 421 postData.append('font_color', JSON.stringify(fontColor));422 423 var bgColorRadios = document.querySelectorAll('input[type="radio"][name="bg-color"]');424 var bgColor = [];425 bgColor426 if (bgColorRadios) {427 bgColorRadios.forEach(function (bgColorRadio) {428 if (bgColorRadio.checked) {429 bgColor.push({ "bg_color_selected": bgColorRadio.value });430 } else {431 bgColor.push({ "bg_color": bgColorRadio.value });432 }433 });434 }435 436 postData.append('background_color', JSON.stringify(bgColor));437 438 postData.append('action', 'ai_app_onsite_create_app_preview_form');439 // postData.append('title_color', titleColor);440 // postData.append('font_color', fontColor);441 // postData.append('background_color', backgroundColor);442 postData.append('app_corner', appCorner);443 postData.append('app_height', appHeight);444 postData.append('is_preview_button', is_preview_button)445 446 xhr.send(postData.toString());447 444 } 448 445 … … 671 668 // If any required field is empty, show an alert and prevent form submission 672 669 if (!isValid) { 673 console.log('Please fill in all required fields.');674 670 return false; // Form is invalid 675 671 } … … 730 726 731 727 }); 732 733 734 //Info:working code735 // jQuery('body').on('click', '.copy-span', function () {736 // alert("waiting");737 // // Select all span elements with the class 'copy-span'738 // const copySpans = document.querySelectorAll('.copy-span');739 740 // // Add event listener to each span741 // copySpans.forEach(function (span) {742 // span.addEventListener('click', function () {743 // // Create a temporary input element to copy the text744 // const textToCopy = span.textContent;745 746 // // Create a temporary input element747 // const tempInput = document.createElement('input');748 // document.body.appendChild(tempInput);749 750 // // Set the value of the input to the text of the span751 // tempInput.value = textToCopy;752 753 // // Select the content in the input754 // tempInput.select();755 // tempInput.setSelectionRange(0, 99999); // For mobile devices756 757 // // Copy the content to clipboard758 // try {759 // document.execCommand('copy');760 // alert('Copied: ' + textToCopy); // Optional: show a confirmation alert761 // } catch (err) {762 // console.error('Unable to copy text', err);763 // }764 765 // // Remove the temporary input element766 // document.body.removeChild(tempInput);767 // });768 // });769 // });770 771 772 // jQuery('body').on('click', '.copy-span', function () {773 // const span = this; // The clicked span element774 // const textToCopy = span.textContent;775 776 // // Create a temporary input element to copy the text777 // const tempInput = document.createElement('input');778 // document.body.appendChild(tempInput);779 780 // // Set the value of the input to the text of the span781 // tempInput.value = textToCopy;782 783 // // Select the content in the input784 // tempInput.select();785 // tempInput.setSelectionRange(0, 99999); // For mobile devices786 787 // // Copy the content to clipboard788 // try {789 // document.execCommand('copy');790 // alert('Copied: ' + textToCopy); // Show the confirmation alert immediately791 // } catch (err) {792 // console.error('Unable to copy text', err);793 // }794 795 // // Remove the temporary input element796 // document.body.removeChild(tempInput);797 // });798 728 799 729 … … 845 775 }, 2000); 846 776 }); 777 778 document.addEventListener('change', function (event) { 779 if ( 780 event.target.matches('input[type="radio"][name="title-color"]') || 781 event.target.matches('input[type="radio"][name="font-color"]') || 782 event.target.matches('input[type="radio"][name="bg-color"]') 783 ) { 784 785 // Remove checked attribute from all radios in the same group 786 const name = event.target.name; 787 const allRadios = document.querySelectorAll(`input[type="radio"][name="${name}"]`); 788 allRadios.forEach(function (radio) { 789 radio.removeAttribute('checked'); 790 }); 791 // Set checked attribute on selected one 792 event.target.setAttribute('checked', 'checked'); 793 } 794 }); 795 -
ai-app-onsite/trunk/assets/js/ai-app-onsite-app-properties.js
r3281194 r3307540 9 9 // Check if status is 404 (Table does not exist or no rows found) 10 10 if (response.status === '404') { 11 //alert('Error: ' + response.message); 11 document.getElementById('app-properties-msg-container').innerHTML = '<p>It looks like some required settings are missing. Please ensure that "App Settings" are configured & an app has been created before adding app details.</p>'; 12 document.getElementById('app-details-form').style.display = 'none'; 12 13 return; 14 }else { 15 document.getElementById('app-properties-msg-container').innerHTML = ''; 16 document.getElementById('app-details-form').style.display = 'block'; 13 17 } 14 18 // Accessing the first object in the array 15 19 var firstObject = response[0]; 16 console.log(firstObject, 'firstObject');17 var app_logo = firstObject.appLogoImagePreview;18 console.log(app_logo, 'app_logo');19 20 var app_logo = firstObject.appLogoImagePreview; 20 21 var fileUploadDiv = document.getElementById('file-upload-div'); 21 22 var removeLogoBtn = document.getElementById('remove-logo-btn'); 23 var previewImage = document.getElementById('previewImage'); 22 24 23 25 if (app_logo != 'No preview available') { 24 var previewImage = document.getElementById('previewImage');25 26 previewImage.style.backgroundImage = `url('${app_logo}')`; 26 27 previewImage.style.backgroundSize = 'contain'; // Optional: Adjust background size … … 33 34 fileUploadDiv.classList.remove('col-md-12'); 34 35 } else { 35 var removeLogoBtn = document.getElementById('remove-logo-btn'); 36 previewImage.style.backgroundImage = ''; // Remove any previous image 37 previewImage.style.display = 'none'; // Hide the preview image 36 38 removeLogoBtn.style.display = 'none'; 37 39 fileUploadDiv.classList.add('col-md-12'); … … 49 51 var submit_button_txt = firstObject.submit_button_txt; 50 52 51 // var obj = JSON.parse(title_color); 52 if (app_name_show === "") { 53 if (app_name_show === "" || app_name_show == null) { 53 54 document.getElementById('app-name').value = app_name; 54 55 } else { … … 66 67 alert('Error: ' + xhr.status + ' ' + xhr.statusText); 67 68 } 69 70 const appDetailsFormTracker = trackFormChanges('#app-details-form'); 71 window.FormChangeRegistry.register('app_settings', appDetailsFormTracker, 'app-details'); 72 73 document.getElementById('save_ai_app_app_properties_data').addEventListener('click', function () { 74 appDetailsFormTracker.reset(); 75 }); 68 76 } 69 77 }; … … 102 110 //Start save app_properties JS 103 111 function ai_app_onsite_save_app_properties() { 104 console.log('Nonce value:', document.getElementById('ai_app_onsite_app_properties_nonce_field').value);105 console.log('Form data:', formData);106 112 // Clear all previous error messages 107 113 document.querySelectorAll('.fields-error').forEach(function (error) { … … 126 132 errors.push('App Disclaimer is required.'); 127 133 } 128 // if (fileUpload === '') {129 // errors.push('File Upload is required.');130 // }131 134 132 135 // If there are errors, display them and return … … 143 146 document.getElementById('app-disclaimer-error').textContent = error; 144 147 } 145 // if (error === 'File Upload is required.') {146 // document.getElementById('fileError').textContent = error;147 // }148 148 }); 149 149 return; 150 150 } 151 151 152 // Show loader 153 var loader = document.getElementById('loader'); 154 loader.style.display = 'flex'; 155 156 // Create and send AJAX request 152 ai_app_onsite_get_plugin_settings_from_properties(function(settings) { 153 const agreeTerms = Array.isArray(settings) 154 ? settings[0]?.agree_terms === '1' 155 : settings?.agree_terms === '1'; 156 157 if (!agreeTerms) { 158 const modalElement = document.getElementById('terms_conditions_modal'); 159 const modalInstance = new bootstrap.Modal(modalElement); 160 modalInstance.show(); 161 162 return; 163 } 164 165 166 // Show loader 167 var loader = document.getElementById('loader'); 168 loader.style.display = 'flex'; 169 170 // Create and send AJAX request 171 var xhr = new XMLHttpRequest(); 172 xhr.onreadystatechange = function () { 173 if (xhr.readyState === 4) { 174 var messageContainer = document.getElementById('app-properties-msg-container'); 175 setTimeout(function () { 176 loader.style.display = 'none'; 177 178 if (xhr.status === 200) { 179 // Handle the response from the server 180 var response = JSON.parse(xhr.responseText); 181 182 if (response.success) { 183 // Show success message 184 messageContainer.innerHTML = '<span style="color: green;"> ' + response.data + '</span>'; 185 } else { 186 // Show error message if request fails 187 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 188 } 189 } else { 190 // Show error message if request fails 191 messageContainer.innerHTML = '<span style="color: red;">Error: Failed to save data</span>'; 192 } 193 // Hide message after 3 seconds 194 setTimeout(function () { 195 messageContainer.innerHTML = ''; 196 }, 3000); 197 }, 2000); 198 } 199 }; 200 201 xhr.open('POST', myPluginAjax.ajaxurl, true); 202 203 // Create FormData object 204 var formData = new FormData(); 205 206 // Gather form data 207 formData.append('action', 'ai_app_onsite_save_app_properties'); 208 formData.append('app-name', document.getElementById("app-name") ? document.getElementById("app-name").value : ''); 209 formData.append('app-name-show', document.getElementById("app-name-toggle").checked); 210 211 // Check if file is selected 212 const fileInput = document.getElementById('file-upload'); 213 if (fileInput.files.length > 0) { 214 const file = fileInput.files[0]; 215 formData.append('app-file', file); 216 } 217 218 formData.append('app-description', document.getElementById("app-description") ? document.getElementById("app-description").value : ''); 219 formData.append('app-disclaimer', document.getElementById("app-disclaimer") ? document.getElementById("app-disclaimer").value : ''); 220 formData.append('submit-btn-txt', document.getElementById("submit-btn-txt") ? document.getElementById("submit-btn-txt").value : ''); 221 222 // Check if radio buttons are selected before accessing their value 223 //var titleColorRadio = document.querySelector('input[name="title-color"]:checked'); 224 225 var titleColorRadios = document.querySelectorAll('input[type="radio"][name="title-color"]'); 226 var titleColors = []; 227 228 if (titleColorRadios) { 229 titleColorRadios.forEach(function (titleColorRadio) { 230 if (titleColorRadio.checked) { 231 titleColors.push({"title_color_selected": titleColorRadio.value}); 232 } else { 233 titleColors.push({"title_color": titleColorRadio.value}); 234 } 235 }); 236 } 237 238 // Append titleColors as a nested array within formData 239 formData.append('titleColors', JSON.stringify(titleColors)); 240 241 //var fontColorRadio = document.querySelector('input[name="font-color"]:checked'); 242 //formData.append('font-color', fontColorRadio ? fontColorRadio.value : ''); 243 var fontColorRadios = document.querySelectorAll('input[type="radio"][name="font-color"]'); 244 var fontColor = []; 245 246 if (fontColorRadios) { 247 fontColorRadios.forEach(function (fontColorRadio) { 248 if (fontColorRadio.checked) { 249 fontColor.push({"font_color_selected": fontColorRadio.value}); 250 } else { 251 fontColor.push({"font_color": fontColorRadio.value}); 252 } 253 }); 254 } 255 256 formData.append('fontColor', JSON.stringify(fontColor)); 257 258 // var bgColorRadio = document.querySelector('input[name="bg-color"]:checked'); 259 // formData.append('bg-color', bgColorRadio ? bgColorRadio.value : ''); 260 var bgColorRadios = document.querySelectorAll('input[type="radio"][name="bg-color"]'); 261 var bgColor = []; 262 bgColor 263 if (bgColorRadios) { 264 bgColorRadios.forEach(function (bgColorRadio) { 265 if (bgColorRadio.checked) { 266 bgColor.push({"bg_color_selected": bgColorRadio.value}); 267 } else { 268 bgColor.push({"bg_color": bgColorRadio.value}); 269 } 270 }); 271 } 272 273 formData.append('bgColor', JSON.stringify(bgColor)); 274 275 // Include nonce field value 276 formData.append('ai_app_onsite_app_properties_nonce_field', document.getElementById("ai_app_onsite_app_properties_nonce_field").value); 277 278 xhr.send(formData); 279 }); 280 } 281 282 function ai_app_onsite_get_plugin_settings_from_properties(callback) { 157 283 var xhr = new XMLHttpRequest(); 284 xhr.open('POST', myPluginAjax.ajaxurl, true); 285 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 158 286 xhr.onreadystatechange = function () { 159 287 if (xhr.readyState === 4) { 160 var messageContainer = document.getElementById('app-properties-msg-container'); 161 setTimeout(function () { 162 loader.style.display = 'none'; 163 164 if (xhr.status === 200) { 165 // Handle the response from the server 166 var response = JSON.parse(xhr.responseText); 167 168 if (response.success) { 169 // Show success message 170 messageContainer.innerHTML = '<span style="color: green;"> ' + response.data + '</span>'; 171 } else { 172 // Show error message if request fails 173 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 174 } 175 } else { 176 // Show error message if request fails 177 messageContainer.innerHTML = '<span style="color: red;">Error: Failed to save data</span>'; 178 } 179 // Hide message after 3 seconds 180 setTimeout(function () { 181 messageContainer.innerHTML = ''; 182 }, 3000); 183 }, 2000); 288 var response = JSON.parse(xhr.responseText); 289 if (xhr.status === 200) { 290 callback(response); 291 } else { 292 console.error('Error fetching plugin settings'); 293 callback({ status: xhr.status, message: xhr.statusText }); 294 } 184 295 } 185 296 }; 186 187 xhr.open('POST', myPluginAjax.ajaxurl, true); 188 189 // Create FormData object 190 var formData = new FormData(); 191 192 // Gather form data 193 formData.append('action', 'ai_app_onsite_save_app_properties'); 194 formData.append('app-name', document.getElementById("app-name") ? document.getElementById("app-name").value : ''); 195 formData.append('app-name-show', document.getElementById("app-name-toggle").checked); 196 197 // Check if file is selected 198 const fileInput = document.getElementById('file-upload'); 199 if (fileInput.files.length > 0) { 200 const file = fileInput.files[0]; 201 formData.append('app-file', file); 202 } 203 204 formData.append('app-description', document.getElementById("app-description") ? document.getElementById("app-description").value : ''); 205 formData.append('app-disclaimer', document.getElementById("app-disclaimer") ? document.getElementById("app-disclaimer").value : ''); 206 formData.append('submit-btn-txt', document.getElementById("submit-btn-txt") ? document.getElementById("submit-btn-txt").value : ''); 207 208 // Check if radio buttons are selected before accessing their value 209 //var titleColorRadio = document.querySelector('input[name="title-color"]:checked'); 210 211 var titleColorRadios = document.querySelectorAll('input[type="radio"][name="title-color"]'); 212 var titleColors = []; 213 214 if (titleColorRadios) { 215 titleColorRadios.forEach(function (titleColorRadio) { 216 if (titleColorRadio.checked) { 217 titleColors.push({ "title_color_selected": titleColorRadio.value }); 218 } else { 219 titleColors.push({ "title_color": titleColorRadio.value }); 220 } 221 }); 222 } 223 224 // Append titleColors as a nested array within formData 225 formData.append('titleColors', JSON.stringify(titleColors)); 226 227 //var fontColorRadio = document.querySelector('input[name="font-color"]:checked'); 228 //formData.append('font-color', fontColorRadio ? fontColorRadio.value : ''); 229 var fontColorRadios = document.querySelectorAll('input[type="radio"][name="font-color"]'); 230 var fontColor = []; 231 232 if (fontColorRadios) { 233 fontColorRadios.forEach(function (fontColorRadio) { 234 if (fontColorRadio.checked) { 235 fontColor.push({ "font_color_selected": fontColorRadio.value }); 236 } else { 237 fontColor.push({ "font_color": fontColorRadio.value }); 238 } 239 }); 240 } 241 242 formData.append('fontColor', JSON.stringify(fontColor)); 243 244 // var bgColorRadio = document.querySelector('input[name="bg-color"]:checked'); 245 // formData.append('bg-color', bgColorRadio ? bgColorRadio.value : ''); 246 var bgColorRadios = document.querySelectorAll('input[type="radio"][name="bg-color"]'); 247 var bgColor = []; 248 bgColor 249 if (bgColorRadios) { 250 bgColorRadios.forEach(function (bgColorRadio) { 251 if (bgColorRadio.checked) { 252 bgColor.push({ "bg_color_selected": bgColorRadio.value }); 253 } else { 254 bgColor.push({ "bg_color": bgColorRadio.value }); 255 } 256 }); 257 } 258 259 formData.append('bgColor', JSON.stringify(bgColor)); 260 261 // Include nonce field value 262 formData.append('ai_app_onsite_app_properties_nonce_field', document.getElementById("ai_app_onsite_app_properties_nonce_field").value); 263 264 xhr.send(formData); 265 } 266 267 268 297 xhr.send('action=ai_app_onsite_get_plugin_settings'); 298 } 269 299 270 300 //=========End save app_properties JS====================== -
ai-app-onsite/trunk/assets/js/ai-app-onsite-field-selector.js
r3281194 r3307540 19 19 jQuery(".form-group .ui-state-default").each(function (index) { 20 20 var position = jQuery(this).index(); 21 console.log("Position of div " + index + ": " + position);22 21 }); 23 22 } … … 141 140 if (xhr.status === 200) { 142 141 // Handle success response 143 console.log(xhr.responseText);144 142 // remove div html logically 145 143 jQuery(e).closest(".form-group").remove(); … … 201 199 // Use 'group' instead of jQuery(".form-group.ui-state-default") 202 200 var firstUniqueId = jQuery(".field-catcher.ui-sortable .form-group.ui-state-default:first").attr('field_unique_id'); 203 console.log(firstUniqueId, 'firstUniqueId');204 201 // Get form fields 205 202 var fieldCreator = document.getElementById("filed_creator_" + idx); … … 321 318 // Handle the response from the server 322 319 var response = JSON.parse(xhr.responseText); 323 // console.log(response);324 320 var response_html_content = response.html_content; 325 321 // toggleMaxCharVisibility(response_html_content); … … 336 332 console.error('Error occurred: ' + xhr.responseText); 337 333 } 334 335 document.getElementById('app_width_figure').setAttribute('name', 'app_width_figure'); 336 jQuery(".field-catcher .form-group").each(function (index) { 337 jQuery(this).find("select").attr("name", "filed_creator_" + index); 338 }); 339 340 const appFieldSelectorSettingsformTracker = trackFormChanges('#myForm'); 341 window.FormChangeRegistry.register('app_field_selector_settings', appFieldSelectorSettingsformTracker, 'field-selector'); 342 343 document.getElementById('save_ai_app_ai_app_fieldselector_data').addEventListener('click', function () { 344 const nonceValue = document.getElementById("ai_app_onsite_field_selector_nonce_field").value; 345 346 appFieldSelectorSettingsformTracker.reset(); 347 348 // Restore nonce after reset 349 document.getElementById("ai_app_onsite_field_selector_nonce_field").value = nonceValue; 350 }); 338 351 } 339 352 }; … … 374 387 maxCharField.style.display = 'block'; 375 388 assignChar.value = '80'; // Assign the value '80' explicitly 376 console.log('textbox', maxCharField.value);377 389 fieldSample.style.display = 'block'; 378 390 document.querySelector(`.dropdown-options-col_${index}`).style.display = 'none'; … … 381 393 maxCharField.style.display = 'block'; 382 394 assignChar.value = '300'; // Assign the value '300' 383 console.log('textarea', maxCharField.value);384 395 fieldSample.style.display = 'block'; 385 396 document.querySelector(`.dropdown-options-col_${index}`).style.display = 'none'; … … 387 398 maxCharField.style.display = 'block'; 388 399 assignChar.value = '10'; // Assign the value '10' 389 console.log('number', maxCharField.value);390 400 fieldSample.style.display = 'block'; 391 401 document.querySelector(`.dropdown-options-col_${index}`).style.display = 'none'; … … 393 403 maxCharField.style.display = 'block'; 394 404 assignChar.value = '50'; // Assign the value '50' 395 console.log('email', maxCharField.value);396 405 fieldSample.style.display = 'block'; 397 406 document.querySelector(`.dropdown-options-col_${index}`).style.display = 'none'; … … 415 424 fieldSample.style.display = 'none'; 416 425 dropdownColumn.style.display = 'block'; 417 console.log('dropdown');418 426 } 419 427 }); … … 433 441 maxCharField.style.display = 'block'; 434 442 assignChar.value = '80'; // Assign the value '80' explicitly 435 console.log('textbox', maxCharField.value);436 443 fieldSample.style.display = 'block'; 437 444 dropdownColumn.style.display = 'none'; … … 439 446 maxCharField.style.display = 'block'; 440 447 assignChar.value = '300'; // Assign the value '300' 441 console.log('textarea', maxCharField.value);442 448 fieldSample.style.display = 'block'; 443 449 dropdownColumn.style.display = 'none'; … … 445 451 maxCharField.style.display = 'block'; 446 452 assignChar.value = '10'; // Assign the value '10' 447 console.log('number', maxCharField.value);448 453 fieldSample.style.display = 'block'; 449 454 dropdownColumn.style.display = 'none'; … … 451 456 maxCharField.style.display = 'block'; 452 457 assignChar.value = '50'; // Assign the value '50' 453 console.log('email', maxCharField.value);454 458 fieldSample.style.display = 'block'; 455 459 dropdownColumn.style.display = 'none'; -
ai-app-onsite/trunk/assets/js/ai-app-onsite-model-settings.js
r3281194 r3307540 101 101 //Start get model settings from db js 102 102 function ai_app_onsite_get_model_settings() { 103 const appModalSettingsformTracker = trackFormChanges('#ai_app_onsite_reset_modal-setting'); 104 appModalSettingsformTracker.reset(); 103 105 104 106 var xhr = new XMLHttpRequest(); … … 109 111 // Handle success response 110 112 var response = JSON.parse(xhr.responseText); 111 console.log(response, 'ai_app_onsite_get_model_settings');112 113 if (response.status === '404') { 113 114 var saveKpenapiKeyBtn = document.getElementById('save-openapi-key'); 114 115 var apiDisableBtn = document.getElementById("api-disable-btn"); 115 116 var apiKeyMgtBtn = document.getElementById("api-key-management"); 116 117 var openaiKey = document.getElementById('openai-key'); 118 var openaiKeyHidden = document.getElementById('openai-key-hidden'); 119 120 openaiKey.value = ''; 121 openaiKeyHidden.value = ''; 117 122 118 123 const engineDropdown = document.getElementById('model'); … … 166 171 167 172 return; 173 } else { 174 document.getElementById('model').classList.remove('border-danger'); 175 document.getElementById('model-help-text').innerHTML = ''; 176 177 document.getElementById('model-dependent-fields').classList.remove('blurred'); 178 document.querySelectorAll('.model-dependent').forEach(function (el) { 179 el.disabled = false; 180 }); 181 182 document.getElementById("api-key-management").style.display = 'block'; 183 184 const apiDisableBtn = document.getElementById("api-disable-btn"); 185 apiDisableBtn.disabled = false; 186 187 // You can also re-enable save if needed 188 const saveKpenapiKeyBtn = document.getElementById('save-openapi-key'); 189 saveKpenapiKeyBtn.removeAttribute('disabled'); // or saveKpenapiKeyBtn.disabled = false; 168 190 } 169 170 191 171 192 … … 203 224 // Check if the value is null or empty 204 225 if (!openai_key) { 205 //jQuery('#apiinfoModal').modal('show'); 226 openaiKey.value = ''; 227 openaiKeyHidden.value = ''; 228 206 229 const modalElement = document.getElementById('apiinfoModal'); 207 230 const modalInstance = new bootstrap.Modal(modalElement); … … 238 261 239 262 } else { 240 241 263 // Handle error response 242 264 alert('Error occurred: ' + xhr.responseText); 243 265 } 266 267 document.getElementById('model').setAttribute('name', 'model'); 268 269 window.FormChangeRegistry.register('app_modal_settings', appModalSettingsformTracker, 'model-settings'); 270 271 document.getElementById('save_ai_app_modal_settings_data').addEventListener('click', function () { 272 appModalSettingsformTracker.reset(); 273 }); 244 274 } 245 275 }; … … 249 279 xhr.send('action=ai_app_onsite_get_model_settings'); 250 280 } 251 252 281 253 282 // Function to update the input value … … 271 300 } 272 301 } 273 274 275 276 277 302 278 303 // Function to send the original API key to the server … … 432 457 // Copy the text inside the text field 433 458 if (document.execCommand('copy')) { 434 console.log('API key copied to clipboard successfully.');435 459 436 460 // Change the icon color by adding a class … … 482 506 } 483 507 484 485 508 function ai_app_onsite_get_openapi_data() { 486 509 var xhr = new XMLHttpRequest(); … … 500 523 var openai_key = firstObject.openai_key; 501 524 var key_status = firstObject.key_status; 502 console.log(key_status, 'key_status');503 525 if (key_status == 'false') { 504 console.log('sderfdfgfgfgfgfgf');505 526 document.getElementById('key-status').textContent = 'DISABLED'; 506 527 document.getElementById("api-disable-btn").checked = false; … … 541 562 return maskedPart.slice(0, maxLength); 542 563 } 543 544 564 545 565 // Add event listener for input changes … … 578 598 579 599 document.getElementById('api-disable-btn').addEventListener('change', function () { 580 console.log(this.checked);581 600 if (this.checked == true) { 582 583 601 var switchText = document.getElementsByClassName('text-switch')[0]; 584 602 switchText.textContent = 'ENABLED'; … … 646 664 } 647 665 } 666 667 const modalElement = document.getElementById('apiinfoModal'); 668 modalElement.addEventListener('hidden.bs.modal', function () { 669 // Remove lingering backdrop 670 document.querySelectorAll('.modal-backdrop').forEach(el => el.remove()); 671 672 // Remove modal-open class and inline styles 673 document.body.classList.remove('modal-open'); 674 document.body.style.overflow = ''; 675 document.body.style.paddingRight = ''; 676 }, { once: true }); 648 677 }); -
ai-app-onsite/trunk/assets/js/ai-app-onsite-openai-api.js
r3281194 r3307540 64 64 } 65 65 66 67 66 function validateForm(aiappForm) { 68 67 // Check if form exists … … 86 85 87 86 if (!errorParagraph) { 88 console.error('Error paragraph not found for field with ID:', field.id);87 // console.error('Error paragraph not found for field with ID:', field.id); 89 88 return; // Exit the loop if error paragraph is not found 90 89 } … … 115 114 // If any required field is empty, show an alert and prevent form submission 116 115 if (!isValid) { 117 console.log('Please fill in all required fields.');118 116 return false; // Form is invalid 119 117 } … … 121 119 return formData; // Return form data if form is valid 122 120 } 121 122 document.addEventListener('keydown', function(event) { 123 if (event.key === 'Enter') { 124 event.preventDefault(); 125 } 126 }); 127 128 129 document.querySelectorAll('a.open-new-tab').forEach(function (link) { 130 link.setAttribute('target', '_blank'); 131 link.setAttribute('rel', 'noopener noreferrer'); 132 }); 133 134 const observer = new MutationObserver(function (mutationsList) { 135 mutationsList.forEach(function (mutation) { 136 mutation.addedNodes.forEach(function (node) { 137 if (node.nodeType === 1) { 138 if (node.matches('a.open-new-tab')) { 139 node.setAttribute('target', '_blank'); 140 node.setAttribute('rel', 'noopener noreferrer'); 141 } else { 142 // Also check any child links inside 143 node.querySelectorAll('a.open-new-tab').forEach(function (link) { 144 link.setAttribute('target', '_blank'); 145 link.setAttribute('rel', 'noopener noreferrer'); 146 }); 147 } 148 } 149 }); 150 }); 151 }); 152 153 observer.observe(document.body, { childList: true, subtree: true }); -
ai-app-onsite/trunk/assets/js/ai-app-onsite-plugin-settings.js
r3272415 r3307540 1 1 // Function to setup terms of service modal 2 2 function setupTermsOfServiceModal() { 3 var termsCheckbox = document.getElementById("terms_conditions"); 4 var acceptButton = document.getElementById("accept_ai_app_terms_of_service"); 5 var oldTermsCheckbox = document.getElementById("terms_of_service-old"); 6 var modal = document.getElementById("terms_conditions_modal"); 7 var closeButton = modal.querySelector(".btn-close"); 8 var savePluginSetting = document.getElementById("save_ai_app_plugin_settings_data"); 9 var termsOfServiceError = document.getElementById('terms_of_service-error'); 10 11 // Function to enable/disable accept button based on checkbox status 12 function toggleAcceptButton() { 13 if (termsCheckbox.checked) { 14 acceptButton.disabled = false; 15 } else { 16 acceptButton.disabled = true; 3 var termsCheckbox = document.getElementById("terms_conditions"); 4 var acceptButton = document.getElementById("accept_ai_app_terms_of_service"); 5 var oldTermsCheckbox = document.getElementById("terms_of_service-old"); 6 var modal = document.getElementById("terms_conditions_modal"); 7 var closeButton = modal.querySelector(".btn-close"); 8 var savePluginSetting = document.getElementById("save_ai_app_plugin_settings_data"); 9 var termsOfServiceError = document.getElementById('terms_of_service-error'); 10 11 // Function to enable/disable accept button based on checkbox status 12 function toggleAcceptButton() { 13 if (termsCheckbox.checked) { 14 acceptButton.disabled = false; 15 } else { 16 acceptButton.disabled = true; 17 } 17 18 } 18 } 19 20 // Initially check the checkbox status 21 toggleAcceptButton(); 22 23 // Event listener for checkbox change 24 termsCheckbox.addEventListener("change", function() { 19 20 // Initially check the checkbox status 25 21 toggleAcceptButton(); 26 }); 27 28 // Event listener for accept button click 29 acceptButton.addEventListener("click", function() { 30 if (termsCheckbox.checked) { 31 oldTermsCheckbox.checked = true; // Check the other checkbox 32 termsOfServiceError.textContent = ''; 33 closeModal(); // Close the modal 22 23 // Event listener for checkbox change 24 termsCheckbox.addEventListener("change", function() { 25 toggleAcceptButton(); 26 }); 27 28 // Event listener for accept button click 29 acceptButton.addEventListener("click", function() { 30 if (termsCheckbox.checked) { 31 oldTermsCheckbox.checked = true; // Check the other checkbox 32 termsOfServiceError.textContent = ''; 33 closeModal(); // Close the modal 34 } 35 }); 36 37 // Event listener for close button click 38 closeButton.addEventListener("click", function() { 39 if (!termsCheckbox.checked) { 40 oldTermsCheckbox.checked = false; // Uncheck the other checkbox 41 } 42 }); 43 44 // Function to close the modal 45 function closeModal() { 46 modal.classList.remove("show"); 47 modal.style.display = "none"; 48 document.body.classList.remove("modal-open"); 49 document.body.style.paddingRight = ""; 50 document.querySelector(".modal-backdrop").remove(); 34 51 } 35 }); 36 37 // Event listener for close button click 38 closeButton.addEventListener("click", function() { 39 if (!termsCheckbox.checked) { 40 oldTermsCheckbox.checked = false; // Uncheck the other checkbox 52 53 function disable(){ 54 oldTermsCheckbox.addEventListener("change", function() { 55 if (oldTermsCheckbox.checked) { 56 savePluginSetting.disabled = false; 57 } else { 58 savePluginSetting.disabled = true; 59 } 60 }); 41 61 } 42 }); 43 44 // Function to close the modal 45 function closeModal() { 46 modal.classList.remove("show"); 47 modal.style.display = "none"; 48 document.body.classList.remove("modal-open"); 49 document.body.style.paddingRight = ""; 50 document.querySelector(".modal-backdrop").remove(); 51 } 52 53 function disable(){ 54 oldTermsCheckbox.addEventListener("change", function() { 55 if (oldTermsCheckbox.checked) { 56 savePluginSetting.disabled = false; 57 } else { 58 savePluginSetting.disabled = true; 62 //disable(); 63 } 64 65 // Call the setup function after the DOM is loaded 66 setupTermsOfServiceModal(); 67 //================End terms of service modal js ========================= 68 69 function ai_app_onsite_show_terms_of_service() { 70 const termsOfServiceModal = document.getElementById("terms_conditions_modal"); 71 const termsOfServiceCheckbox = document.getElementById("terms-form-group"); 72 const divider = document.getElementById("divider"); 73 const termsOfServiceButtons = document.getElementById("terms_conditions_button"); 74 75 const modalInstance = new bootstrap.Modal(termsOfServiceModal); 76 modalInstance.show(); 77 78 termsOfServiceCheckbox.style.display = "none"; 79 divider.style.display = "none"; 80 termsOfServiceButtons.style.display = "none"; 81 } 82 83 let isPluginSaveTriggered = false; 84 let isSwitchChecked = false; 85 86 //Start save plugin settings JS 87 function ai_app_onsite_save_plugin_settings() { 88 // Clear all previous error messages 89 document.querySelectorAll('.fields-error').forEach(function(error) { 90 error.textContent = ''; 91 }); 92 93 // Get form fields 94 var terms_of_service = document.getElementById("terms_of_service-old").checked; 95 96 // Collect error messages 97 var errors = []; 98 if (!terms_of_service) { 99 errors.push('Please Agree to Terms of Service.'); 100 const modalElement = document.getElementById('terms_conditions_modal'); 101 const modalInstance = new bootstrap.Modal(modalElement); 102 modalInstance.show(); 103 104 const termsOfServiceCheckbox = document.getElementById("terms-form-group"); 105 const divider = document.getElementById("divider"); 106 const termsOfServiceButtons = document.getElementById("terms_conditions_button"); 107 108 termsOfServiceCheckbox.style.display = "block"; 109 divider.style.display = "block"; 110 termsOfServiceButtons.style.display = "flex"; 111 isPluginSaveTriggered = true; 112 }else { 113 isPluginSaveTriggered = false; 114 } 115 116 // If there are errors, display them and return 117 if (errors.length > 0) { 118 errors.forEach(function(error) { 119 if (error === 'Please Agree to Terms of Service.') { 120 document.getElementById('terms_of_service-error').textContent = error; 121 } 122 }); 123 return; 124 } 125 // Show loader 126 var loader = document.getElementById('loader'); 127 loader.style.display = 'flex'; 128 129 var xhr = new XMLHttpRequest(); 130 xhr.onreadystatechange = function() { 131 if (xhr.readyState === 4) { 132 // Show success message 133 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 134 setTimeout(function() { 135 loader.style.display = 'none'; 136 137 if (xhr.status === 200) { 138 // Handle the response from the server 139 var response = JSON.parse(xhr.responseText); 140 if (response.success) { 141 messageContainer.innerHTML = '<span style="color: green;"> ' + response.data + '</span>'; 142 ai_app_onsite_get_plugin_settings(); 143 }else{ 144 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 145 } 146 } else { 147 messageContainer.innerHTML = '<span style="color: red;">Error: Failed to save data</span>'; 148 } 149 // Hide message after 3 seconds 150 setTimeout(function() { 151 messageContainer.innerHTML = ''; 152 }, 3000); 153 }, 2000); 59 154 } 60 }); 61 } 62 //disable(); 63 } 64 65 // Call the setup function after the DOM is loaded 66 setupTermsOfServiceModal(); 67 //================End terms of service modal js ========================= 68 69 //Start save plugin settings JS 70 function ai_app_onsite_save_plugin_settings() { 71 // Clear all previous error messages 72 document.querySelectorAll('.fields-error').forEach(function(error) { 73 error.textContent = ''; 74 }); 75 76 // Get form fields 77 var terms_of_service = document.getElementById("terms_of_service-old").checked; 78 79 // Collect error messages 80 var errors = []; 81 if (!terms_of_service) { 82 errors.push('Please Agree to Terms of Service.'); 83 } 84 85 // If there are errors, display them and return 86 if (errors.length > 0) { 87 errors.forEach(function(error) { 88 if (error === 'Please Agree to Terms of Service.') { 89 document.getElementById('terms_of_service-error').textContent = error; 90 } 91 }); 92 return; 93 } 94 // Show loader 95 var loader = document.getElementById('loader'); 96 loader.style.display = 'flex'; 97 98 var xhr = new XMLHttpRequest(); 99 xhr.onreadystatechange = function() { 100 if (xhr.readyState === 4) { 101 // Show success message 102 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 103 setTimeout(function() { 104 loader.style.display = 'none'; 105 155 }; 156 157 xhr.open('POST', myPluginAjax.ajaxurl, true); 158 159 var formData = new FormData(); 160 formData.append('action', 'ai_app_onsite_save_plugin_settings'); 161 formData.append('terms_of_service', document.getElementById("terms_of_service-old") ? document.getElementById("terms_of_service-old").checked : false); 162 formData.append('app_selector', document.getElementById("app_selector") ? document.getElementById("app_selector").value : ""); 163 formData.append('app_email', document.getElementById("app_email") ? document.getElementById("app_email").value : ""); 164 165 // Gather selected banned words 166 var bannedWordsSelect = document.querySelector('[data-multi-select-plugin]'); 167 var selectedOptions = bannedWordsSelect.selectedOptions; 168 var banned_words = []; 169 let selectedLabels = document.querySelectorAll('.selected-wrapper .selected-label'); 170 171 // Loop through each of the selected labels 172 selectedLabels.forEach(function(label) { 173 banned_words.push(label.textContent); 174 }); 175 // Append each banned word to the formData object 176 for (var j = 0; j < banned_words.length; j++) { 177 formData.append('banned_words[]', banned_words[j]); 178 } 179 180 181 // Append the CSV file 182 const fileInput = document.getElementById('csv-upload'); 183 if (fileInput.files.length > 0) { 184 const file = fileInput.files[0]; 185 formData.append('csv-file', file); 186 } 187 188 // Append nonce field value 189 formData.append('ai_app_onsite_plugin_settings_nonce_field', document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value); 190 191 192 xhr.send(formData); 193 } 194 195 //=======================End save plugin settings js=========================== 196 197 //Start get plugin setting from db js 198 function ai_app_onsite_get_plugin_settings() { 199 var xhr = new XMLHttpRequest(); 200 201 xhr.onreadystatechange = function() { 202 if (xhr.readyState === 4) { 106 203 if (xhr.status === 200) { 107 // Handle the response from the server 108 var response = JSON.parse(xhr.responseText); 109 if (response.success) { 110 messageContainer.innerHTML = '<span style="color: green;"> ' + response.data + '</span>'; 111 }else{ 112 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 113 } 204 // Handle success response 205 var response = JSON.parse(xhr.responseText); 206 if (response.status === "404") { 207 return; 208 }; 209 210 // Accessing the first object in the array 211 var firstObject = response[0]; 212 213 // Accessing properties of the first object 214 var id = firstObject.id; 215 var agreeTerms = firstObject.agree_terms; 216 var appSelector = firstObject.app_selector; 217 var userStats = firstObject.user_stats; 218 var bannedWords = firstObject.banned_words; 219 var bannedWordsCSV = firstObject.banned_words_csv; 220 var appName = firstObject.appName; 221 const selectElement = document.getElementById("bannedWords"); 222 223 var app_email = firstObject.app_email; 224 225 // Assume selectElement is already defined as your target select element 226 bannedWordsCSV.forEach((item) => { 227 // Check if an option with the same value already exists 228 const exists = Array.from(selectElement.options).some( 229 (option) => option.value === item[0] 230 ); 231 232 if (!exists) { 233 // Create a new option element 234 const option = document.createElement("option"); 235 236 // Set the value and text of the option element 237 option.value = item[0]; 238 option.text = item[0]; 239 240 // Append the option element to the select element 241 selectElement.appendChild(option); 242 } 243 244 const optionToSelect = Array.from(selectElement.options).find( 245 (option) => option.value === item[0] 246 ); 247 if (optionToSelect) { 248 optionToSelect.selected = true; 249 } 250 }); 251 252 if ( 253 appName != null && 254 appName !== "" && 255 appName !== "undefined" 256 ) { 257 var selectElements = document.getElementById("app_selector"); 258 selectElements.value = appName; 259 } 260 var app_emails = document.getElementById("app_email"); 261 app_emails.value = app_email; 262 263 // Set checkbox checked if agreeTerms is "1" 264 if (agreeTerms === "1") { 265 document.getElementById("terms_of_service-old").checked = true; 266 // Ensure the modal is not triggered 267 } 268 269 var searchContainer = document.querySelector(".search-container"); 270 271 var searchContainer = document.querySelector(".search-container"); // Ensure the selector is correct 272 if (!searchContainer) { 273 console.error("searchContainer element not found!"); 274 return; // Exit if the container is missing 275 } 276 bannedWords.forEach(function (value) { 277 if (value) { 278 // Ensure value is not empty or falsy 279 var exists = document.querySelector( 280 '.selected-wrapper span.selected-label[data-value="' + 281 value + 282 '"]' 283 ); 284 if (!exists) { 285 // Create new elements only if the value is not empty and doesn't already exist 286 var newDiv = document.createElement("div"); 287 newDiv.className = "selected-wrapper"; 288 289 var labelSpan = document.createElement("span"); 290 labelSpan.className = "selected-label"; 291 labelSpan.textContent = value; 292 labelSpan.setAttribute("data-value", value); 293 294 var closeLink = document.createElement("a"); 295 closeLink.className = "selected-close"; 296 closeLink.setAttribute("tabindex", "-1"); 297 closeLink.setAttribute("data-option", value); 298 closeLink.setAttribute("data-hits", "0"); 299 closeLink.href = "#"; 300 closeLink.textContent = "x"; 301 302 newDiv.appendChild(labelSpan); 303 newDiv.appendChild(closeLink); 304 searchContainer.before(newDiv); // Ensure searchContainer exists before this line 305 } 306 } 307 }); 308 309 document 310 .querySelectorAll(".selected-wrapper") 311 .forEach((wrapper) => { 312 const label = wrapper.querySelector(".selected-label"); 313 if (!label.hasAttribute("data-value")) { 314 wrapper.remove(); 315 } 316 }); 317 318 // Event listener for the dropdown icon click 319 const dropdownIcon = document.querySelector(".dropdown-icon"); 320 if (dropdownIcon) { 321 dropdownIcon.addEventListener("click", function () { 322 if (this.classList.contains("active")) { 323 document 324 .querySelectorAll(".selected-wrapper .selected-label") 325 .forEach(function (element) { 326 var valueToRemove = element.textContent.trim(); 327 document 328 .querySelectorAll(".autocomplete-list li") 329 .forEach(function (liElement) { 330 if ( 331 liElement.textContent.trim() === valueToRemove 332 ) { 333 liElement.parentNode.removeChild(liElement); 334 } 335 }); 336 }); 337 } else { 338 console.log("Dropdown icon is not active"); 339 } 340 }); 341 } else { 342 console.log("Dropdown icon not found"); 343 } 114 344 } else { 115 messageContainer.innerHTML = '<span style="color: red;">Error: Failed to save data</span>'; 345 // Handle error response 346 alert('Error occurred: ' + xhr.responseText); 347 } 348 349 const appSettingsformTracker = trackFormChanges('#app_settings_form'); 350 window.FormChangeRegistry.register('app_settings', appSettingsformTracker, 'app-settings'); 351 352 document.getElementById('save_ai_app_plugin_settings_data').addEventListener('click', function () { 353 appSettingsformTracker.reset(); 354 }); 355 356 357 } 358 }; 359 360 xhr.open('POST', myPluginAjax.ajaxurl, true); 361 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 362 xhr.send('action=ai_app_onsite_get_plugin_settings'); 363 364 ai_app_onsite_get_app_license_key(); 365 } 366 367 /*=============End get plugin setting from db js============================== */ 368 369 370 /*=============Download terms Of service js=================================== */ 371 372 function ai_app_onsite_download_terms_Of_service() { 373 const { jsPDF } = window.jspdf; 374 const doc = new jsPDF(); 375 const termsContent = document.getElementById('terms-conditions-modal-pdf').innerText; 376 377 const maxWidth = 180; // Maximum width for text in mm 378 const startX = 10; // X-coordinate to start text 379 const startY = 10; // Y-coordinate to start text 380 const lineHeight = 4.5; // Approximate line height in mm 381 const pageHeight = 297; // A4 page height in mm (210x297mm) 382 const marginBottom = 10; // Bottom margin 383 384 let cursorY = startY; // Track current Y-coordinate 385 386 // Set font size 387 const fontSize = 12; // Set the font size as desired 388 doc.setFontSize(fontSize); 389 390 // Split text into lines that fit within the specified max width 391 const lines = doc.splitTextToSize(termsContent, maxWidth); 392 393 // Add the lines of text to the PDF 394 lines.forEach(line => { 395 if (cursorY + lineHeight > pageHeight - marginBottom) { 396 // Add new page if the text exceeds the page height 397 doc.addPage(); 398 cursorY = startY; // Reset cursorY for new page 399 } 400 doc.text(line, startX, cursorY); 401 cursorY += lineHeight * (fontSize / 10); // Adjust cursorY based on font size 402 }); 403 doc.save('AIappOniste-terms-of-service.pdf'); 404 } 405 406 /*=============End download terms Of service js=================================== */ 407 408 409 /*=============Download user stats js=================================== */ 410 function ai_app_onsite_download_user_stats(event) { 411 event.preventDefault(); 412 // Show loader 413 document.getElementById('loader').style.display = 'flex'; 414 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 415 416 // Get the selected month (e.g., from a dropdown or an input) 417 const month = document.getElementById('ai_app_onsite-user-stats').value; 418 var userStatsError = document.getElementById('ai_app_onsite-user-stats-error'); 419 userStatsError.textContent = ''; 420 var ai_app_onsite_download_user_stats_nonce = myPluginAjax.downloadUserStatsNonce; 421 422 // Prepare data to send 423 const data = new FormData(); 424 data.append('ai_app_onsite_download_user_stats_nonce', ai_app_onsite_download_user_stats_nonce); // Correctly use the nonce variable 425 data.append('action', 'ai_app_onsite_download_user_stats'); // Action name 426 data.append('month', month); // Pass the month value 427 // Make AJAX request 428 fetch(ajaxurl, { 429 method: 'POST', 430 body: data, 431 }) 432 .then(response => { 433 if (!response.ok) { 434 throw new Error('Network response was not ok'); 435 } 436 return response.text(); // Read response as text 437 }) 438 .then(text => { 439 // Hide loader after a delay (e.g., 1 second) 440 setTimeout(() => { 441 document.getElementById('loader').style.display = 'none'; 442 443 // Check if the response indicates failure and no data found 444 if (text.includes('No user statistics found.')) { 445 // Show error message 446 userStatsError.textContent = 'No user statistics found.'; 447 } else { 448 // Create a blob from the response text 449 const blob = new Blob([text], { type: 'text/csv' }); 450 451 // Create a link element 452 const url = window.URL.createObjectURL(blob); 453 const a = document.createElement('a'); 454 a.style.display = 'none'; 455 a.href = url; 456 a.download = 'AIappOniste_User_Stats.csv'; 457 458 // Append the link to the body 459 document.body.appendChild(a); 460 a.click(); 461 462 // Remove the link 463 document.body.removeChild(a); 464 465 // Revoke the object URL 466 window.URL.revokeObjectURL(url); 467 468 messageContainer.innerHTML = '<span style="color: green;">User stats downloaded successfully</span>'; 469 470 } 471 setTimeout(function() { 472 messageContainer.innerHTML = ''; 473 }, 3000); 474 }, 2000); // Adjust delay time as needed 475 }) 476 .catch(error => { 477 // Hide loader 478 document.getElementById('loader').style.display = 'none'; 479 480 // Show error message 481 document.getElementById('ai_app_onsite-user-stats-error').textContent = 'Error: ' + error.message; 482 }); 483 } 484 485 //upload file js 486 function validateCSVFile(input) { 487 var file = document.getElementById('csv-upload').files[0]; 488 var fileError = document.getElementById('fileError'); 489 // Check if file is selected 490 if (!file) { 491 fileError.textContent = 'Please select a file.'; 492 return; 493 } 494 495 // Check file type 496 var validExtensions = ['text/csv']; 497 if (!validExtensions.includes(file.type)) { 498 fileError.textContent = 'Please select a valid image file (SVG, PNG, JPG, or GIF).'; 499 this.value = ''; // Clear the input field 500 501 return; 502 } 503 504 fileError.textContent = ''; // Clear any previous errors 505 506 uploadCSVFile(file); 507 // Reset input value to allow same file to be selected again 508 input.value = ''; 509 } 510 511 512 function uploadCSVFile(file) { 513 var formData = new FormData(); 514 formData.append('csv-file', file); 515 formData.append('action', 'ai_app_onsite_handle_csv_upload'); 516 formData.append('ai_app_onsite_plugin_settings_nonce_csv_upload_field', document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value); 517 518 var xhr = new XMLHttpRequest(); 519 xhr.open('POST', myPluginAjax.ajaxurl, true); 520 521 xhr.onreadystatechange = function () { 522 if (xhr.readyState === 4) { // Ensure the request is complete 523 if (xhr.status === 200) { 524 525 if (xhr.responseText) { // Check if the response text is not empty 526 try { 527 var response = JSON.parse(xhr.responseText); 528 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 529 if (messageContainer) { 530 if (response.success) { 531 messageContainer.innerHTML = '<span style="color: green;">' + response.data + '</span>'; 532 } else { 533 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 534 } 535 ai_app_onsite_get_plugin_settings(); 536 537 } else { 538 console.error('messageContainer element not found'); 539 } 540 } catch (e) { 541 console.error('Failed to parse response:', e); 542 var messageContainer = document.getElementById('messageContainer'); 543 if (messageContainer) { 544 messageContainer.innerHTML = '<span style="color: red;">Error parsing response</span>'; 545 } else { 546 console.error('messageContainer element not found'); 547 } 548 } 549 } else { 550 console.error('Empty response'); 551 var messageContainer = document.getElementById('messageContainer'); 552 if (messageContainer) { 553 messageContainer.innerHTML = '<span style="color: red;">Empty response</span>'; 554 } else { 555 console.error('messageContainer element not found'); 556 } 557 } 558 } else { 559 console.error('Request failed with status:', xhr.status); 560 var messageContainer = document.getElementById('messageContainer'); 561 if (messageContainer) { 562 messageContainer.innerHTML = '<span style="color: red;">Error: ' + xhr.status + '</span>'; 563 } else { 564 console.error('messageContainer element not found'); 565 } 116 566 } 117 567 // Hide message after 3 seconds … … 119 569 messageContainer.innerHTML = ''; 120 570 }, 3000); 121 }, 2000); 571 572 573 } 574 }; 575 576 xhr.send(formData); 577 } 578 579 function uploadTermCondition(checkbox) { 580 var terms_of_service = document.getElementById("terms_of_service-old").checked; 581 var terms_of_service_nonce = document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value; 582 var xhr = new XMLHttpRequest(); // Initialize the XMLHttpRequest object 583 xhr.open('POST', myPluginAjax.ajaxurl, true); 584 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // Set the request header 585 586 xhr.onreadystatechange = function () { 587 if (xhr.readyState === 4) { // Ensure the request is complete 588 var messageContainer = document.getElementById('Plugin-settings-msg-container') || document.getElementById('messageContainer'); 589 if (xhr.status === 200) { 590 591 if (xhr.responseText) { // Check if the response text is not empty 592 try { 593 var response = JSON.parse(xhr.responseText); 594 if (messageContainer) { 595 if (response.success) { 596 messageContainer.innerHTML = '<span style="color: green;">' + response.data + '</span>'; 597 } else { 598 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 599 } 600 } else { 601 console.error('messageContainer element not found'); 602 } 603 } catch (e) { 604 console.error('Failed to parse response:', e); 605 if (messageContainer) { 606 messageContainer.innerHTML = '<span style="color: red;">Error parsing response</span>'; 607 } else { 608 console.error('messageContainer element not found'); 609 } 610 } 611 } else { 612 console.error('Empty response'); 613 if (messageContainer) { 614 messageContainer.innerHTML = '<span style="color: red;">Empty response</span>'; 615 } else { 616 console.error('messageContainer element not found'); 617 } 618 } 619 } else { 620 console.error('Request failed with status:', xhr.status); 621 if (messageContainer) { 622 messageContainer.innerHTML = '<span style="color: red;">Error: ' + xhr.status + '</span>'; 623 } else { 624 console.error('messageContainer element not found'); 625 } 626 } 627 628 // Hide message after 3 seconds 629 setTimeout(function() { 630 if (messageContainer) { 631 messageContainer.innerHTML = ''; 632 } 633 }, 3000); 634 } 635 }; 636 637 638 xhr.send('action=ai_app_onsite_get_accept_terms_of_service&terms_of_service=' + terms_of_service+'&ai_app_onsite_plugin_settings_terms_of_service_nonce='+terms_of_service_nonce); 639 } 640 641 function toggleAppNameSelector() { 642 setTimeout(function() { 643 const app_selector_input_element = document.getElementById("app_selector"); 644 const appSelectorLabel = document.querySelector(".app_selector_input_label"); 645 646 if (app_selector_input_element && app_selector_input_element.value != '') { 647 appSelectorLabel.innerText = "Edit App Name"; 648 app_selector_input_element.classList.remove('border-danger'); 649 } else { 650 appSelectorLabel.innerHTML = 'Create Your First App <span class="text-danger">*</span>'; 651 app_selector_input_element.classList.add('border-danger'); 652 app_selector_input_element.setAttribute('placeholder', 'Please Enter Your App Name'); 653 } 654 }, 2000); 655 } 656 657 document.addEventListener('DOMContentLoaded', function() { 658 const licenseKeyInfoModal = document.getElementById("license_key_info_modal"); 659 const saveButton = document.getElementById("active_ai_app_plugin_license_key"); 660 const disableKeyBtn = document.getElementById("key-disable-btn"); 661 const messageContainer = document.getElementById("app-license-msg-container"); 662 const keyInput = document.getElementById('licence_key'); 663 664 document.addEventListener('keydown', function(event) { 665 if (event.key === 'Enter') { 666 event.preventDefault(); 667 } 668 }); 669 670 const currentStatus = !disableKeyBtn.checked ? 'enabled' : 'disabled'; 671 disableKeyBtn.setAttribute('data-original-status', currentStatus); 672 673 if (licenseKeyInfoModal) { 674 let isHidingModal = false; 675 let lastClickedElement = null; 676 const modalContent = licenseKeyInfoModal.querySelector('.modal-content'); 677 678 const showUnsavedWarning = () => { 679 saveButton?.classList.add("border-danger"); 680 messageContainer.innerHTML = '<span style="color: red;">You have unsaved changes, consider saving them.</span>'; 681 }; 682 683 const resetModalState = () => { 684 isSwitchChecked = false; 685 messageContainer.innerHTML = ""; 686 saveButton?.classList.remove("border-danger"); 687 }; 688 689 const handleCancelAction = () => { 690 isHidingModal = true; 691 if (isSwitchChecked) { 692 disableKeyBtn.checked = !disableKeyBtn.checked; 693 ai_app_onsite_disable_license_key(); 694 } 695 resetModalState(); 696 jQuery(licenseKeyInfoModal).modal('hide'); 697 isHidingModal = false; 698 }; 699 700 // Track the last clicked element 701 document.addEventListener('mousedown', (event) => { 702 lastClickedElement = event.target; 703 }); 704 705 706 // Intercept dismiss logic 707 licenseKeyInfoModal.addEventListener('hide.bs.modal', (event) => { 708 if (isHidingModal) return; 709 710 const isDismissButton = lastClickedElement?.getAttribute("data-bs-dismiss") === "modal"; 711 const isCancelButton = lastClickedElement?.id === "cancel"; 712 713 if (isDismissButton && isCancelButton) { 714 handleCancelAction(); 715 } else if (isSwitchChecked && lastClickedElement?.textContent?.trim() && lastClickedElement?.textContent !== "Save") { 716 event.preventDefault(); 717 showUnsavedWarning(); 718 } 719 }); 720 } 721 722 setTimeout(function() { 723 const app_selector_input_element = document.getElementById("app_selector"); 724 725 app_selector_input_element.addEventListener("input", function () { 726 if (app_selector_input_element.value.trim() !== "") { 727 app_selector_input_element.classList.remove("border-danger"); 728 } else { 729 app_selector_input_element.classList.add("border-danger"); 730 } 731 }); 732 }, 1000); 733 734 keyInput.addEventListener("input", function () { 735 if (keyInput.value.trim() !== "") { 736 saveButton?.removeAttribute('disabled'); 737 } else { 738 saveButton?.setAttribute('disabled', 'true'); 739 } 740 }); 741 742 743 var button = document.getElementById("accept_ai_app_terms_of_service"); 744 button.addEventListener("click", function () { 745 var terms_of_service = 746 document.getElementById("terms_conditions").checked; 747 var terms_of_service_nonce = document.getElementById( 748 "ai_app_onsite_plugin_settings_nonce_field" 749 ).value; 750 var xhr = new XMLHttpRequest(); // Initialize the XMLHttpRequest object 751 xhr.open("POST", myPluginAjax.ajaxurl, true); 752 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // Set the request header 753 754 var loader = document.getElementById("loader"); 755 loader.style.display = "flex"; 756 757 xhr.onreadystatechange = function () { 758 if (xhr.readyState === 4) { 759 // Ensure the request is complete 760 var messageContainer = 761 document.getElementById("Plugin-settings-msg-container") || 762 document.getElementById("messageContainer"); 763 if (xhr.status === 200) { 764 if (xhr.responseText) { 765 // Check if the response text is not empty 766 try { 767 var response = JSON.parse(xhr.responseText); 768 if (messageContainer) { 769 if (response.success) { 770 if (isPluginSaveTriggered) { 771 setTimeout(function () { 772 ai_app_onsite_save_plugin_settings(); 773 }, 1000); 774 } else { 775 loader.style.display = "none"; 776 messageContainer.innerHTML = 777 '<span style="color: green;">' + 778 response.data + 779 "</span>"; 780 } 781 } else { 782 loader.style.display = "none"; 783 messageContainer.innerHTML = 784 '<span style="color: red;">Error: ' + 785 response.error + 786 "</span>"; 787 } 788 } else { 789 loader.style.display = "none"; 790 console.error("messageContainer element not found"); 791 } 792 } catch (e) { 793 loader.style.display = "none"; 794 console.error("Failed to parse response:", e); 795 if (messageContainer) { 796 messageContainer.innerHTML = 797 '<span style="color: red;">Error parsing response</span>'; 798 } else { 799 console.error("messageContainer element not found"); 800 } 801 } 802 } else { 803 loader.style.display = "none"; 804 console.error("Empty response"); 805 if (messageContainer) { 806 messageContainer.innerHTML = 807 '<span style="color: red;">Empty response</span>'; 808 } else { 809 console.error("messageContainer element not found"); 810 } 811 } 812 } else { 813 loader.style.display = "none"; 814 console.error("Request failed with status:", xhr.status); 815 if (messageContainer) { 816 messageContainer.innerHTML = 817 '<span style="color: red;">Error: ' + xhr.status + "</span>"; 818 } else { 819 console.error("messageContainer element not found"); 820 } 821 } 822 823 // Hide message after 3 seconds 824 setTimeout(function () { 825 if (messageContainer) { 826 messageContainer.innerHTML = ""; 827 } 828 }, 3000); 829 } 830 }; 831 832 xhr.send( 833 "action=ai_app_onsite_get_accept_terms_of_service&terms_of_service=" + 834 terms_of_service + 835 "&ai_app_onsite_plugin_settings_terms_of_service_nonce=" + 836 terms_of_service_nonce 837 ); 838 }); 839 840 ai_app_onsite_get_plugin_settings(); 841 842 var licenseKeychange = document.getElementById('licence_key') 843 if (licenseKeychange) { 844 licenseKeychange.onchange = handleInputChange; 845 } 846 }); 847 /*=============End download user stats js=================================== */ 848 849 // LICENSE SETTING 850 const keyNote = document.getElementById('key_note'); 851 const licenseStatus = document.getElementById('license_status'); 852 const loader = document.getElementById('loader'); 853 const statusElem = document.getElementById('license_key_status'); 854 const messageContainer = document.getElementById('app-license-msg-container'); 855 const keyInput = document.getElementById('licence_key'); 856 const keyInputHd = document.getElementById('licence_key_hidden'); 857 const expiryElem = document.getElementById('license_key_expiry_date'); 858 const keyDisableStatusElem = document.getElementById('license_key_disabled_status'); 859 const removeBtn = document.getElementById('remove_ai_app_plugin_license_key'); 860 const expiryStatus = document.getElementById('expiry_status'); 861 const keyStatus = document.getElementById('key_status'); 862 const disableKeyBtn = document.getElementById("key-disable-btn"); 863 const licenseTextSwitch = document.getElementById('license-text-switch'); 864 865 function handleInputChange() { 866 if (keyInput.value) { 867 keyInputHd.value = keyInput.value; 868 869 ai_app_onsite_app_verify_license_key(); 870 } 871 } 872 873 // Initial state 874 setUIState('default'); 875 876 //==================== 877 // Helper Functions 878 //==================== 879 880 function formatDate(dateString) { 881 return new Date(dateString).toLocaleDateString('en-US', { 882 year: 'numeric', 883 month: 'long', 884 day: 'numeric', 885 }); 886 } 887 888 function ai_app_onsite_disable_license_key() { 889 // Enable or diabled License key status 890 const switch_status = disableKeyBtn.checked; 891 if(switch_status){ 892 licenseTextSwitch.textContent = 'Enabled'; 893 licenseTextSwitch.style.color = 'green'; 894 isSwitchChecked = true; // Mark as toggled 895 } else { 896 licenseTextSwitch.textContent = 'Disabled'; 897 licenseTextSwitch.style.color = 'red'; 898 isSwitchChecked = true; // Mark as toggled 899 } 900 } 901 902 function setUIState(state, data = {}) { 903 switch (state) { 904 case 'active': 905 case 'inactive': 906 const isActive = state === 'active'; 907 keyInput.disabled = true; 908 licenseStatus.style.display = 'block'; 909 expiryStatus.style.display = 'block'; 910 keyStatus.style.display = 'block'; 911 statusElem.textContent = isActive ? 'ACTIVE' : 'EXPIRED'; 912 statusElem.style.color = isActive ? 'green' : 'red'; 913 keyNote.style.display = 'none'; 914 removeBtn.classList.toggle('d-flex', true); 915 removeBtn.disabled = false; 916 expiryElem.textContent = formatDate(data.expiry); 917 keyDisableStatusElem.textContent = data.key_disable_status == 'false' ? 'Enabled' : 'Disabled'; 918 keyDisableStatusElem.style.color = data.key_disable_status == 'false' ? 'green' : 'red'; 919 disableKeyBtn.disabled = false; 920 disableKeyBtn.checked = data.key_disable_status == 'false'; 921 licenseTextSwitch.textContent = data.key_disable_status == 'false' ? 'Enabled' : 'Disabled'; 922 licenseTextSwitch.style.color = data.key_disable_status == 'false' ? 'green' : 'red'; 923 break; 924 925 case 'default': 926 default: 927 keyInput.disabled = false; 928 keyInput.value = ''; 929 keyInputHd.value = ''; 930 licenseStatus.style.display = 'none'; 931 expiryStatus.style.display = 'none'; 932 keyStatus.style.display = 'none'; 933 keyNote.style.display = 'block'; 934 removeBtn.classList.toggle('d-flex', true); 935 removeBtn.disabled = true; 936 expiryElem.textContent = ''; 937 keyDisableStatusElem.textContent = ''; 938 disableKeyBtn.checked = false; 939 disableKeyBtn.disabled = true; 940 licenseTextSwitch.textContent = 'Disabled'; 941 licenseTextSwitch.style.color = 'red'; 942 break; 943 } 944 } 945 946 function sendAjax(action, onSuccess) { 947 const xhr = new XMLHttpRequest(); 948 xhr.open('POST', myPluginAjax.ajaxurl, true); 949 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 950 951 xhr.onreadystatechange = () => { 952 if (xhr.readyState !== 4) return; 953 if (xhr.status === 200) { 954 try { 955 const response = JSON.parse(xhr.responseText); 956 onSuccess(response); 957 } catch (err) { 958 console.error('Invalid JSON response:', err); 959 alert('Unexpected response from server.'); 960 } 961 } else { 962 alert(`Error: ${xhr.status} ${xhr.statusText}`); 963 } 964 965 const licenseFormTracker = trackFormChanges('#license-validation-form'); 966 window.FormChangeRegistry.register('license_settings', licenseFormTracker, 'app-settings'); 967 968 document.getElementById('active_ai_app_plugin_license_key').addEventListener('click', function () { 969 licenseFormTracker.reset(); 970 }); 971 }; 972 973 xhr.send(`action=${encodeURIComponent(action)}`); 974 } 975 976 //==================== 977 // Fetch License Key 978 //==================== 979 function ai_app_onsite_get_app_license_key() { 980 const saveButton = document.getElementById("active_ai_app_plugin_license_key"); 981 982 sendAjax('ai_app_onsite_get_app_license_key', (response) => { 983 if (response.status === '404') { 984 saveButton?.setAttribute('disabled', 'true'); 985 return; 986 } 987 988 const { license_key, license_key_hd, key_status, subscription_expiry_date, key_disable_status } = response[0] || {}; 989 990 keyInput.value = license_key || ''; 991 keyInputHd.value = license_key_hd || ''; 992 993 if (key_status === 'ACTIVE') { 994 saveButton?.removeAttribute('disabled'); 995 setUIState('active', { expiry: subscription_expiry_date, key_disable_status: key_disable_status }); 996 } else if (key_status === 'INACTIVE' && license_key) { 997 saveButton?.removeAttribute('disabled'); 998 setUIState('inactive', { expiry: subscription_expiry_date, key_disable_status: key_disable_status }); 999 } else { 1000 saveButton?.setAttribute('disabled', 'true'); 1001 setUIState('default'); 1002 } 1003 toggleAppNameSelector(); 1004 }); 1005 } 1006 1007 //==================== 1008 // Remove License Key 1009 //==================== 1010 function ai_app_onsite_app_remove_license_key() { 1011 if (confirm("Warning: Removing the premium access key may cause your existing app to lose functionality. All PLUS features will be disabled within 24 hours. Are you sure you want to proceed?")) { 1012 loader.style.display = 'flex'; 1013 1014 sendAjax('ai_app_onsite_app_remove_license_key', (response) => { 1015 loader.style.display = 'none'; 1016 location.reload(true); 1017 setUIState('default'); 1018 }); 1019 } 1020 } 1021 1022 //==================== 1023 // Disable/Enable License Key 1024 //==================== 1025 function ai_app_onsite_app_toggle_license_key_status(status) { 1026 loader.style.display = 'flex'; 1027 1028 const xhr = new XMLHttpRequest(); 1029 xhr.open('POST', myPluginAjax.ajaxurl, true); 1030 1031 xhr.onreadystatechange = () => { 1032 loader.style.display = 'none'; 1033 1034 if (xhr.readyState !== 4) return; 1035 if (xhr.status === 200) { 1036 try { 1037 const response = JSON.parse(xhr.responseText); 1038 } catch (err) { 1039 console.error('Invalid JSON response:', err); 1040 } 1041 } else { 1042 alert(`Error: ${xhr.status} ${xhr.statusText}`); 1043 } 1044 }; 1045 1046 const formData = new FormData(); 1047 formData.append('action', 'ai_app_onsite_app_toggle_license_key_status'); 1048 formData.append('status', status); 1049 1050 xhr.send(formData); 1051 } 1052 1053 1054 //========[ Validate & Save License Key ]========// 1055 function ai_app_onsite_app_verify_license_key(close_modal = false) { 1056 const loader = document.getElementById('loader'); 1057 const saveButton = document.getElementById("active_ai_app_plugin_license_key"); 1058 1059 let licenceKey = document.getElementById('licence_key').value.trim(); 1060 const licenceKeyHidden = document.getElementById('licence_key_hidden').value.trim(); 1061 if (licenceKeyHidden && licenceKeyHidden.trim() !== '') { 1062 licenceKey = licenceKeyHidden; 1063 } 1064 const status = !disableKeyBtn.checked ? 'true' : 'false'; 1065 const nonce = document.getElementById("ai_app_onsite_app_verify_license_key_nonce_field").value; 1066 1067 // Clear error messages 1068 document.querySelectorAll('.fields-error').forEach(el => el.textContent = ''); 1069 loader.style.display = 'flex'; 1070 1071 const xhr = new XMLHttpRequest(); 1072 xhr.open('POST', myPluginAjax.ajaxurl, true); 1073 1074 xhr.onreadystatechange = () => { 1075 if (xhr.readyState !== 4) return; 1076 1077 setTimeout(function () { 1078 loader.style.display = 'none'; 1079 1080 let response; 1081 try { 1082 response = JSON.parse(xhr.responseText); 1083 } catch (e) { 1084 messageContainer.innerHTML = `<span style="color: red;">Invalid server response</span>`; 1085 return; 1086 } 1087 1088 if (xhr.status === 200) { 1089 if (response.success) { 1090 saveButton?.classList.remove("border-danger"); 1091 ai_app_onsite_get_app_license_key(); 1092 messageContainer.innerHTML = `<span style="color: green;">${response.data}</span>`; 1093 close_modal = true; 1094 } else { 1095 close_modal = false; 1096 messageContainer.innerHTML = `<span style="color: red;">Error: ${response.data}</span>`; 1097 } 1098 } else { 1099 close_modal = false; 1100 messageContainer.innerHTML = `<span style="color: red;">Error: Failed to verify data</span>`; 1101 } 1102 1103 setTimeout(function () { 1104 if(close_modal){ 1105 var modal = document.getElementById("license_key_info_modal"); 1106 jQuery(modal).modal("hide"); 1107 location.reload(true); 1108 messageContainer.innerHTML = ""; 1109 } 1110 1111 }, 3000); 1112 }, 2000); 1113 }; 1114 1115 const formData = new FormData(); 1116 formData.append('action', 'ai_app_onsite_app_verify_license_key'); 1117 formData.append('licence_key', licenceKey); 1118 formData.append('status', status); 1119 formData.append('ai_app_onsite_app_verify_license_key_nonce_field', nonce); 1120 1121 xhr.send(formData); 1122 } 1123 1124 window.FormChangeRegistry = { 1125 trackers: {}, 1126 tabMap: {}, 1127 1128 register: function (key, tracker, tabKey) { 1129 this.trackers[key] = tracker; 1130 1131 if (tabKey) { 1132 if (!this.tabMap[tabKey]) this.tabMap[tabKey] = []; 1133 this.tabMap[tabKey].push(key); 1134 } 1135 }, 1136 1137 isAnyDirty: function () { 1138 return Object.values(this.trackers).some(t => t.hasUnsavedChanges()); 1139 }, 1140 1141 isTabDirty: function (tabKey) { 1142 const tabKeys = this.tabMap[tabKey] || []; 1143 return tabKeys.some(key => this.trackers[key]?.hasUnsavedChanges()); 1144 }, 1145 1146 resetTab: function (tabKey) { 1147 const tabKeys = this.tabMap[tabKey] || []; 1148 tabKeys.forEach(key => this.trackers[key]?.reset()); 122 1149 } 123 1150 }; 124 125 xhr.open('POST', myPluginAjax.ajaxurl, true); 126 127 console.log(document.getElementById("app_email").value); 128 129 var formData = new FormData(); 130 formData.append('action', 'ai_app_onsite_save_plugin_settings'); 131 formData.append('terms_of_service', document.getElementById("terms_of_service-old") ? document.getElementById("terms_of_service-old").checked : false); 132 formData.append('app_selector', document.getElementById("app_selector") ? document.getElementById("app_selector").value : ""); 133 formData.append('app_email', document.getElementById("app_email") ? document.getElementById("app_email").value : ""); 134 135 136 // Gather selected banned words 137 var bannedWordsSelect = document.querySelector('[data-multi-select-plugin]'); 138 var selectedOptions = bannedWordsSelect.selectedOptions; 139 var banned_words = []; 140 let selectedLabels = document.querySelectorAll('.selected-wrapper .selected-label'); 141 142 // Loop through each of the selected labels 143 selectedLabels.forEach(function(label) { 144 banned_words.push(label.textContent); 145 }); 146 // Append each banned word to the formData object 147 for (var j = 0; j < banned_words.length; j++) { 148 formData.append('banned_words[]', banned_words[j]); 149 } 150 151 152 // Append the CSV file 153 const fileInput = document.getElementById('csv-upload'); 154 if (fileInput.files.length > 0) { 155 const file = fileInput.files[0]; 156 formData.append('csv-file', file); 157 } 158 159 // Append nonce field value 160 formData.append('ai_app_onsite_plugin_settings_nonce_field', document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value); 161 162 163 xhr.send(formData); 164 } 165 166 //=======================End save plugin settings js=========================== 167 168 //Start get plugin setting from db js 169 function ai_app_onsite_get_plugin_settings() { 170 var xhr = new XMLHttpRequest(); 171 172 xhr.onreadystatechange = function() { 173 if (xhr.readyState === 4) { 174 175 if (xhr.status === 200) { 176 // Handle success response 177 var response = JSON.parse(xhr.responseText); 178 if(response.status === '404'){ 179 //jQuery('#terms_conditions_modal').modal('show'); 180 const modalElement = document.getElementById('terms_conditions_modal'); 181 const modalInstance = new bootstrap.Modal(modalElement); 182 modalInstance.show(); 183 184 185 return; 186 } 187 188 // Accessing the first object in the array 189 var firstObject = response[0]; 190 191 // Accessing properties of the first object 192 var id = firstObject.id; 193 var agreeTerms = firstObject.agree_terms; 194 var appSelector = firstObject.app_selector; 195 var userStats = firstObject.user_stats; 196 var bannedWords = firstObject.banned_words; 197 var bannedWordsCSV = firstObject.banned_words_csv; 198 var appName = firstObject.appName; 199 const selectElement = document.getElementById('bannedWords'); 200 201 var app_email = firstObject.app_email; 202 203 204 // Assume selectElement is already defined as your target select element 205 bannedWordsCSV.forEach(item => { 206 // Check if an option with the same value already exists 207 const exists = Array.from(selectElement.options).some(option => option.value === item[0]); 208 209 if (!exists) { 210 // Create a new option element 211 const option = document.createElement('option'); 212 213 // Set the value and text of the option element 214 option.value = item[0]; 215 option.text = item[0]; 216 217 // Append the option element to the select element 218 selectElement.appendChild(option); 219 } 220 }); 221 222 if (appName != null && appName !== '' && appName !== 'undefined') { 223 var selectElements = document.getElementById('app_selector'); 224 selectElements.value = appName; 225 } 226 var app_emails = document.getElementById('app_email'); 227 app_emails.value = app_email; 228 229 // Set checkbox checked if agreeTerms is "1" 230 if (agreeTerms === "1") { 231 document.getElementById('terms_of_service-old').checked = true; 232 // Ensure the modal is not triggered 233 } else { 234 // Show the modal if terms are not agreed to 235 const modalElement = document.getElementById('terms_conditions_modal'); 236 const modalInstance = new bootstrap.Modal(modalElement); 237 modalInstance.show(); 238 } 239 240 var searchContainer = document.querySelector('.search-container'); 241 242 console.log('bannedWords', bannedWords); 243 // 244 // document.addEventListener('DOMContentLoaded', function() { 245 var searchContainer = document.querySelector('.search-container'); // Ensure the selector is correct 246 if (!searchContainer) { 247 console.error('searchContainer element not found!'); 248 return; // Exit if the container is missing 249 } 250 bannedWords.forEach(function(value) { 251 console.log('value', value); 252 if (value) { // Ensure value is not empty or falsy 253 var exists = document.querySelector('.selected-wrapper span.selected-label[data-value="' + value + '"]'); 254 if (!exists) { 255 // Create new elements only if the value is not empty and doesn't already exist 256 var newDiv = document.createElement('div'); 257 newDiv.className = 'selected-wrapper'; 258 259 var labelSpan = document.createElement('span'); 260 labelSpan.className = 'selected-label'; 261 labelSpan.textContent = value; 262 labelSpan.setAttribute('data-value', value); 263 264 var closeLink = document.createElement('a'); 265 closeLink.className = 'selected-close'; 266 closeLink.setAttribute('tabindex', '-1'); 267 closeLink.setAttribute('data-option', value); 268 closeLink.setAttribute('data-hits', '0'); 269 closeLink.href = '#'; 270 closeLink.textContent = 'x'; 271 272 newDiv.appendChild(labelSpan); 273 newDiv.appendChild(closeLink); 274 searchContainer.before(newDiv); // Ensure searchContainer exists before this line 275 } 276 } 277 }); 278 // }); 279 280 281 282 283 284 document.querySelectorAll('.selected-wrapper').forEach(wrapper => { 285 const label = wrapper.querySelector('.selected-label'); 286 if (!label.hasAttribute('data-value')) { 287 wrapper.remove(); 288 } 289 }); 290 291 292 // Event listener for the dropdown icon click 293 const dropdownIcon = document.querySelector('.dropdown-icon'); 294 if (dropdownIcon) { 295 dropdownIcon.addEventListener('click', function() { 296 console.log('Dropdown icon clicked'); 297 if (this.classList.contains('active')) { 298 console.log('Dropdown icon is active'); 299 document.querySelectorAll('.selected-wrapper .selected-label').forEach(function(element) { 300 var valueToRemove = element.textContent.trim(); 301 console.log('Removing:', valueToRemove); 302 document.querySelectorAll('.autocomplete-list li').forEach(function(liElement) { 303 if (liElement.textContent.trim() === valueToRemove) { 304 console.log('Found and removing li:', liElement.textContent.trim()); 305 liElement.parentNode.removeChild(liElement); 306 } 307 }); 308 }); 309 } else { 310 console.log('Dropdown icon is not active'); 311 } 312 }); 313 } else { 314 console.log('Dropdown icon not found'); 315 } 316 317 318 319 320 321 } else { 322 // Handle error response 323 alert('Error occurred: ' + xhr.responseText); 324 } 325 } 326 }; 327 328 xhr.open('POST', myPluginAjax.ajaxurl, true); 329 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 330 xhr.send('action=ai_app_onsite_get_plugin_settings'); 331 } 332 333 ai_app_onsite_get_plugin_settings(); 334 /*=============End get plugin setting from db js============================== */ 335 336 337 /*=============Download terms Of service js=================================== */ 338 339 function ai_app_onsite_download_terms_Of_service() { 340 const { jsPDF } = window.jspdf; 341 const doc = new jsPDF(); 342 const termsContent = document.getElementById('terms-conditions-modal-pdf').innerText; 343 344 const maxWidth = 180; // Maximum width for text in mm 345 const startX = 10; // X-coordinate to start text 346 const startY = 10; // Y-coordinate to start text 347 const lineHeight = 4.5; // Approximate line height in mm 348 const pageHeight = 297; // A4 page height in mm (210x297mm) 349 const marginBottom = 10; // Bottom margin 350 351 let cursorY = startY; // Track current Y-coordinate 352 353 // Set font size 354 const fontSize = 12; // Set the font size as desired 355 doc.setFontSize(fontSize); 356 357 // Split text into lines that fit within the specified max width 358 const lines = doc.splitTextToSize(termsContent, maxWidth); 359 360 // Add the lines of text to the PDF 361 lines.forEach(line => { 362 if (cursorY + lineHeight > pageHeight - marginBottom) { 363 // Add new page if the text exceeds the page height 364 doc.addPage(); 365 cursorY = startY; // Reset cursorY for new page 366 } 367 doc.text(line, startX, cursorY); 368 cursorY += lineHeight * (fontSize / 10); // Adjust cursorY based on font size 369 }); 370 doc.save('AIappOniste-terms-of-service.pdf'); 371 } 372 373 /*=============End download terms Of service js=================================== */ 374 375 376 /*=============Download user stats js=================================== */ 377 function ai_app_onsite_download_user_stats(event) { 378 event.preventDefault(); 379 // Show loader 380 document.getElementById('loader').style.display = 'flex'; 381 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 382 383 // Get the selected month (e.g., from a dropdown or an input) 384 const month = document.getElementById('ai_app_onsite-user-stats').value; 385 var userStatsError = document.getElementById('ai_app_onsite-user-stats-error'); 386 userStatsError.textContent = ''; 387 var ai_app_onsite_download_user_stats_nonce = myPluginAjax.downloadUserStatsNonce; 388 389 // Prepare data to send 390 const data = new FormData(); 391 data.append('ai_app_onsite_download_user_stats_nonce', ai_app_onsite_download_user_stats_nonce); // Correctly use the nonce variable 392 data.append('action', 'ai_app_onsite_download_user_stats'); // Action name 393 data.append('month', month); // Pass the month value 394 // Make AJAX request 395 fetch(ajaxurl, { 396 method: 'POST', 397 body: data, 398 }) 399 .then(response => { 400 if (!response.ok) { 401 throw new Error('Network response was not ok'); 402 } 403 return response.text(); // Read response as text 404 }) 405 .then(text => { 406 // Hide loader after a delay (e.g., 1 second) 407 setTimeout(() => { 408 document.getElementById('loader').style.display = 'none'; 409 410 // Check if the response indicates failure and no data found 411 if (text.includes('No user statistics found.')) { 412 // Show error message 413 userStatsError.textContent = 'No user statistics found.'; 414 } else { 415 // Create a blob from the response text 416 const blob = new Blob([text], { type: 'text/csv' }); 417 418 // Create a link element 419 const url = window.URL.createObjectURL(blob); 420 const a = document.createElement('a'); 421 a.style.display = 'none'; 422 a.href = url; 423 a.download = 'AIappOniste_User_Stats.csv'; 424 425 // Append the link to the body 426 document.body.appendChild(a); 427 a.click(); 428 429 // Remove the link 430 document.body.removeChild(a); 431 432 // Revoke the object URL 433 window.URL.revokeObjectURL(url); 434 435 console.log('User stats downloaded successfully'); 436 messageContainer.innerHTML = '<span style="color: green;">User stats downloaded successfully</span>'; 437 438 } 439 setTimeout(function() { 440 messageContainer.innerHTML = ''; 441 }, 3000); 442 }, 2000); // Adjust delay time as needed 443 }) 444 .catch(error => { 445 // Hide loader 446 document.getElementById('loader').style.display = 'none'; 447 448 // Show error message 449 document.getElementById('ai_app_onsite-user-stats-error').textContent = 'Error: ' + error.message; 450 }); 451 } 452 453 // Function to clear error message when month selection is changed 454 // document.getElementById('ai_app_onsite-user-stats').addEventListener('change', function() { 455 // document.getElementById('ai_app_onsite-user-stats-error').textContent = ''; 456 // }); 457 458 //upload file js 459 function validateCSVFile(input) { 460 var file = document.getElementById('csv-upload').files[0]; 461 var fileError = document.getElementById('fileError'); 462 // Check if file is selected 463 if (!file) { 464 fileError.textContent = 'Please select a file.'; 465 return; 466 } 467 468 // Check file type 469 var validExtensions = ['text/csv']; 470 if (!validExtensions.includes(file.type)) { 471 fileError.textContent = 'Please select a valid image file (SVG, PNG, JPG, or GIF).'; 472 this.value = ''; // Clear the input field 1151 1152 let pendingTabSwitch = null; 1153 let currentTab = null; 1154 1155 document.querySelectorAll('.plugin-tab').forEach(tab => { 1156 tab.addEventListener('click', function (e) { 1157 e.preventDefault(); 1158 1159 const targetTabId = this.getAttribute('data-tab-id'); 1160 const targetTab = this.getAttribute('data-form-tab'); 1161 const activeTab = document.querySelector('.plugin-tab.nav-tab-active')?.getAttribute('data-form-tab'); 1162 1163 // window.FormChangeRegistry.trackers[activeTab]?.deactivate(); 1164 // window.FormChangeRegistry.trackers[targetTab]?.activate(); 1165 1166 if (activeTab && window.FormChangeRegistry.isTabDirty(activeTab)) { 1167 pendingTabSwitch = targetTab; 1168 currentTab = activeTab; 1169 1170 // Store targetTabId to proceed later 1171 window._deferredTabClick = targetTabId; 1172 1173 const modal = new bootstrap.Modal(document.getElementById('unsavedChangesModal')); 1174 modal.show(); 1175 } else { 1176 handleTabClick(targetTabId); 1177 } 1178 }); 1179 }); 1180 1181 document.querySelectorAll('.dismiss-unsaved-modal').forEach(button => { 1182 button.addEventListener('click', function () { 1183 const modalElement = document.getElementById('unsavedChangesModal'); 1184 const modalInstance = bootstrap.Modal.getInstance(modalElement); 1185 1186 if (modalInstance) { 1187 modalInstance.hide(); 1188 1189 setTimeout(() => { 1190 if (!document.querySelector('.modal.show')) { 1191 document.querySelectorAll('.modal-backdrop').forEach(el => el.remove()); 1192 document.body.classList.remove('modal-open'); 1193 document.body.style.overflow = ''; 1194 } 1195 1196 window.FormChangeRegistry.resetTab(currentTab); 1197 1198 if (window._deferredTabClick) { 1199 handleTabClick(window._deferredTabClick); 1200 window._deferredTabClick = null; 1201 currentTab = null; 1202 pendingTabSwitch = null; 1203 } 1204 }, 400); 1205 } 1206 }); 1207 }); 1208 1209 document.querySelectorAll('.save-changes-modal').forEach(button => { 1210 button.addEventListener('click', function () { 1211 const modalElement = document.getElementById('unsavedChangesModal'); 1212 const modalInstance = bootstrap.Modal.getInstance(modalElement); 1213 1214 if (modalInstance) { 1215 switch (currentTab) { 1216 case 'app-settings': 1217 ai_app_onsite_save_plugin_settings(); 1218 break; 1219 case 'app-details': 1220 ai_app_onsite_save_app_properties(); 1221 break; 1222 case 'model-settings': 1223 ai_app_onsite_save_model_settings(); 1224 break; 1225 case 'field-selector': 1226 ai_app_onsite_save_ai_app_fieldselector_data(); 1227 break; 1228 case 'prompt-editor': 1229 ai_app_onsite_save_prompt_editor(); 1230 break; 1231 case 'app-preview': 1232 ai_app_onsite_update_style_properties_only(); 1233 break; 1234 default: 1235 console.warn('No matching save method for the current tab:', currentTab); 1236 } 1237 1238 modalInstance.hide(); 1239 1240 setTimeout(() => { 1241 if (!document.querySelector('.modal.show')) { 1242 document.querySelectorAll('.modal-backdrop').forEach(el => el.remove()); 1243 document.body.classList.remove('modal-open'); 1244 document.body.style.overflow = ''; 1245 } 1246 1247 window.FormChangeRegistry.resetTab(currentTab); 1248 1249 if (window._deferredTabClick) { 1250 handleTabClick(window._deferredTabClick); 1251 window._deferredTabClick = null; 1252 currentTab = null; 1253 pendingTabSwitch = null; 1254 } 1255 }, 400); 1256 } 1257 }); 1258 }); 1259 1260 function activatePluginTab(tabName) { 1261 document.querySelectorAll('.plugin-tab-content').forEach(el => el.classList.add('d-none')); 1262 document.getElementById(`tab-content-${tabName}`)?.classList.remove('d-none'); 1263 1264 document.querySelectorAll('.plugin-tab').forEach(el => el.classList.remove('nav-tab-active')); 1265 document.querySelector(`.plugin-tab[data-form-tab="${tabName}"]`)?.classList.add('nav-tab-active'); 1266 } 1267 1268 // Tracker Utility 1269 function trackFormChanges(formSelector, options = {}) { 1270 const form = typeof formSelector === 'string' ? document.querySelector(formSelector) : formSelector; 1271 if (!form) return; 1272 1273 const config = { 1274 warnOnLeave: false, 1275 customWarningMessage: 'You have unsaved changes.', 1276 onChange: null, 1277 ...options, 1278 }; 1279 1280 let initialState = {}; 1281 let isDirty = false; 1282 1283 const getFieldValue = (field) => { 1284 if (field.type === 'color') return; 1285 if (field.type === 'radio') { 1286 const selected = document.querySelector(`input[name="${field.name}"]:checked`); 1287 return selected ? selected.value : ''; 1288 } 1289 if (field.type === 'checkbox') { 1290 return field.checked; 1291 } 1292 if (field.type === 'file') { 1293 return Array.from(field.files).map(file => file.name).join(',') || ''; 1294 } 1295 if (field.tagName === 'TEXTAREA') { 1296 return field.value.trim(); 1297 } 1298 if (field.tagName === 'SELECT') { 1299 if (field.multiple) { 1300 return Array.from(field.selectedOptions).map(option => option.value).join(','); 1301 } 1302 return field.value; 1303 } 1304 return field.value.trim(); 1305 }; 1306 1307 const getCurrentFormState = () => { 1308 const state = {}; 1309 form.querySelectorAll('input, textarea, select').forEach(field => { 1310 if (field.name) { 1311 const value = getFieldValue(field); 1312 if (value !== undefined) { 1313 state[field.name] = value; 1314 } 1315 } 1316 }); 1317 return state; 1318 }; 1319 1320 const captureInitialState = () => { 1321 initialState = getCurrentFormState(); 1322 }; 1323 1324 const hasChanged = () => { 1325 const currentState = getCurrentFormState(); 473 1326 474 return; 475 } 476 477 fileError.textContent = ''; // Clear any previous errors 478 479 uploadCSVFile(file); 480 // Reset input value to allow same file to be selected again 481 input.value = ''; 482 } 483 484 485 function uploadCSVFile(file) { 486 var formData = new FormData(); 487 formData.append('csv-file', file); 488 formData.append('action', 'ai_app_onsite_handle_csv_upload'); 489 formData.append('ai_app_onsite_plugin_settings_nonce_csv_upload_field', document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value); 490 491 var xhr = new XMLHttpRequest(); 492 xhr.open('POST', myPluginAjax.ajaxurl, true); 493 494 xhr.onreadystatechange = function () { 495 if (xhr.readyState === 4) { // Ensure the request is complete 496 if (xhr.status === 200) { 497 console.log('Response Text:', xhr.responseText); // Log the raw response text 498 499 if (xhr.responseText) { // Check if the response text is not empty 500 try { 501 var response = JSON.parse(xhr.responseText); 502 var messageContainer = document.getElementById('Plugin-settings-msg-container'); 503 if (messageContainer) { 504 if (response.success) { 505 messageContainer.innerHTML = '<span style="color: green;">' + response.data + '</span>'; 506 } else { 507 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 508 } 509 ai_app_onsite_get_plugin_settings(); 510 511 } else { 512 console.error('messageContainer element not found'); 513 } 514 } catch (e) { 515 console.error('Failed to parse response:', e); 516 var messageContainer = document.getElementById('messageContainer'); 517 if (messageContainer) { 518 messageContainer.innerHTML = '<span style="color: red;">Error parsing response</span>'; 519 } else { 520 console.error('messageContainer element not found'); 521 } 522 } 523 } else { 524 console.error('Empty response'); 525 var messageContainer = document.getElementById('messageContainer'); 526 if (messageContainer) { 527 messageContainer.innerHTML = '<span style="color: red;">Empty response</span>'; 528 } else { 529 console.error('messageContainer element not found'); 530 } 531 } 532 } else { 533 console.error('Request failed with status:', xhr.status); 534 var messageContainer = document.getElementById('messageContainer'); 535 if (messageContainer) { 536 messageContainer.innerHTML = '<span style="color: red;">Error: ' + xhr.status + '</span>'; 537 } else { 538 console.error('messageContainer element not found'); 539 } 540 } 541 // Hide message after 3 seconds 542 setTimeout(function() { 543 messageContainer.innerHTML = ''; 544 }, 3000); 545 546 547 } 548 }; 549 550 xhr.send(formData); 551 } 552 553 function uploadTermCondition(checkbox) { 554 var terms_of_service = document.getElementById("terms_of_service-old").checked; 555 var terms_of_service_nonce = document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value; 556 var xhr = new XMLHttpRequest(); // Initialize the XMLHttpRequest object 557 xhr.open('POST', myPluginAjax.ajaxurl, true); 558 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // Set the request header 559 560 xhr.onreadystatechange = function () { 561 if (xhr.readyState === 4) { // Ensure the request is complete 562 var messageContainer = document.getElementById('Plugin-settings-msg-container') || document.getElementById('messageContainer'); 563 if (xhr.status === 200) { 564 console.log('Response Text:', xhr.responseText); // Log the raw response text 565 566 if (xhr.responseText) { // Check if the response text is not empty 567 try { 568 var response = JSON.parse(xhr.responseText); 569 if (messageContainer) { 570 if (response.success) { 571 messageContainer.innerHTML = '<span style="color: green;">' + response.data + '</span>'; 572 } else { 573 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 574 } 575 } else { 576 console.error('messageContainer element not found'); 577 } 578 } catch (e) { 579 console.error('Failed to parse response:', e); 580 if (messageContainer) { 581 messageContainer.innerHTML = '<span style="color: red;">Error parsing response</span>'; 582 } else { 583 console.error('messageContainer element not found'); 584 } 585 } 586 } else { 587 console.error('Empty response'); 588 if (messageContainer) { 589 messageContainer.innerHTML = '<span style="color: red;">Empty response</span>'; 590 } else { 591 console.error('messageContainer element not found'); 592 } 593 } 594 } else { 595 console.error('Request failed with status:', xhr.status); 596 if (messageContainer) { 597 messageContainer.innerHTML = '<span style="color: red;">Error: ' + xhr.status + '</span>'; 598 } else { 599 console.error('messageContainer element not found'); 600 } 601 } 602 603 // Hide message after 3 seconds 604 setTimeout(function() { 605 if (messageContainer) { 606 messageContainer.innerHTML = ''; 607 } 608 }, 3000); 609 } 610 }; 611 612 613 xhr.send('action=ai_app_onsite_get_accept_terms_of_service&terms_of_service=' + terms_of_service+'&ai_app_onsite_plugin_settings_terms_of_service_nonce='+terms_of_service_nonce); 614 } 615 616 document.addEventListener('DOMContentLoaded', function() { 617 618 var button = document.getElementById('accept_ai_app_terms_of_service'); 619 button.addEventListener('click', function() { 620 var terms_of_service = document.getElementById("terms_conditions").checked; 621 var terms_of_service_nonce = document.getElementById("ai_app_onsite_plugin_settings_nonce_field").value; 622 var xhr = new XMLHttpRequest(); // Initialize the XMLHttpRequest object 623 xhr.open('POST', myPluginAjax.ajaxurl, true); 624 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); // Set the request header 625 626 xhr.onreadystatechange = function () { 627 if (xhr.readyState === 4) { // Ensure the request is complete 628 var messageContainer = document.getElementById('Plugin-settings-msg-container') || document.getElementById('messageContainer'); 629 if (xhr.status === 200) { 630 console.log('Response Text:', xhr.responseText); // Log the raw response text 631 632 if (xhr.responseText) { // Check if the response text is not empty 633 try { 634 var response = JSON.parse(xhr.responseText); 635 if (messageContainer) { 636 if (response.success) { 637 messageContainer.innerHTML = '<span style="color: green;">' + response.data + '</span>'; 638 } else { 639 messageContainer.innerHTML = '<span style="color: red;">Error: ' + response.error + '</span>'; 640 } 641 } else { 642 console.error('messageContainer element not found'); 643 } 644 } catch (e) { 645 console.error('Failed to parse response:', e); 646 if (messageContainer) { 647 messageContainer.innerHTML = '<span style="color: red;">Error parsing response</span>'; 648 } else { 649 console.error('messageContainer element not found'); 650 } 651 } 652 } else { 653 console.error('Empty response'); 654 if (messageContainer) { 655 messageContainer.innerHTML = '<span style="color: red;">Empty response</span>'; 656 } else { 657 console.error('messageContainer element not found'); 658 } 659 } 660 } else { 661 console.error('Request failed with status:', xhr.status); 662 if (messageContainer) { 663 messageContainer.innerHTML = '<span style="color: red;">Error: ' + xhr.status + '</span>'; 664 } else { 665 console.error('messageContainer element not found'); 666 } 667 } 668 669 // Hide message after 3 seconds 670 setTimeout(function() { 671 if (messageContainer) { 672 messageContainer.innerHTML = ''; 673 } 674 }, 3000); 675 } 676 }; 677 678 xhr.send('action=ai_app_onsite_get_accept_terms_of_service&terms_of_service=' + terms_of_service+'&ai_app_onsite_plugin_settings_terms_of_service_nonce='+terms_of_service_nonce); 679 680 }); 681 682 683 684 }); 685 /*=============End download user stats js=================================== */ 1327 for (let key in initialState) { 1328 if (initialState.hasOwnProperty(key)) { 1329 if (initialState[key] !== currentState[key]) { 1330 return true; 1331 } 1332 } 1333 } 1334 1335 return false; 1336 }; 1337 1338 const markDirty = () => { 1339 isDirty = hasChanged(); 1340 if (typeof config.onChange === 'function') config.onChange(isDirty); 1341 }; 1342 1343 const bindListeners = () => { 1344 form.querySelectorAll('input, textarea, select').forEach(field => { 1345 field.addEventListener('input', markDirty); 1346 field.addEventListener('change', markDirty); 1347 }); 1348 }; 1349 1350 const observer = new MutationObserver(() => { 1351 bindListeners(); 1352 markDirty(); 1353 }); 1354 1355 observer.observe(form, { childList: true, subtree: true }); 1356 1357 captureInitialState(); 1358 bindListeners(); 1359 1360 return { 1361 activate: () => { 1362 active = true; 1363 captureInitialState(); 1364 }, 1365 deactivate: () => { 1366 active = false; 1367 }, 1368 reset: () => { 1369 captureInitialState(); 1370 isDirty = false; 1371 }, 1372 hasUnsavedChanges: () => isDirty, 1373 markDirty: () => markDirty 1374 }; 1375 } 1376 1377 -
ai-app-onsite/trunk/assets/js/ai-app-onsite-prompt-editor.js
r3281194 r3307540 6 6 var aiResponseTone = document.getElementById('ai-response-tone'); 7 7 var egAiOutput = document.getElementById('eg-ai-output'); 8 8 let initialPromptContent = ''; 9 let appPromptFormTracker = null; 9 10 10 11 function onChangePromptInput() { … … 19 20 // Use TinyMCE API to get the content of the WYSIWYG editor 20 21 var promptInputValue = tinymce.get('prompt').getContent({ format: 'text' }).trim(); // 'prompt' is the editor ID 21 console.log('Prompt Input Value:', promptInputValue); // Log to check the input value22 22 23 23 // Target the error message container 24 24 var promptError = document.querySelector('.prompt-error'); // Ensure this selector is correct for your error display element 25 console.log('Prompt Error Element:', promptError); // Log to verify that the error container is found26 25 27 26 var errors = []; … … 122 121 123 122 if (response.status === '404') { 123 if (typeof tinymce !== "undefined" && tinymce.get('prompt')) { 124 tinymce.get('prompt').setContent(''); // Set content to the TinyMCE editor 125 } 126 promptInput.value = ''; 124 127 return; 125 128 } … … 127 130 // Accessing the first object in the array 128 131 var firstObject = response[0]; 129 // console.log('firstObject =', firstObject);130 132 131 133 // Access properties of the first object … … 139 141 if (typeof tinymce !== "undefined" && tinymce.get('prompt')) { 140 142 tinymce.get('prompt').setContent(prompt_html); // Set content to the TinyMCE editor 143 141 144 } else { 142 145 // If TinyMCE is not initialized, set the value directly to the textarea 143 146 promptInput.value = prompt_html; 144 147 } 148 initialPromptContent = normalizeContent(prompt_html); 145 149 146 150 if (ai_response_style) { … … 176 180 //Start save model settings JS 177 181 function ai_app_onsite_save_prompt_editor() { 178 179 // console.log('v1');180 182 181 183 //check Prompt value … … 233 235 } 234 236 235 // console.log('promptInputValue = ', promptInputValue);236 237 237 var aiResponseStyleValue = aiResponseStyle ? aiResponseStyle.value.trim() : ''; 238 238 var aiResponseToneValue = aiResponseTone ? aiResponseTone.value.trim() : ''; … … 252 252 } 253 253 254 255 // Wait for the DOM to fully load256 254 document.addEventListener("DOMContentLoaded", function () { 257 258 // Make sure TinyMCE is available259 255 if (typeof tinymce !== "undefined") { 260 // Initialize the TinyMCE editor 261 tinymce.init({ 262 selector: '#prompt', // Target the wp_editor's textarea by editor_id 263 setup: function (editor) { 264 // Listen for changes in the editor content 265 editor.on('change', function () { 266 // Call your custom JavaScript function 267 onChangePromptInput(); 256 tinymce.on('AddEditor', function (e) { 257 if (e.editor.id === 'prompt') { 258 const editor = e.editor; 259 260 editor.on('init', function () { 261 // Setup form tracker 262 appPromptFormTracker = trackFormChanges('#prompt-editor'); 263 window.FormChangeRegistry.register('app_prompt_settings', appPromptFormTracker, 'prompt-editor'); 264 265 document.getElementById('ai_app_onsite_save_prompt_editor').addEventListener('click', function (e) { 266 e.preventDefault(); 267 268 appPromptFormTracker.reset(); 269 ai_app_onsite_save_prompt_editor(); 270 }); 268 271 }); 272 273 editor.on('input change undo redo', function () { 274 const currentContent = normalizeContent(editor.getContent({ format: 'html' })); 275 if (currentContent !== initialPromptContent) { 276 document.querySelector('textarea[name="editor_prompt_aiapp"]').value = editor.getContent(); // store actual HTML or raw value 277 appPromptFormTracker.markDirty(); 278 } else { 279 appPromptFormTracker.reset(); 280 } 281 }); 269 282 } 270 283 }); 284 }else { 285 if (promptError) { 286 promptError.innerHTML = 'For best performance please install the <a href="https://wordpress.org/plugins/classic-editor/" target="_blank">Classic Editor</a> WP plugin.'; 287 } 271 288 } 272 289 }); 273 290 274 275 291 // Normalization function 292 function normalizeContent(content) { 293 return content.replace(/\u00a0/g, ' ') // 294 .replace(/[\r\n]+/g, ' ') // newlines 295 .replace(/\s+/g, ' ') // multiple spaces to one 296 .trim(); 297 } 298 299 300 301 302 303 304 305 306 307 308 -
ai-app-onsite/trunk/assets/js/ai-app-onsite-reset-localstorage.js
r3250856 r3307540 2 2 document.querySelectorAll('.deactivate a').forEach(function(element) { 3 3 element.addEventListener('click', function(e) { 4 var pluginSlug = 'ai-app-onsite/ai-app-onsite.php'; // Replace with your plugin slug5 4 var href = this.getAttribute('href'); 6 5 e.preventDefault(); // Prevent the default deactivation action … … 9 8 localStorage.setItem("settings", "{}"); // or use a default settings JSON object 10 9 localStorage.setItem("app_Title_gutenberg_block", ""); 11 console.log("LocalStorage keys have been reset");12 10 } 13 window.location.href = href; // Proceed with the deactivation 14 15 11 window.location.href = href; // Proceed with the deactivation 16 12 }); 17 13 }); -
ai-app-onsite/trunk/handler/ai-app-onsite-app-preview.php
r3281194 r3307540 22 22 global $wpdb; 23 23 $table_appropriate = $wpdb->prefix . 'ai_app_onsite_app_properties'; 24 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate ", ARRAY_A);24 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate WHERE app_id = 1", ARRAY_A); 25 25 if (empty($appropriates)) { 26 //error_log('No data found in app properties');26 error_log('No data found in app properties'); 27 27 return; 28 28 } 29 29 30 $is_preview = isset($_POST['is_preview_button']) && $_POST['is_preview_button'] === 'true'; 30 31 … … 32 33 $appropriates[0]['font_color'] = ($is_preview && isset($_POST['font_color'])) ? $_POST['font_color'] : $appropriates[0]['font_color']; 33 34 $appropriates[0]['bg_color'] = ($is_preview && isset($_POST['background_color'])) ? $_POST['background_color'] : $appropriates[0]['bg_color']; 34 35 $appropriates[0]['app_corner'] = ($is_preview && isset($_POST['app_corner'])) ? $_POST['app_corner'] : $appropriates[0]['app_corner']; 36 $appropriates[0]['app_height'] = ($is_preview && isset($_POST['app_height'])) ? $_POST['app_height'] : $appropriates[0]['app_height']; 37 38 $titleColors = json_decode($appropriates[0]['title_color'], true); 39 $fontColors = json_decode($appropriates[0]['font_color'], true); 40 $bgColors = json_decode($appropriates[0]['bg_color'], true); 41 $appCorner = $appropriates[0]['app_corner']; 42 $appHeight = $appropriates[0]['app_height']; 43 44 35 $appropriates[0]['app_corner'] = ($is_preview && isset($_POST['app_corner'])) ? $_POST['app_corner'] : $appropriates[0]['app_corner']; 36 $appropriates[0]['app_height'] = ($is_preview && isset($_POST['app_height'])) ? $_POST['app_height'] : $appropriates[0]['app_height']; 37 38 $titleColors = isset($appropriates[0]['title_color']) ? json_decode($appropriates[0]['title_color'], true) : null; 39 $fontColors = isset($appropriates[0]['font_color']) ? json_decode($appropriates[0]['font_color'], true) : null; 40 $bgColors = isset($appropriates[0]['bg_color']) ? json_decode($appropriates[0]['bg_color'], true) : null; 41 $appCorner = $appropriates[0]['app_corner']; 42 $appHeight = $appropriates[0]['app_height']; 45 43 46 44 $title_color_selected = null; 47 $font_color_selected = null;48 $bg_color_selected = null;49 $app_corner_selected = null;50 $app_height_selected = null;45 $font_color_selected = null; 46 $bg_color_selected = null; 47 $app_corner_selected = null; 48 $app_height_selected = null; 51 49 52 50 if(!is_null($titleColors)) { … … 94 92 95 93 $this->appProperty = [ 96 'app_name' => $appropriates[0]['app_name'],97 'app_logo' => $appropriates[0]['app_logo'],98 'app_disclaimer' => $appropriates[0]['app_disclaimer'],99 'app_description' => $appropriates[0]['app_description'],100 'submit_button_txt' => $appropriates[0]['submit_button_txt'],101 'title_color' => 'style="color:' . $title_color . ';"',102 'font_color' => 'style="color:' . $font_color . ';"',103 'small_font_color' => 'style="color:' . $font_color . '; opacity:0.5;"',94 'app_name' => $appropriates[0]['app_name'], 95 'app_logo' => $appropriates[0]['app_logo'], 96 'app_disclaimer' => $appropriates[0]['app_disclaimer'], 97 'app_description' => $appropriates[0]['app_description'], 98 'submit_button_txt' => $appropriates[0]['submit_button_txt'], 99 'title_color' => 'style="color:' . $title_color . ';"', 100 'font_color' => 'style="color:' . $font_color . ';"', 101 'small_font_color' => 'style="color:' . $font_color . '; opacity:0.5;"', 104 102 'app_description_color' => 'style="color:' . $font_color . '; opacity:0.5; text-align: center; font-size: 20px;"', 105 'background_color' => $background_color, 106 'btn_color' => 'style="background-color:' . $title_color . ';"' 103 'background_color' => $background_color, 104 'btn_color' => 'style="background-color:' . $title_color . ';"', 105 'short_code_genrated' => $appropriates[0]['short_code_genrated'] 107 106 ]; 108 107 … … 136 135 break; 137 136 } 138 139 137 140 138 //New Logic … … 144 142 } 145 143 if ($appName !== "aiapp") { 146 147 144 $shortCodeGenrated = $appropriates[0]['short_code_genrated']; 148 145 … … 172 169 } 173 170 171 private function ai_app_onsite_json_error_404($message) { 172 wp_send_json(array( 173 'status' => '404', 174 'message' => $message 175 )); 176 } 177 174 178 // AJAX callback function 175 179 public function ai_app_onsite_create_app_preview_form() … … 178 182 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_field_selector_settings'; 179 183 $table_name_app_properties = $wpdb->prefix . 'ai_app_onsite_app_properties'; 180 181 // if $this->appProperty is not initialized return 182 if (empty($this->appProperty)) { 183 wp_send_json_error('App properties are not initialized.'); 184 return; 185 } 186 187 188 // Check if the table exists 189 if ($wpdb->get_var("SHOW TABLES LIKE '$table_name_settings'") != $table_name_settings) { 190 $results = array('status' => '404', 'message' => 'No App found'); 191 wp_send_json($results); 192 } 193 194 // Check if the table has rows 195 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings"); 196 if ($rows_count == 0) { 197 $results = array('status' => '404', 'message' => 'No rows found in the table.'); 198 wp_send_json($results); 199 } 184 $table_name_model_settings = $wpdb->prefix . 'ai_app_onsite_model_settings'; 185 186 // Check if the table ai_app_onsite_field_selector_settings exists 187 if ($wpdb->get_var("SHOW TABLES LIKE '$table_name_settings'") != $table_name_settings || $wpdb->get_var("SHOW TABLES LIKE '$table_name_model_settings'") != $table_name_model_settings) { 188 $this->ai_app_onsite_json_error_404('No App found'); 189 } 190 191 // Check if the table ai_app_onsite_field_selector_settings has rows 192 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 193 $model_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_model_settings WHERE app_id = 1"); 194 195 if ($rows_count == 0 || $model_count == 0 || empty($this->appProperty)) { 196 $this->ai_app_onsite_json_error_404('It looks like some required settings are missing. Please ensure that "App Details," "Model Settings," and "Form Fields" are configured before previewing the form.'); 197 } 198 199 200 200 201 201 // Fetch the data 202 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ORDER BY field_position ASC", ARRAY_A);202 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1 ORDER BY field_position ASC", ARRAY_A); 203 203 204 204 $table_appropriate = $wpdb->prefix . 'ai_app_onsite_app_properties'; 205 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate", ARRAY_A); 205 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate WHERE app_id = 1", ARRAY_A); 206 if( 207 empty($appropriates[0]['title_color']) || 208 empty($appropriates[0]['font_color']) || 209 empty($appropriates[0]['bg_color']) || 210 empty($appropriates[0]['app_corner']) || 211 empty($appropriates[0]['app_height'])) 212 { 213 $this->ai_app_onsite_json_error_404('It looks like some required settings are missing. Please ensure that "App Details" are configured before previewing the form.'); 214 } 206 215 $app_logo = isset($appropriates[0]['app_logo']) && !empty($appropriates[0]['app_logo']) 207 216 ? $appropriates[0]['app_logo'] … … 286 295 287 296 $formHTML .= '<div class="ai-app-preview-powered_by_note-wrapper"> 288 <p class="powered_by" style="opacity:0.5;text-align: right;margin: 0; color:#159AD7;"><span class="disclaimer-heading"><a href="https://www.aiapponsite.com/" target="_blank">Built with AIappOnsite</a></span>297 <p class="powered_by" style="opacity:0.5;text-align: right;margin: 0; color:#159AD7;"><span class="disclaimer-heading"><a href="https://www.aiapponsite.com/" class="open-new-tab">Built with AIappOnsite</a></span> 289 298 </div>'; 290 299 … … 333 342 334 343 $table_name = $wpdb->prefix . 'ai_app_onsite_app_properties'; 335 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name ");344 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name WHERE app_id = 1"); 336 345 337 346 if ($existing_settings) { … … 360 369 } 361 370 362 363 364 365 371 // Define shortcode function 366 372 public function ai_app_onsite_create_openAi_app_form_shortcode(): string { 367 373 global $wpdb; 368 374 $table_appropriate = $wpdb->prefix . 'ai_app_onsite_app_properties'; 369 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate ", ARRAY_A);375 $appropriates = $wpdb->get_results("SELECT * FROM $table_appropriate WHERE app_id = 1", ARRAY_A); 370 376 371 377 // Make AJAX call to retrieve form HTML … … 411 417 jQuery(document).ready(function($) { 412 418 413 $(".ai-app-feedback-section .like i ").on("click", function() {414 var feedback = $(this).hasClass("fa-thumbs-up") ? "thumbs_up" : "thumbs_down";419 $(".ai-app-feedback-section .like i, .ai-app-feedback-section .dislike i").on("click", function() { 420 var feedback = $(this).hasClass("fa-thumbs-up") ? "thumbs_up" : "thumbs_down"; 415 421 var response_id = $("#ai_response_id").val(); 416 console.log(response_id);417 422 $.ajax({ 418 423 url: "' . admin_url('admin-ajax.php') . '", … … 456 461 457 462 // Check if the table has rows 458 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");463 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 459 464 if ($rows_count == 0) { 460 465 //die('No rows found in the table.'); … … 465 470 466 471 // Fetch the data 467 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ", ARRAY_A);472 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 468 473 469 474 $generateURLForID = $results[0]['app_logo']; -
ai-app-onsite/trunk/handler/ai-app-onsite-app-properties.php
r3281194 r3307540 149 149 'app_height' => $app_height 150 150 ), 151 array('%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )151 array('%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') 152 152 ); 153 153 … … 177 177 178 178 // Check if the table has rows 179 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings"); 179 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 180 180 181 if ($rows_count == 0) { 181 182 //die('No rows found in the table.'); 182 $results = array('status' => '404', 'message' => ' No rows found in the table.');183 $results = array('status' => '404', 'message' => 'App not found. Please create an app first.'); 183 184 184 185 wp_send_json($results); … … 186 187 187 188 // Fetch the data 188 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ", ARRAY_A);189 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 189 190 190 191 $generateURLForID = $results[0]['app_logo']; … … 253 254 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_app_properties'; 254 255 255 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");256 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 256 257 if ($existing_settings) { 257 258 … … 298 299 } 299 300 300 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");301 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 301 302 $file_url = $existing_settings->app_logo; 302 303 // Check if the database operation was successful … … 323 324 } 324 325 325 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");326 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 326 327 if ($existing_settings) { 327 328 -
ai-app-onsite/trunk/handler/ai-app-onsite-field-selector.php
r3250856 r3307540 47 47 $form_data_array = json_decode($form_data_array, true); 48 48 49 50 // echo '<pre>'; print_r($form_data_array); echo '</pre>';51 52 49 // Table name for field selector settings 53 50 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_field_selector_settings'; 54 51 55 $max_field_option = $wpdb->get_var("SELECT MAX(field_position) FROM $table_name_settings"); 56 57 58 52 $max_field_option = $wpdb->get_var("SELECT MAX(field_position) FROM $table_name_settings WHERE app_id = 1"); 59 53 60 54 // Iterate through form data and insert/update settings … … 175 169 public function ai_app_onsite_read_field_selector_callback() 176 170 { 177 178 171 global $wpdb; 179 172 … … 181 174 182 175 // Fetch data from the database 183 $results = $wpdb->get_results("SELECT * FROM $table_name ORDER BY field_position ASC", ARRAY_A);176 $results = $wpdb->get_results("SELECT * FROM $table_name WHERE app_id = 1 ORDER BY field_position ASC", ARRAY_A); 184 177 185 178 … … 190 183 $ctr = 0; 191 184 192 $app_width = $results[0]['app_width'] ;185 $app_width = $results[0]['app_width'] ?? '70'; 193 186 194 187 … … 266 259 // Return the HTML content 267 260 $arrayName = array('app_width' => $app_width, 'html_content' => $html_content, 'count' => $ctr); 268 //echo $html_content;269 261 270 262 wp_send_json($arrayName); … … 315 307 public function ai_app_onsite_drag_data_save_database_callback() 316 308 { 317 318 319 309 if ( 320 310 ! isset($_POST['ai_app_onsite_fields_selector_order_nonce']) || … … 324 314 } 325 315 326 327 328 316 global $wpdb; 329 317 $table_name = $wpdb->prefix . 'ai_app_onsite_field_selector_settings'; … … 336 324 // Iterate through the form data array 337 325 foreach ($form_data_array as $key => $value) { 338 // Prepare the data to update 339 /* $update_data = array( 340 'field_position' => $value['fieldOrder'], 341 'field_uniqueid' => $value['fieldUniqueId'] 342 ); 343 344 // Print the data to be updated (for debugging purposes) 345 print_r($update_data);*/ 326 346 327 $field_position = $value['fieldOrder'] / 3; 347 328 // Uncomment the update query to actually update the data -
ai-app-onsite/trunk/handler/ai-app-onsite-model-settings.php
r3272415 r3307540 51 51 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_model_settings'; 52 52 53 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");53 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 54 54 55 55 if ($existing_settings) { … … 69 69 array('%s', '%f', '%f', '%f', '%d', '%f'), 70 70 ); 71 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");71 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 72 72 73 73 // Check if the database operation was successful … … 95 95 ); 96 96 } 97 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");97 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 98 98 99 99 // Check if the database operation was successful … … 119 119 120 120 // Check if the table has rows 121 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");121 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 122 122 if ($rows_count == 0) { 123 123 $results = array('status' => '404', 'message' => 'No rows found in the table.'); … … 130 130 131 131 // Fetch the data 132 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ", ARRAY_A);132 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 133 133 134 134 // Return the data … … 163 163 164 164 // Fetch the data 165 $results = $wpdb->get_results("SELECT openai_key, key_status FROM $table_name_settings ", ARRAY_A);165 $results = $wpdb->get_results("SELECT openai_key, key_status FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 166 166 167 167 // Return the data … … 197 197 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_model_settings'; 198 198 199 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");199 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 200 200 201 201 if ($existing_settings) { -
ai-app-onsite/trunk/handler/ai-app-onsite-openAi-api.php
r3281194 r3307540 34 34 35 35 36 $model_settings = $wpdb->get_results("SELECT * FROM $table_name_model_settings ", ARRAY_A);37 38 $plugin_settings = $wpdb->get_results("SELECT * FROM $table_name_plugin_settings ", ARRAY_A);36 $model_settings = $wpdb->get_results("SELECT * FROM $table_name_model_settings WHERE app_id = 1", ARRAY_A); 37 38 $plugin_settings = $wpdb->get_results("SELECT * FROM $table_name_plugin_settings WHERE app_id = 1", ARRAY_A); 39 39 $formData = $_POST; 40 40 $field_names = array_keys($formData); 41 41 $field_values = array_values($formData); 42 42 $pairs = array_combine($field_names, $field_values); 43 $banned_words = unserialize($plugin_settings[0]['banned_words']); 44 $app_email = $plugin_settings[0]['app_email']; 43 $banned_words = (!empty($plugin_settings) && isset($plugin_settings[0]['banned_words']) && !is_null($plugin_settings[0]['banned_words'])) 44 ? unserialize($plugin_settings[0]['banned_words']) 45 : []; 46 $app_email = isset($plugin_settings[0]['app_email']) ? $plugin_settings[0]['app_email'] : null; 45 47 46 48 function containsBannedWordPart($value, $banned_word) … … 58 60 59 61 // Iterate through field values and check against banned words 60 foreach ($field_values as $value) { 61 foreach ($banned_words as $banned_word) { 62 if (containsBannedWordPart($value, $banned_word)) { 63 wp_send_json_error("Banned word included in: " . $value); 64 break; 62 if (!empty($banned_words)) { 63 foreach ($field_values as $value) { 64 foreach ($banned_words as $banned_word) { 65 if (containsBannedWordPart($value, $banned_word)) { 66 wp_send_json_error("Banned word included in: " . $value); 67 break 2; 68 } 65 69 } 66 70 } 67 71 } 68 72 69 $field_selector_settings = $wpdb->get_results("SELECT `field_label` FROM $table_name_field_selector", ARRAY_A); 70 73 74 $field_selector_settings = $wpdb->get_results("SELECT `field_label` FROM $table_name_field_selector WHERE app_id = 1", ARRAY_A); 75 71 76 $fieldLabels = array_column($field_selector_settings, 'field_label'); 72 77 // Process each element of the array … … 163 168 164 169 $replace_array = array_combine($formatted_field_names, $field_values); 165 166 $prompt_results = $wpdb->get_results("SELECT * FROM $table_name_prompt_editor", ARRAY_A); 167 170 171 172 $prompt_results = $wpdb->get_results("SELECT * FROM $table_name_prompt_editor WHERE app_id = 1", ARRAY_A); 173 168 174 if (empty($prompt_results)) { 169 175 wp_send_json_error('No prompt results found'); -
ai-app-onsite/trunk/handler/ai-app-onsite-plugin-settings.php
r3250856 r3307540 13 13 add_action( 'wp_ajax_nopriv_ai_app_onsite_handle_csv_upload', array( $this, 'ai_app_onsite_handle_csv_upload_callback' ) ); 14 14 15 add_action( 'wp_ajax_ai_app_onsite_get_accept_terms_of_service', array( $this, 'ai_app_onsite_get_accept_terms_of_service_callback' ) );15 add_action( 'wp_ajax_ai_app_onsite_get_accept_terms_of_service', array( $this, 'ai_app_onsite_get_accept_terms_of_service_callback' ) ); 16 16 add_action( 'wp_ajax_nopriv_ai_app_onsite_get_accept_terms_of_service', array( $this, 'ai_app_onsite_get_accept_terms_of_service_callback' ) ); 17 17 … … 19 19 } 20 20 21 // Public method to handle AJAX callback22 23 21 public function ai_app_onsite_save_plugin_settings_callback() { 24 25 26 27 22 global $wpdb; // Access the WordPress database object 28 23 if ( … … 33 28 } 34 29 35 // Handle AJAX request36 37 30 // Check if settings already exist in the database 38 31 $table_name_settings = $wpdb->prefix . 'ai_app_onsite_plugin_settings'; … … 40 33 // Extract individual settings values 41 34 $agree_terms = isset($_POST['terms_of_service'] ) && $_POST['terms_of_service'] == true ? 1 : 0; 42 // $app_selector = isset($_POST['app_selector'] ) ? sanitize_text_field($_POST['app_selector'] ) : '';43 // $app_email = isset($_POST['app_email'] ) ? sanitize_text_field($_POST['app_email'] ) : '';44 // $banned_words = isset($_POST['banned_words'] ) ? serialize($_POST['banned_words'] ) : '';45 46 35 $app_selector = isset( $_POST['app_selector'] ) ? sanitize_text_field( wp_unslash( $_POST['app_selector'] ) ) : ''; 47 36 $app_email = isset($_POST['app_email'] ) ? sanitize_text_field(wp_unslash($_POST['app_email']) ) : ''; 48 37 $banned_words = isset( $_POST['banned_words'] ) ? serialize( array_map( 'sanitize_text_field', wp_unslash( $_POST['banned_words'] ) ) ) : ''; 49 50 51 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings"); 38 39 if ($app_selector == '') { 40 $results = array('status' => '404', 'error' => 'App Name is required.'); 41 wp_send_json($results); 42 exit; 43 } 44 45 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 52 46 53 47 // If settings already exist, update the row; otherwise, insert a new row 54 48 if ($existing_settings) { 55 // Update existing row56 // Define the update data array57 49 $update_data = array( 58 50 'agree_terms' => $agree_terms, … … 84 76 wp_send_json_error('Error updating data: ' . $wpdb->last_error); 85 77 } else { 78 $table_app_properties = $wpdb->prefix . 'ai_app_onsite_app_properties'; 79 80 $existing_app = $wpdb->get_row("SELECT * FROM $table_app_properties WHERE app_id = 1"); 81 82 if ($existing_app) { 83 // Update the app name if it already exists 84 $wpdb->update( 85 $table_app_properties, 86 array( 87 'app_name' => $app_selector, 88 ), 89 array('app_id' => $existing_app->app_id), 90 array('%s'), 91 array('%d') 92 ); 93 94 if ($wpdb->last_error) { 95 wp_send_json_error('Error updating app name: ' . $wpdb->last_error); 96 } 97 } else { 98 // Insert new app name if it doesn't exist 99 $wpdb->insert( 100 $table_app_properties, 101 array( 102 'app_id' => 1, 103 'app_name' => $app_selector, 104 'submit_button_txt' => 'Submit', 105 ), 106 array('%d', '%s', '%s') 107 ); 108 109 if ($wpdb->last_error) { 110 wp_send_json_error('Error saving app name: ' . $wpdb->last_error); 111 } 112 } 86 113 // Return success message for update 87 114 wp_send_json_success('Settings updated successfully.'); … … 107 134 } else { 108 135 // Return success message for insert 136 $table_app_properties = $wpdb->prefix . 'ai_app_onsite_app_properties'; 137 138 // Insert new app name into the app properties table 139 $wpdb->insert( 140 $table_app_properties, 141 array( 142 'app_id' => 1, 143 'app_name' => $app_selector, 144 'submit_button_txt' => 'Submit', 145 ), 146 array('%d', '%s', '%s') 147 ); 148 149 if ($wpdb->last_error) { 150 wp_send_json_error('Error saving app name: ' . $wpdb->last_error); 151 } 109 152 wp_send_json_success('Settings saved successfully.'); 110 153 } 111 154 } 155 112 156 } 113 157 … … 124 168 125 169 // Check if the table has rows 126 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");170 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 127 171 if ($rows_count == 0) { 128 129 172 $results = array('status' => '404', 'message' => 'No rows found in the table.'); 130 173 … … 135 178 } 136 179 137 138 139 $getAppName = $wpdb->get_results("SELECT * FROM $table_app_name", ARRAY_A);140 141 $appName = $getAppName[0]['app_name'];180 $getAppName = $wpdb->get_results("SELECT * FROM $table_app_name WHERE app_id = 1", ARRAY_A); 181 182 $appName = isset($getAppName[0]['app_name_show']) && !empty($getAppName[0]['app_name_show']) 183 ? $getAppName[0]['app_name_show'] 184 : (isset($getAppName[0]['app_name']) ? $getAppName[0]['app_name'] : ''); 142 185 143 186 // Fetch the data 144 $results = $wpdb->get_results("SELECT * FROM $table_name_settings", ARRAY_A); 145 187 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 188 189 // Create a mapping of app IDs to app names 190 $appNameMapping = []; 146 191 // Unserialize 'banned_words_csv' before sending response 147 192 foreach ($results as &$row) { 148 if (!empty($appName)) { 149 $row['appName'] = $appName; 150 } 151 $unserializedDataCsv = unserialize($row['banned_words_csv']); 193 if (!empty($appName)) { 194 $row['appName'] = $appName; 195 } 196 $banned_words_raw = $row['banned_words_csv'] ?? ''; 197 198 if (is_string($banned_words_raw) && $banned_words_raw !== '' && is_serialized($banned_words_raw)) { 199 $unserializedDataCsv = unserialize($banned_words_raw); 200 } else { 201 $unserializedDataCsv = []; 202 } 152 203 $unserializedData = unserialize($row['banned_words']); 153 204 if ($unserializedDataCsv !== false) { … … 224 275 } 225 276 226 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings ");277 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 227 278 if ($existing_settings) { 228 279 if (!empty($serializedData)) { … … 278 329 279 330 $terms_of_service = isset($_POST['terms_of_service']) ? intval($_POST['terms_of_service']) : 0; 280 $checked = ($_POST['terms_of_service'] == true) ? 1 : 0; 281 282 283 284 285 286 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings"); 331 $checked = ($_POST['terms_of_service'] == true) ? 1 : 0; 332 333 $existing_settings = $wpdb->get_row("SELECT * FROM $table_name_settings WHERE app_id = 1"); 287 334 288 335 if ($existing_settings) { -
ai-app-onsite/trunk/handler/ai-app-onsite-prompt-editor.php
r3272415 r3307540 116 116 117 117 // Check if the table has rows 118 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");118 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 119 119 if ($rows_count == 0) { 120 121 120 $results = array('status' => '404', 'message' => 'No rows found in the table.'); 122 121 … … 128 127 129 128 // Fetch the data 130 $results = $wpdb->get_results("SELECT field_tag FROM $table_name_settings ", ARRAY_A);129 $results = $wpdb->get_results("SELECT field_tag FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 131 130 132 131 // Return the data … … 149 148 150 149 // Check if the table has rows 151 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");150 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 152 151 if ($rows_count == 0) { 153 152 $results = array('status' => '404', 'message' => 'No rows found in the table.'); … … 160 159 161 160 // Fetch the data 162 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ", ARRAY_A);161 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 163 162 164 163 // Return the data … … 180 179 181 180 // Check if the table has rows 182 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings ");181 $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name_settings WHERE app_id = 1"); 183 182 if ($rows_count == 0) { 184 183 … … 192 191 193 192 // Fetch the data 194 $results = $wpdb->get_results("SELECT * FROM $table_name_settings ", ARRAY_A);193 $results = $wpdb->get_results("SELECT * FROM $table_name_settings WHERE app_id = 1", ARRAY_A); 195 194 196 195 // Return the data -
ai-app-onsite/trunk/handler/ai-app-onsite-user-stats.php
r3281194 r3307540 104 104 $table_name = $wpdb->prefix . 'ai_app_onsite_user_statistics'; 105 105 $query = "SELECT * FROM $table_name"; 106 $user_stats = $wpdb->get_results( "SELECT * FROM $table_name WHERE MONTH(updated_at) = %d", $month);106 $user_stats = $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE app_id = 1 AND MONTH(updated_at) = %d", $month)); 107 107 108 108 // Check if there are any user statistics -
ai-app-onsite/trunk/includes/class-ai-app-onsite-admin.php
r3272415 r3307540 31 31 <div class="wrap ai-app-onsite-wrap"> 32 32 <div class=" ai-app-onsite-top-bar d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white box-shadow"> 33 <h5 class="my-0 mr-md-auto font-weight-normal logo-bg-fixed"> 34 35 </h5> 33 <h5 class="my-0 mr-md-auto font-weight-normal logo-bg-fixed"></h5> 34 <?php if (ai_app_onsite_is_premium_disabled()) : ?> 35 <h5 class="gold-gradient" id="gold_gradient">PREMIUM</h5> 36 <?php endif; ?> 36 37 </div> 37 38 <div class="ai-app-onsite-tab-content-box shadow-sm rounded"> 38 39 <!-- Tab navigation --> 39 40 <h2 class="nav-tab-wrapper"> 40 <a href="#" class="nav-tab nav-tab-active " id="plugin-settings-tab" onclick="handleTabClick('plugin-settings-tab')">41 <a href="#" class="nav-tab nav-tab-active plugin-tab" id="plugin-settings-tab" data-form-tab="app-settings" data-tab-id="plugin-settings-tab"> 41 42 <div class="icon"> 42 43 <div class="assets-settings-grey-icon"></div> 43 44 <div class="assets-settings-blue-icon"></div> 44 45 </div> 45 PluginSettings46 </a> 47 <a href="#" class="nav-tab " id="app-properties-tab" onclick="handleTabClick('app-properties-tab')">46 App Settings 47 </a> 48 <a href="#" class="nav-tab plugin-tab" id="app-properties-tab" data-form-tab="app-details" data-tab-id="app-properties-tab"> 48 49 <div class="icon"> 49 50 <div class="assets-clapperboard-grey-icon"></div> 50 51 <div class="assets-clapperboard-blue-icon"></div> 51 52 </div> 52 App Properties53 </a> 54 <a href="#" class="nav-tab " id="model-settings-tab" onclick="handleTabClick('model-settings-tab')">53 App Details 54 </a> 55 <a href="#" class="nav-tab plugin-tab" id="model-settings-tab" data-form-tab="model-settings" data-tab-id="model-settings-tab"> 55 56 <div class="icon"> 56 57 <div class="assets-disc-grey-icon"></div> … … 59 60 Model Settings 60 61 </a> 61 <a href="#" class="nav-tab " id="field-selector-tab" onclick="handleTabClick('field-selector-tab')">62 <a href="#" class="nav-tab plugin-tab" id="field-selector-tab" data-form-tab="field-selector" data-tab-id="field-selector-tab"> 62 63 <div class="icon"> 63 64 <div class="assets-chevron-grey-icon"></div> … … 66 67 Field Selector 67 68 </a> 68 <a href="#" class="nav-tab " id="prompt-editor-tab" onclick="handleTabClick('prompt-editor-tab')">69 <a href="#" class="nav-tab plugin-tab" id="prompt-editor-tab" data-form-tab="prompt-editor" data-tab-id="prompt-editor-tab"> 69 70 <div class="icon"> 70 71 <div class="assets-promt-icon-grey-icon"></div> … … 73 74 Prompt Editor 74 75 </a> 75 <a href="#" class="nav-tab " id="app-preview-tab" onclick="handleTabClick('app-preview-tab')">76 <a href="#" class="nav-tab plugin-tab" id="app-preview-tab" data-form-tab="app-preview" data-tab-id="app-preview-tab"> 76 77 <div class="icon"> 77 78 <div class="assets-preview-icon-grey-icon"></div> … … 285 286 </div> 286 287 288 <div class="modal fade" id="unsavedChangesModal" tabindex="-1" aria-labelledby="unsavedChangesModalLabel" aria-hidden="true"> 289 <div class="modal-dialog modal-dialog-centered"> 290 <div class="modal-content text-center"> 291 <div class="modal-header"> 292 <h5 class="modal-title" id="unsavedChangesModalLabel">Unsaved Changes</h5> 293 <button type="button" class="btn-close dismiss-unsaved-modal"></button> 294 </div> 295 <div class="modal-body"> 296 You have unsaved changes. Please save them before navigating away or refreshing. 297 </div> 298 <div class="modal-footer justify-content-center"> 299 <button type="button" class="btn btn-primary" aria-label="Close" data-bs-dismiss="modal">Got It</button> 300 <!-- class="btn btn-primary dismiss-unsaved-modal" --> 301 </div> 302 </div> 303 </div> 304 </div> 305 287 306 <!-- Modal --> 288 <div class="modal fade bd-example-modal-sm plugin-setting" id="terms_conditions_modal" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true"> 289 <div class="modal-dialog modal-dialog-centered" role="document"> 290 <div class="modal-content"> 291 <div class="modal-header"> 292 <h5 class="fs-bold-16" id="terms_conditions_modal_label">Terms of Services</h5> 293 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 307 <div class="modal fade bd-example-modal-sm plugin-setting" id="terms_conditions_modal" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true"> 308 <div class="modal-dialog modal-dialog-centered" role="document"> 309 <div class="modal-content"> 310 <div class="modal-header"> 311 <h5 class="fs-bold-16" id="terms_conditions_modal_label">Terms of Services</h5> 312 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 313 </div> 314 <div class="modal-body mb-1"> 315 <div id="terms-conditions-modal-pdf"> 316 <p class="fs-regular-14 neutral-black-fs-100 mb-3 text-center">Terms of Services</p> 317 <p class="fs-regular-14 neutral-black-fs-90">Please read these terms carefully before using our service.</p> 318 <p class="fs-regular-14 neutral-black-fs-100 mb-1">1. User Responsibility</p> 319 <p class="fs-regular-12 neutral-black-fs-70">If you reside in the European Economic Area, Switzerland, the UK, California or some other locations, you may be subject to special conditions and laws that govern the use of AI. These and other locales also have privacy and data protection rules and laws that may also dictate how you can leverage tools like AIappOnsite.</p> 320 <p class="fs-regular-12 neutral-black-fs-70">It is important that you abide by all such applicable laws. Furthermore, you may not use the Service in a way that infringes, misappropriates or violates anyone’s rights. You may also not use the Service in a way that endangers or harms, or intends to do the same, to end users of applications built with the Service.</p> 321 322 <p class="fs-regular-14 neutral-black-fs-100 mb-1">2. Using AI Services</p> 323 <p class="fs-regular-12 neutral-black-fs-70">The Service requires that the site owner or their designee provide an API key which the Service will use tointegrate with an AI model provider. All AI functionality of the Service depends on one or more API keys, whichis provided by the various AI model vendors. An account must be opened with one of these vendors in order to get an API key.</p> 324 <p class="fs-regular-12 neutral-black-fs-70">These AI model providers are separate companies and unaffiliated with the Service, and have their own terms and conditions. Read them carefully. The API keys and their use are bound by the terms and conditions of the AI model provider and strictly controlled by the site owner or their designee (not AIappOnsite).</p> 325 326 <p class="fs-regular-14 neutral-black-fs-100 mb-1">3. Limitation of Liability</p> 327 <p class="fs-regular-12 neutral-black-fs-70">Given that the site owner fully controls the use, purpose and output of any application built with it, AIappOnsite bears no responsibility or liability for how it is used, or to any consequences of its use by site owners or their site visitors.</p> 328 <p class="fs-regular-12 neutral-black-fs-70">You agree that you are leveraging third party AI models and services separate from AIappOnsite, and that you have full control over and final responsibility for the prompts that will access the API as well as the end-user experience, and any representations made to them.</p> 329 330 <p class="fs-regular-14 neutral-black-fs-100 mb-1">4. Paid Accounts</p> 331 <p class="fs-regular-12 neutral-black-fs-70">Billing. If you purchase any services, you will provide complete and accurate billing information, including a valid payment method. For paid subscriptions, we will automatically charge your payment method on each agreed-upon periodic renewal until you cancel. You’re responsible for all applicable taxes, and we’ll charge tax when required. If your payment cannot be completed, we may downgrade your account or suspend your access to our services until payment is received.</p> 332 <p class="fs-regular-12 neutral-black-fs-70">Cancellation. You can cancel your paid subscription at any time. Previous payments are non-refundable,except where required by law. These Terms do not override any mandatory local laws regarding your cancellation rights.</p> 333 <p class="fs-regular-12 neutral-black-fs-70">Changes. We may change our prices from time to time. If we increase our subscription prices, we will give you at least 30 days’ notice and any price increase will take effect on your next renewal so that you can cancel if you do not agree to the price increase</p> 334 335 <p class="fs-regular-14 neutral-black-fs-100 mb-1">5. Termination and Suspension</p> 336 <p class="fs-regular-12 neutral-black-fs-70">Termination. You are free to stop using our Services at any time. We reserve the right to suspend or terminate your access to our Services or delete your account if we determine: 337 <ul class="pl-2"> 338 <li class="fs-regular-12 neutral-black-fs-70">- You breached these Terms of Service.</li> 339 <li class="fs-regular-12 neutral-black-fs-70">- We must do so to comply with the law.</li> 340 <li class="fs-regular-12 neutral-black-fs-70">- Your use of our Services could cause risk or harm to AIappOnsite or anyone else.</li> 341 </ul> 342 </p> 343 <p class="fs-regular-12 neutral-black-fs-70">Appeals. If you believe we have suspended or terminated your account in error, you can file an appeal with us by contacting our Support team.</p> 344 345 <p class="fs-regular-14 neutral-black-fs-100 mb-1">6. Discontinuation of Services</p> 346 <p class="fs-regular-12 neutral-black-fs-70">We may decide to discontinue our Services, but if we do, we will give you advance notice and a refund for any prepaid, unused services.</p> 347 348 <p class="fs-regular-14 neutral-black-fs-100 mb-1">7. Disclaimer of Warranties</p> 349 <p class="fs-regular-12 neutral-black-fs-70">Our services are provided “as is.” except to the extent prohibited by law, we and our affiliates and licensors make no warranties (express, implied, statutory or otherwise) with respect to the services, and disclaim all warranties including, but not limited to, warranties of merchantability, fitness for a particular purpose,satisfactory quality, non-infringement, and quiet enjoyment, and any warranties arising out of any course of dealing or trade usage. We do not warrant that the services will be uninterrupted, accurate or error free, or that any content will be secure or not lost or altered.</p> 350 <p class="fs-regular-12 neutral-black-fs-70">You accept and agree that any use of the service is at your sole risk.</p> 351 352 <p class="fs-regular-14 neutral-black-fs-100 mb-1">8. Limitation of liability</p> 353 <p class="fs-regular-12 neutral-black-fs-70">Neither we nor any of our affiliates or licensors will be liable for any indirect,incidental, special, consequential, or exemplary damages, including damages for loss of profits, goodwill, use, or data or other losses, even if we have been advised of the possibility of such damages. Our aggregate liability under these terms will not exceed the greater of the amount you paid for the service that gave rise to the claim during the 12 months before the liability arose or one hundred dollars ($100).The limitations in this section apply only to the maximum extent permitted by applicable law.</p> 354 <p class="fs-regular-12 neutral-black-fs-70">Some countries and states do not allow the disclaimer of certain warranties or the limitation of certain damages, so some or all of the terms above may not apply to you, and you may have additional rights. In that case, these Terms only limit our responsibilities to the maximum extent permissible in your country of residence.</p> 355 <p class="fs-regular-12 neutral-black-fs-70">Aiapponsite’s affiliates, suppliers, licensors, and distributors are intended third party beneficiaries of this section.</p> 356 357 <p class="fs-regular-14 neutral-black-fs-100 mb-1">9. Indemnity</p> 358 <p class="fs-regular-12 neutral-black-fs-70">If you are a business or organization, to the extent permitted by law, you will indemnify and hold harmless us,our affiliates, and our personnel, from and against any costs, losses, liabilities, and expenses (including attorneys’ fees) from third party claims arising out of or relating to your use of the Services and Content or any violation of these Terms.</p> 359 360 <div class="terms-form-group form-group mb-0" id="terms-form-group"> 361 <input type="checkbox" id="terms_conditions"> 362 <label for="terms_conditions" class="fs-regular-14 pl-1 neutral-black-fs-90">Agree to Terms of Service</label> 363 </div> 364 </div> 365 <div class="divider-light mt-2 mb-3" id="divider"></div> 366 <div class="button-wrap" id="terms_conditions_button"> 367 <button type="button" id="download_ai_app_terms_of_service" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-white" name="save-plugin-settings" onclick="ai_app_onsite_download_terms_Of_service()">Download</button> 368 <button type="button" id="accept_ai_app_terms_of_service" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-purple border-purple text-white" name="save-plugin-settings" data-bs-dismiss="modal">Accept</button> 369 </div> 370 </div> 371 </div> 372 </div> 294 373 </div> 295 <div class="modal-body mb-1">296 <div id="terms-conditions-modal-pdf">297 <p class="fs-regular-14 neutral-black-fs-100 mb-3 text-center">Terms of Services</p>298 <p class="fs-regular-14 neutral-black-fs-90">Please read these terms carefully before using our service.</p>299 <p class="fs-regular-14 neutral-black-fs-100 mb-1">1. User Responsibility</p>300 <p class="fs-regular-12 neutral-black-fs-70">If you reside in the European Economic Area, Switzerland, the UK, California or some other locations, you may be subject to special conditions and laws that govern the use of AI. These and other locales also have privacy and data protection rules and laws that may also dictate how you can leverage tools like AIappOnsite.</p>301 <p class="fs-regular-12 neutral-black-fs-70">It is important that you abide by all such applicable laws. Furthermore, you may not use the Service in a way that infringes, misappropriates or violates anyone’s rights. You may also not use the Service in a way that endangers or harms, or intends to do the same, to end users of applications built with the Service.</p>302 303 <p class="fs-regular-14 neutral-black-fs-100 mb-1">2. Using AI Services</p>304 <p class="fs-regular-12 neutral-black-fs-70">The Service requires that the site owner or their designee provide an API key which the Service will use tointegrate with an AI model provider. All AI functionality of the Service depends on one or more API keys, whichis provided by the various AI model vendors. An account must be opened with one of these vendors in order to get an API key.</p>305 <p class="fs-regular-12 neutral-black-fs-70">These AI model providers are separate companies and unaffiliated with the Service, and have their own terms and conditions. Read them carefully. The API keys and their use are bound by the terms and conditions of the AI model provider and strictly controlled by the site owner or their designee (not AIappOnsite).</p>306 307 <p class="fs-regular-14 neutral-black-fs-100 mb-1">3. Limitation of Liability</p>308 <p class="fs-regular-12 neutral-black-fs-70">Given that the site owner fully controls the use, purpose and output of any application built with it, AIappOnsite bears no responsibility or liability for how it is used, or to any consequences of its use by site owners or their site visitors.</p>309 <p class="fs-regular-12 neutral-black-fs-70">You agree that you are leveraging third party AI models and services separate from AIappOnsite, and that you have full control over and final responsibility for the prompts that will access the API as well as the end-user experience, and any representations made to them.</p>310 311 <p class="fs-regular-14 neutral-black-fs-100 mb-1">4. Paid Accounts</p>312 <p class="fs-regular-12 neutral-black-fs-70">Billing. If you purchase any services, you will provide complete and accurate billing information, including a valid payment method. For paid subscriptions, we will automatically charge your payment method on each agreed-upon periodic renewal until you cancel. You’re responsible for all applicable taxes, and we’ll charge tax when required. If your payment cannot be completed, we may downgrade your account or suspend your access to our services until payment is received.</p>313 <p class="fs-regular-12 neutral-black-fs-70">Cancellation. You can cancel your paid subscription at any time. Previous payments are non-refundable,except where required by law. These Terms do not override any mandatory local laws regarding your cancellation rights.</p>314 <p class="fs-regular-12 neutral-black-fs-70">Changes. We may change our prices from time to time. If we increase our subscription prices, we will give you at least 30 days’ notice and any price increase will take effect on your next renewal so that you can cancel if you do not agree to the price increase</p>315 316 <p class="fs-regular-14 neutral-black-fs-100 mb-1">5. Termination and Suspension</p>317 <p class="fs-regular-12 neutral-black-fs-70">Termination. You are free to stop using our Services at any time. We reserve the right to suspend or terminate your access to our Services or delete your account if we determine:318 <ul class="pl-2">319 <li class="fs-regular-12 neutral-black-fs-70">- You breached these Terms of Service.</li>320 <li class="fs-regular-12 neutral-black-fs-70">- We must do so to comply with the law.</li>321 <li class="fs-regular-12 neutral-black-fs-70">- Your use of our Services could cause risk or harm to AIappOnsite or anyone else.</li>322 </ul>323 </p>324 <p class="fs-regular-12 neutral-black-fs-70">Appeals. If you believe we have suspended or terminated your account in error, you can file an appeal with us by contacting our Support team.</p>325 326 <p class="fs-regular-14 neutral-black-fs-100 mb-1">6. Discontinuation of Services</p>327 <p class="fs-regular-12 neutral-black-fs-70">We may decide to discontinue our Services, but if we do, we will give you advance notice and a refund for any prepaid, unused services.</p>328 329 <p class="fs-regular-14 neutral-black-fs-100 mb-1">7. Disclaimer of Warranties</p>330 <p class="fs-regular-12 neutral-black-fs-70">Our services are provided “as is.” except to the extent prohibited by law, we and our affiliates and licensors make no warranties (express, implied, statutory or otherwise) with respect to the services, and disclaim all warranties including, but not limited to, warranties of merchantability, fitness for a particular purpose,satisfactory quality, non-infringement, and quiet enjoyment, and any warranties arising out of any course of dealing or trade usage. We do not warrant that the services will be uninterrupted, accurate or error free, or that any content will be secure or not lost or altered.</p>331 <p class="fs-regular-12 neutral-black-fs-70">You accept and agree that any use of the service is at your sole risk.</p>332 333 <p class="fs-regular-14 neutral-black-fs-100 mb-1">8. Limitation of liability</p>334 <p class="fs-regular-12 neutral-black-fs-70">Neither we nor any of our affiliates or licensors will be liable for any indirect,incidental, special, consequential, or exemplary damages, including damages for loss of profits, goodwill, use, or data or other losses, even if we have been advised of the possibility of such damages. Our aggregate liability under these terms will not exceed the greater of the amount you paid for the service that gave rise to the claim during the 12 months before the liability arose or one hundred dollars ($100).The limitations in this section apply only to the maximum extent permitted by applicable law.</p>335 <p class="fs-regular-12 neutral-black-fs-70">Some countries and states do not allow the disclaimer of certain warranties or the limitation of certain damages, so some or all of the terms above may not apply to you, and you may have additional rights. In that case, these Terms only limit our responsibilities to the maximum extent permissible in your country of residence.</p>336 <p class="fs-regular-12 neutral-black-fs-70">Aiapponsite’s affiliates, suppliers, licensors, and distributors are intended third party beneficiaries of this section.</p>337 338 <p class="fs-regular-14 neutral-black-fs-100 mb-1">9. Indemnity</p>339 <p class="fs-regular-12 neutral-black-fs-70">If you are a business or organization, to the extent permitted by law, you will indemnify and hold harmless us,our affiliates, and our personnel, from and against any costs, losses, liabilities, and expenses (including attorneys’ fees) from third party claims arising out of or relating to your use of the Services and Content or any violation of these Terms.</p>340 341 <div class="terms-form-group form-group mb-0">342 <input type="checkbox" id="terms_conditions">343 <label for="terms_conditions" class="fs-regular-14 pl-1 neutral-black-fs-90">Agree to Terms of Service</label>344 </div>345 </div>346 <div class="divider-light mt-2 mb-3"></div>347 <div class="button-wrap">348 <button type="button" id="download_ai_app_terms_of_service" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-white" name="save-plugin-settings" onclick="ai_app_onsite_download_terms_Of_service()">Download</button>349 <button type="button" id="accept_ai_app_terms_of_service" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-purple border-purple text-white" name="save-plugin-settings" data-bs-dismiss="modal">Accept</button>350 </div>351 </div>352 </div>353 </div>354 </div>355 374 356 375 <?php -
ai-app-onsite/trunk/includes/class-ai-app-onsite-app-preview.php
r3281194 r3307540 54 54 <div class="row" id="system-settings-container"> 55 55 <p class="fs-6 font-semibold">Style Settings</p> 56 <form class="form-wrapper" method="POST" enctype="multipart/form-data">56 <form class="form-wrapper" method="POST" id="app_preview_settings_form" enctype="multipart/form-data"> 57 57 <?php wp_nonce_field('ai_app_onsite_app_properties_nonce', 'ai_app_onsite_app_properties_nonce_field'); ?> 58 58 <!-- Colors Selector --> … … 68 68 <div class="input-group-color"> 69 69 <label class="color-container title-color green-check"> 70 <input type="radio" checked="checked" name="title-color" value="#5c5c5c">70 <input type="radio" name="title-color" value="#5c5c5c" checked="checked"> 71 71 <span class="checkmark"></span> 72 72 </label> … … 95 95 <div class="input-group-color"> 96 96 <label class="color-container font-color white-check"> 97 <input type="radio" checked="checked" name="font-color" value="#8d949a">97 <input type="radio" name="font-color" value="#8d949a" checked="checked"> 98 98 <span class="checkmark"></span> 99 99 </label> … … 124 124 <div class="input-group-color"> 125 125 <label class="color-container bg-color grey-check"> 126 <input type="radio" checked="checked" name="bg-color" value="#f4f4f4">126 <input type="radio" name="bg-color" value="#f4f4f4" checked="checked"> 127 127 <span class="checkmark"></span> 128 128 </label> … … 176 176 <div class="text-end mb-3" id="preview-action-container"> 177 177 <button type="button" id="preview_ai_app_app_properties_data" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="preview-plugin-settings" onclick="ai_app_onsite_create_app_preview_form(true)">Preview</button> 178 <button type="button" id="save_ai_app_app_properties_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_update_style_properties_only()">Save</button>178 <button type="button" id="save_ai_app_app_properties_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" id="ai_app_onsite_update_style_properties_only" onclick="ai_app_onsite_update_style_properties_only()">Save</button> 179 179 </div> 180 180 </form> -
ai-app-onsite/trunk/includes/class-ai-app-onsite-app-properties.php
r3281194 r3307540 10 10 <!-- Render your plugin setting tab page here --> 11 11 <div> 12 <form class="form-wrapper" method="POST" enctype="multipart/form-data">12 <form class="form-wrapper" id="app-details-form" method="POST" enctype="multipart/form-data"> 13 13 <?php wp_nonce_field('ai_app_onsite_app_properties_nonce', 'ai_app_onsite_app_properties_nonce_field'); ?> 14 14 <div class="form-group mb-20"> … … 20 20 <div class="assets-folder-icon"></div> 21 21 </span> 22 <input type="text" name="app-name" id="app-name" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8 ">22 <input type="text" name="app-name" id="app-name" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8 app-name" disabled> 23 23 <p id="app-name-error" class="fields-error"></p> 24 24 </div> … … 35 35 </div> 36 36 <div class="form-group"> 37 <label class="fs-medium-14 mb-1">App Logo/Image</label>37 <label class="fs-medium-14 mb-1">App Image</label> 38 38 <div class="col-12 d-flex flex-column flex-md-row"> 39 39 <!-- First div with the file input and preview --> … … 59 59 <div class="assets-cross-icon"></div> <!-- You can replace this with an actual cross icon --> 60 60 </span> 61 <span>Remove Logo</span>61 <span>Remove Image</span> 62 62 </button> 63 63 … … 77 77 <div class="assets-pen-icon"></div> 78 78 </span> 79 <textarea class="border text-write w-100 fs-regular-14 neutral-black-fs-100 radius-6" id="app-description" rows="4" cols="50" placeholder=""></textarea>79 <textarea class="border text-write w-100 fs-regular-14 neutral-black-fs-100 radius-6" id="app-description" name="app-description" rows="4" cols="50" placeholder=""></textarea> 80 80 <p class="neutral-black-fs-60 fs-regular-12 mb-0" id="wordCount">275 characters left</p> 81 81 <p id="app-description-error" class="fields-error"></p> … … 88 88 <div class="assets-pen-icon"></div> 89 89 </span> 90 <textarea id="app-disclaimer" class="border text-write w-100 fs-regular-14 neutral-black-fs-100 radius-6 " placeholder=""></textarea>90 <textarea id="app-disclaimer" class="border text-write w-100 fs-regular-14 neutral-black-fs-100 radius-6 " name="app-disclaimer" placeholder=""></textarea> 91 91 <p class="neutral-black-fs-60 fs-regular-12 mb-0">Note: This app uses OpenAI to generate suggestions and feedback. Never include any personal identifying data when using AI tools.</p> 92 92 <p id="app-disclaimer-error" class="fields-error"></p> -
ai-app-onsite/trunk/includes/class-ai-app-onsite-db-handler.php
r3281194 r3307540 9 9 protected $app_properties; 10 10 protected $model_settings; 11 protected $license_settings; 11 12 protected $field_selector_settings; 12 13 protected $prompt_editor; … … 16 17 { 17 18 18 $this->wpdb = $wpdb; 19 $this->plugin_settings = $wpdb->prefix . 'ai_app_onsite_plugin_settings'; 20 $this->app_properties = $wpdb->prefix . 'ai_app_onsite_app_properties'; 21 $this->model_settings = $wpdb->prefix . 'ai_app_onsite_model_settings'; 19 $this->wpdb = $wpdb; 20 $this->plugin_settings = $wpdb->prefix . 'ai_app_onsite_plugin_settings'; 21 $this->app_properties = $wpdb->prefix . 'ai_app_onsite_app_properties'; 22 $this->model_settings = $wpdb->prefix . 'ai_app_onsite_model_settings'; 23 $this->license_settings = $wpdb->prefix . 'ai_app_onsite_license_settings'; 22 24 $this->field_selector_settings = $wpdb->prefix . 'ai_app_onsite_field_selector_settings'; 23 $this->prompt_editor = $wpdb->prefix . 'ai_app_onsite_prompt_editor';24 $this->user_statistics = $wpdb->prefix . 'ai_app_onsite_user_statistics';25 $this->prompt_editor = $wpdb->prefix . 'ai_app_onsite_prompt_editor'; 26 $this->user_statistics = $wpdb->prefix . 'ai_app_onsite_user_statistics'; 25 27 } 26 28 … … 33 35 $app_properties = $this->app_properties; 34 36 $model_settings = $this->model_settings; 37 $license_settings = $this->license_settings; 35 38 $field_selector_settings = $this->field_selector_settings; 36 39 $prompt_editor = $this->prompt_editor; … … 41 44 $app_properties_table = $app_properties; 42 45 $model_settings_table = $model_settings; 46 $license_settings_table = $license_settings; 43 47 $field_selector_settings_table = $field_selector_settings; 44 48 $prompt_editor_table = $prompt_editor; … … 95 99 )"; 96 100 101 $sql_license_settings = "CREATE TABLE IF NOT EXISTS $license_settings_table ( 102 id INT(11) NOT NULL AUTO_INCREMENT, 103 app_id INT(30) NOT NULL, 104 license_key VARCHAR(255), 105 key_status VARCHAR(11), 106 subscription_expiry_date VARCHAR(255), 107 key_disable_status ENUM('true', 'false') DEFAULT 'false', 108 created_at DATETIME NOT NULL, 109 updated_at DATETIME NOT NULL, 110 PRIMARY KEY (id) 111 )"; 112 97 113 $sql_field_selector_settings = "CREATE TABLE IF NOT EXISTS $field_selector_settings_table ( 98 114 id INT(30) NOT NULL AUTO_INCREMENT, … … 148 164 $sql_app_properties, 149 165 $sql_model_settings, 166 $sql_license_settings, 150 167 $sql_field_selector_settings, 151 168 $sql_prompt_editor, … … 169 186 $app_properties_table = $this->app_properties; 170 187 $model_settings_table = $this->model_settings; 188 $license_settings_table = $this->license_settings; 171 189 $field_selector_settings_table = $this->field_selector_settings; 172 190 $prompt_editor_table = $this->prompt_editor; … … 177 195 $this->wpdb->query("DROP TABLE IF EXISTS $app_properties_table"); 178 196 $this->wpdb->query("DROP TABLE IF EXISTS $model_settings_table"); 197 $this->wpdb->query("DROP TABLE IF EXISTS $license_settings_table"); 179 198 $this->wpdb->query("DROP TABLE IF EXISTS $field_selector_settings_table"); 180 199 $this->wpdb->query("DROP TABLE IF EXISTS $prompt_editor_table"); -
ai-app-onsite/trunk/includes/class-ai-app-onsite-field-selector.php
r3250856 r3307540 8 8 ob_start(); ?> 9 9 <div class="field-select-content"> 10 < divid="myForm" class="container">10 <form id="myForm" class="container"> 11 11 <?php wp_nonce_field('ai_app_onsite_field_selector_nonce', 'ai_app_onsite_field_selector_nonce_field'); ?> 12 12 <div class="row alignment-items-center mb-4"> … … 14 14 <div class="select-percentage"> 15 15 <label class="fs-medium-14 mb-0">App Width</label> 16 <select id="app_width_figure" class="number-select">16 <select id="app_width_figure" name="app_width_figure" class="number-select"> 17 17 <option value="30">30%</option> 18 18 <option value="50">50%</option> … … 43 43 <button type="button" id="save_ai_app_ai_app_fieldselector_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_save_ai_app_fieldselector_data()">Save</button> 44 44 </div> 45 </ div>45 </form> 46 46 </div> 47 47 <div id="field-selector-msg-container" class="message-container"></div> -
ai-app-onsite/trunk/includes/class-ai-app-onsite-model-settings.php
r3272415 r3307540 11 11 <div class="modal-setting-content"> 12 12 <div id="modal-setting-msg-container"></div> 13 <form class="form-wrapper" id="ai_app_onsite_reset_modal-setting"> 14 <?php wp_nonce_field('ai_app_onsite_model_settings_nonce', 'ai_app_onsite_model_settings_nonce_field'); ?> 13 <form class="form-wrapper" id="ai_app_onsite_reset_modal-setting"> <?php wp_nonce_field('ai_app_onsite_model_settings_nonce', 'ai_app_onsite_model_settings_nonce_field'); ?> 15 14 <div class="row"> 16 15 <div class="col-lg-12"> … … 20 19 <div class="assets-engine-icon"></div> 21 20 </span> 22 <select id="model" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60radius-6 px-10 py-8">21 <select id="model" name="model" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8"> 23 22 <option value="">Please Select Model</option> 24 23 <option value="gpt-4o">Open AI - gpt-4o</option> … … 34 33 </div> 35 34 </div> 36 <div id="model-dependent-fields" class="row"> 37 38 <div class="col-lg-6 mb-20"> 39 <div class="form-group"> 40 <label class="fs-medium-14 font-semibold">Max Tokens</label> 41 <div class="select-box-icon"> 42 <span class="field-icon"> 43 <div class="assets-token-icon"></div> 44 </span> 45 <input type="text" name="" placeholder="3000" id="max-tokens" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="3000"> 46 <span class="small-text text-muted">Maximum number of tokens (words & characters) allowed in response.</span> 47 </div> 48 </div> 35 <div id="model-dependent-fields" class="row"> 36 <div class="col-lg-6 mb-20"> 37 <div class="form-group"> 38 <label class="fs-medium-14 font-semibold">Max Tokens</label> 39 <div class="select-box-icon"> 40 <span class="field-icon"> 41 <div class="assets-token-icon"></div> 42 </span> 43 <input type="text" name="max-tokens" placeholder="3000" id="max-tokens" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="3000"> 44 <span class="small-text text-muted">Maximum number of tokens (words & characters) allowed in response.</span> 49 45 </div> 50 <div class="col-lg-6 mb-20">51 <div class="form-group">52 <label class="fs-medium-14 font-semibold">Temperature</label>53 <div class="select-box-icon">54 <span class="field-icon">55 <div class="assets-temprature-icon"></div>56 </span>57 <input type="text" name="temperature" placeholder="1" id="temperature" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0.7">58 <span class="small-text text-muted">Controls creativity — higher value = more random responses.</span>59 </div>60 </div>61 46 </div> 62 <div class="col-lg-6 mb-20"> 63 <div class="form-group"> 64 <label class="fs-medium-14 font-semibold">Top P</label> 65 <div class="select-box-icon"> 66 <span class="field-icon"> 67 <div class="assets-temprature-icon"></div> 68 </span> 69 <input type="text" name="top-p" placeholder="1" id="top-p" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="1"> 70 <span class="small-text text-muted">Controls diversity — lower value = more focused responses.</span> 71 </div> 72 </div> 47 </div> 48 <div class="col-lg-6 mb-20"> 49 <div class="form-group"> 50 <label class="fs-medium-14 font-semibold">Temperature</label> 51 <div class="select-box-icon"> 52 <span class="field-icon"> 53 <div class="assets-temprature-icon"></div> 54 </span> 55 <input type="text" name="temperature" placeholder="1" id="temperature" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0.7"> 56 <span class="small-text text-muted">Controls creativity — higher value = more random responses.</span> 73 57 </div> 74 <div class="col-lg-6 mb-20">75 <div class="form-group mb-0">76 <label class="fs-medium-14 font-semibold">F. Penalty</label>77 <div class="select-box-icon">78 <span class="field-icon">79 <div class="assets-penalty-icon"></div>80 </span>81 <input type="text" name="f-penalty" placeholder="0" id="f-penalty" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0">82 <span class="small-text text-muted">Reduces repetition of existing words in the response.</span>83 </div>84 </div>85 58 </div> 86 <div class="col-lg-6 mb-20"> 87 <div class="form-group mb-0"> 88 <label class="fs-medium-14 font-semibold">P. Penalty</label> 89 <div class="select-box-icon"> 90 <span class="field-icon"> 91 <div class="assets-penalty-icon"></div> 92 </span> 93 <input type="text" name="p-penalty" placeholder="0" id="p-penalty" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0"> 94 <span class="small-text text-muted">Reduces repetition of new words in the response.</span> 95 </div> 96 </div> 59 </div> 60 <div class="col-lg-6 mb-20"> 61 <div class="form-group"> 62 <label class="fs-medium-14 font-semibold">Top P</label> 63 <div class="select-box-icon"> 64 <span class="field-icon"> 65 <div class="assets-temprature-icon"></div> 66 </span> 67 <input type="text" name="top-p" placeholder="1" id="top-p" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="1"> 68 <span class="small-text text-muted">Controls diversity — lower value = more focused responses.</span> 97 69 </div> 98 </div> 99 70 </div> 71 </div> 72 <div class="col-lg-6 mb-20"> 73 <div class="form-group mb-0"> 74 <label class="fs-medium-14 font-semibold">F. Penalty</label> 75 <div class="select-box-icon"> 76 <span class="field-icon"> 77 <div class="assets-penalty-icon"></div> 78 </span> 79 <input type="text" name="f-penalty" placeholder="0" id="f-penalty" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0"> 80 <span class="small-text text-muted">Reduces repetition of existing words in the response.</span> 81 </div> 82 </div> 83 </div> 84 <div class="col-lg-6 mb-20"> 85 <div class="form-group mb-0"> 86 <label class="fs-medium-14 font-semibold">P. Penalty</label> 87 <div class="select-box-icon"> 88 <span class="field-icon"> 89 <div class="assets-penalty-icon"></div> 90 </span> 91 <input type="text" name="p-penalty" placeholder="0" id="p-penalty" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" value="0"> 92 <span class="small-text text-muted">Reduces repetition of new words in the response.</span> 93 </div> 94 </div> 95 </div> 96 </div> 100 97 <div class="divider-light"></div> 101 98 <div class="row justify-content-center"> 102 <div class="col-lg-6" id="api-key-management"> 103 <div class="api-key-icon select-box-icon d-flex justify-content-around align-items-center" onclick="ai_app_onsite_get_openapi_data()"> 104 <span class="#"> 105 <div class="assets-api-key-icon"></div> 106 </span> 107 <p class="mb-0 fs-6 cursor-pointer" data-bs-toggle="modal" data-bs-target="#apiinfoModal"> 108 API Key Management 109 </p> 110 111 <span class="mb-0"> 112 <p id="key-status" class="mb-0 font-semibold fs-6"></p> 113 </span> 114 </div> 115 116 <p id="manage-key-error" class="mt-2 ml-3 fields-error"></p> 99 <div class="col-lg-6" id="api-key-management"> 100 <div class="api-key-icon select-box-icon d-flex justify-content-around align-items-center" onclick="ai_app_onsite_get_openapi_data()"> 101 <span class="#"> 102 <div class="assets-api-key-icon"></div> 103 </span> 104 <p class="mb-0 fs-6 cursor-pointer" data-bs-toggle="modal" data-bs-target="#apiinfoModal"> API Key Management </p> 105 <span class="mb-0"> 106 <p id="key-status" class="mb-0 font-semibold fs-6"></p> 107 </span> 117 108 </div> 118 <div class="col-lg-6"> 119 <div class="text-end"> 120 <button type="button" id="cancel_ai_app_plugin_settings_data" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="save-plugin-settings" onclick="reset()">Reset to Default</button> 121 <button type="button" id="save_ai_app_plugin_settings_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_save_model_settings()">Save</button> 122 </div> 109 <p id="manage-key-error" class="mt-2 ml-3 fields-error"></p> 110 </div> 111 <div class="col-lg-6"> 112 <div class="text-end"> 113 <button type="button" id="cancel_ai_app_plugin_settings_data" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="save-plugin-settings" onclick="reset()">Reset to Default</button> 114 <button type="button" id="save_ai_app_modal_settings_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_save_model_settings()">Save</button> 123 115 </div> 124 116 </div> 117 </div> 125 118 </form> 126 127 119 <!-- Modal --> 128 120 <div class="modal fade bd-example-modal-sm plugin-setting" id="apiinfoModal" tabindex="-1" role="dialog" aria-labelledby="apiinfoModalLabel" aria-hidden="true"> 129 121 <div class="modal-dialog modal-sm modal-400 modal-dialog-centered" role="document"> 130 <div class="modal-content"> 131 <div id="modal-message-container" class="message-container"></div> 132 <div class="modal-header"> 133 <h5 class="fs-bold-16 mb-0 logo-bg-fixed-sm" id="terms_conditions_modal_label"> 134 </h5> 135 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 122 <div class="modal-content"> 123 <div id="modal-message-container" class="message-container"></div> 124 <div class="modal-header"> 125 <h5 class="fs-bold-16 mb-0 logo-bg-fixed-sm" id="terms_conditions_modal_label"></h5> 126 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 127 </div> 128 <div class="modal-body"> 129 <p class="fs-regular-14 neutral-black-fs-100">Please enter your OpenAI API key below. You can get an API key from your <a href="https://openai.com/api/" class="neutral-black-fs-100 underline open-new-tab"> OpenAI account dashboard.</a> 130 </p> 131 <div class="form-group mb-0"> 132 <label class="fs-medium-14 fw-semibold">API Key</label> 133 <div class="select-box-icon right-icon"> 134 <span class="field-icon copy-api-key"> 135 <div class="assets-copy-icon"></div> 136 </span> 137 <input type="text" name="openai-key" placeholder="Enter text" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" id="openai-key"> 138 <input type="hidden" name="openai-key-hidden" id="openai-key-hidden"> 136 139 </div> 137 <div class="modal-body"> 138 <p class="fs-regular-14 neutral-black-fs-100">Please enter your OpenAI API key below. You can get an API key from your <a href="" class="neutral-black-fs-100 underline"> OpenAI account dashboard.</a></p> 139 <div class="form-group mb-0"> 140 <label class="fs-medium-14 fw-semibold">API Key</label> 141 <div class="select-box-icon right-icon"> 142 <span class="field-icon copy-api-key"> 143 <div class="assets-copy-icon"></div> 144 </span> 145 <input type="text" name="openai-key" placeholder="Enter text" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" id="openai-key"> 146 <input type="hidden" name="openai-key-hidden" id="openai-key-hidden"> 147 </div> 148 <div class="d-flex justify-content-start align-items-center mt-2 key-toggle"> 149 <span id="maskToggle" class="text-muted me-3 mask__toggle">Show Key</span> 150 </div> 151 <p id="openai-key-error" class="fields-error"></p> 152 </div> 153 <p class="fs-regular-12 neutral-black-fs-60 mb-1 mt-2">Note: Your API key will be stored locally and securely in your browser and never shared.</p> 154 <div class="flex-row alignment-items-center mt-3 mb-3"> 155 <div class="col-50"> 156 <button class="btn remove-btn align-items-center" id="key-remove-btn" onclick="ai_app_onsite_clear_openapi_Key_field()"> 157 <span class="btn-icon me-1"> 158 <div class="assets-delete-icon"></div> 159 </span> Remove API Key 160 </button> 161 </div> 162 <div class="col-50"> 163 <div class="enable-switch-box d-flex justify-content-between align-items-baseline"> 164 <span class="fs-medium-14 text-switch me-2" id="text-switch">Disabled</span> 165 <label class="switch"> 166 <input type="checkbox" id="api-disable-btn" onchange="ai_app_onsite_disable_openapi_key()"> 167 <span class="slider round"></span> 168 </label> 169 </div> 170 </div> 171 </div> 172 <div class="divider-light mt-2 mb-3"></div> 173 <div class="button-wrap"> 174 <button type="button" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-white" name="save-plugin-settings" data-bs-dismiss="modal">Cancel</button> 175 <button type="button" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-purple text-white" name="save-openapi-key" id="save-openapi-key" onclick="save_openapi_key()">Save</button> 176 </div> 140 <div class="d-flex justify-content-start align-items-center mt-2 key-toggle"> 141 <span id="maskToggle" class="text-muted me-3 mask__toggle">Show Key</span> 142 </div> 143 <p id="openai-key-error" class="fields-error"></p> 144 </div> 145 <p class="fs-regular-12 neutral-black-fs-60 mb-1 mt-2">Note: Your API key will be stored locally and securely in your browser and never shared.</p> 146 <div class="flex-row alignment-items-center mt-3 mb-3"> 147 <div class="col-50"> 148 <button class="btn remove-btn align-items-center" id="key-remove-btn" onclick="ai_app_onsite_clear_openapi_Key_field()"> 149 <span class="btn-icon me-1"> 150 <div class="assets-delete-icon"></div> 151 </span> Remove API Key </button> 152 </div> 153 <div class="col-50"> 154 <div class="enable-switch-box d-flex justify-content-between align-items-baseline"> 155 <span class="fs-medium-14 text-switch me-2" id="text-switch">Disabled</span> 156 <label class="switch"> 157 <input type="checkbox" id="api-disable-btn" onchange="ai_app_onsite_disable_openapi_key()"> 158 <span class="slider round"></span> 159 </label> 160 </div> 177 161 </div> 178 162 </div> 163 <div class="divider-light mt-2 mb-3"></div> 164 <div class="button-wrap"> 165 <button type="button" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-white" name="save-plugin-settings" data-bs-dismiss="modal">Cancel</button> 166 <button type="button" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-purple text-white" name="save-openapi-key" id="save-openapi-key" onclick="save_openapi_key()">Save</button> 167 </div> 168 </div> 169 </div> 179 170 </div> 180 171 </div> 172 <!-- Modal --> 181 173 </div> 182 174 <div id="model-settings-msg-container" class="message-container"></div> -
ai-app-onsite/trunk/includes/class-ai-app-onsite-plugin-settings.php
r3281201 r3307540 1 1 <?php 2 if (! class_exists('AI_App_Onsite_Plugin_Settings')) { 3 class AI_App_Onsite_Plugin_Settings 4 { 5 public static function render_plugin_settings() 6 { 7 $plugin_data = get_plugin_data(WP_PLUGIN_DIR . '/ai-app-onsite/ai-app-onsite.php'); 8 $version = $plugin_data['Version']; 9 ob_start(); ?> 10 <div class="form-wrapper"> 11 <form enctype="multipart/form-data"> 12 <?php wp_nonce_field('ai_app_onsite_plugin_settings_nonce', 'ai_app_onsite_plugin_settings_nonce_field'); ?> 13 <div class="mb-20"> 14 <div class="d-flex justify-content-between mb-0 align-items-center"> 15 <p class="font-bold fs-5 mb-0">Get Started</p> 16 <p class="fs-regular-14 neutral-black-fs-60 mb-0">Version: <?php echo $version; ?></p> 2 if (!class_exists("AI_App_Onsite_Plugin_Settings")) { 3 class AI_App_Onsite_Plugin_Settings 4 { 5 public static function render_plugin_settings() 6 { 7 $plugin_data = get_plugin_data(plugin_dir_path(__DIR__) . "/ai-app-onsite.php"); 8 $version = $plugin_data["Version"]; 9 ob_start(); 10 ?> 11 <div class="app-plugin-settings"> 12 <div class="form-wrapper"> 13 <div class="col-12 col-md-12"> 14 <div class="row d-flex align-items-center mb-2"> 15 <div class="col-md-6"> 16 <p class="font-bold fs-5 mb-0">Access Key</p> 17 </div> 18 <div class="col-md-6"> 19 <div class="api-key-icon d-flex justify-content-end align-items-center"> 20 <span class="px-3" > 21 <div class="assets-api-key-icon"> </div> 22 </span> 23 <p class="fs-7 cursor-pointer mb-0" data-bs-toggle="modal" data-bs-target="#license_key_info_modal"> 24 Key Management 25 </p> 26 </div> 27 </div> 28 </div> 29 <div class="row d-flex align-items-center"> 30 <div class="col-md-12"> 31 <p class="fs-7 mb-0">Unlock powerful extra features with an AIappOnsite premium plan. <a href="https://aiapponsite.com/pricing" class="open-new-tab">Learn more</a> and get your access key now</p> 32 </div> 33 </div> 34 <div class="row d-flex justify-content-center mt-3"> 35 <div class="col-12 col-md-4 align-items-center mb-3" id="license_status"> 36 <div class="row d-flex"> 37 <label for="licence_key" class="d-block fs-regular-10 mb-only-4">Verification Status</label> 38 <p class="font-bold mb-1" id="license_key_status"></p> 39 </div> 40 </div> 41 <div class="col-12 col-md-4 align-items-center mb-3" id="expiry_status"> 42 <div class="row d-flex"> 43 <label for="licence_key" class="d-block fs-regular-10 mb-only-4">Exipry Date</label> 44 <p class="font-bold mb-1" id="license_key_expiry_date"></p> 45 </div> 46 </div> 47 <div class="col-12 col-md-4 align-items-center mb-3" id="key_status"> 48 <div class="row d-flex"> 49 <label for="licence_key" class="d-block fs-regular-10 mb-only-4">Key Status</label> 50 <p class="font-bold mb-1" id="license_key_disabled_status"></p> 51 </div> 52 </div> 53 </div> 54 <div class="divider-light mt-2 mb-2"></div> 55 </div> 56 <form enctype="multipart/form-data" id="app_settings_form"> 57 <?php wp_nonce_field("ai_app_onsite_plugin_settings_nonce","ai_app_onsite_plugin_settings_nonce_field"); ?> <div class="mb-20"> 58 <div class="d-flex justify-content-between mb-0 align-items-center"> 59 <p class="font-bold fs-5 mb-0">Get Started</p> 60 <p class="fs-regular-14 neutral-black-fs-60 mb-0">Version: <?php echo $version; ?> </p> 61 </div> 62 <div class="terms-form-group form-group mb-0"> 63 <input type="checkbox" id="terms_of_service-old" name="terms_of_service-old" onchange="uploadTermCondition(this)"> 64 <label for="terms_of_service-old" data-toggle="modal" data-target=".bd-example-modal-sm" class="custom-checkbox fs-medium-14 "> 65 <span class="ml-1">Agree to Terms of Service</span> 66 </label> 67 </div> 68 <p class="fs-regular-14 ml-25 mb-1 text-muted"> You must agree to the terms of service to use this plugin. Please read the terms carefully before proceeding. </p> 69 <p id="terms_of_service-error" class="ml-25 fields-error"></p> 70 </div> 71 <div class="mb-3 app_selector_input"> 72 <label for="app_selector_input" class="d-block fs-medium-14 mb-only-4 app_selector_input_label" >Create Your First App <span class="text-danger">*</span> 73 </label> 74 <div class="select-box-icon"> 75 <span class="field-icon"> 76 <div class="assets-folder-icon"></div> 77 </span> 78 <input type="text" id="app_selector" name="app_selector" placeholder="Please Enter Your App Name" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8"> 79 </div> 80 </div> 81 <div class="mb-3"> 82 <label for="email-notification" class="d-block fs-medium-14 mb-only-4">App Email (for form data passing) <span class="fs-regular-14"></span> 83 </label> 84 <div class="select-box-icon"> 85 <span class="field-icon"> 86 <div class="assets-email-icon"></div> 87 </span> 88 <input type="email" name="app_email" id="app_email" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8"> 89 </div> 90 </div> 91 <div class="mb-3"> 92 <label class="d-block fs-medium-14 mb-only-4">Banned/blocked words (comma Separated)</label> 93 <div class="multi-select-container select-box-icon mb-20 fs-regular-14 neutral-black-fs-100 border border-1 radius-6 px-10 py-8"> 94 <span class="field-icon"> 95 <div class="assets-banned-icon"></div> 96 </span> 97 <div class="multi-select"> 98 <select multiple data-multi-select-plugin id="bannedWords" name="bannedWords"></select> 99 </div> 100 </div> 101 </div> 102 <div class="form-group"> 103 <label class="fs-medium-14">Upload Banned/Block CSV</label> 104 <div class="file-drop-area border "> 105 <span class="fake-btn"> 106 <div class="assets-upload-file-icon"></div> 107 </span> 108 <div> 109 <p class="file-msg-top mb-0 neutral-black-fs-110"> 110 <span class="text-purple">Click to upload</span> or drag and drop 111 </p> 112 <p class="neutral-black-fs-50 mb-0 fs-regular-12">CSV</p> 113 </div> 114 <input class="file-input" type="file" id="csv-upload" name="csv-file" accept=".csv" onchange="validateCSVFile(this)"> 115 </div> 116 <p id="fileError" class="mt-1 fields-error"></p> 117 </div> 118 <div class="divider-light"></div> 119 <div class="text-end"> 120 <button type="button" id="cancel_ai_app_plugin_settings_data" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="save-plugin-settings">Cancel</button> 121 <button type="button" id="save_ai_app_plugin_settings_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_save_plugin_settings()">Save</button> 122 </div> 123 </form> 124 </div> 125 <!-- Modal --> 126 <div class="modal fade bd-example-modal-sm plugin-setting" id="license_key_info_modal" tabindex="-1" role="dialog" aria-labelledby="license_key_info_modalLabel" aria-hidden="true"> 127 <div class="modal-dialog modal-sm modal-400 modal-dialog-centered" role="document"> 128 <div class="modal-content"> 129 <div id="modal-message-container" class="message-container"></div> 130 <div class="modal-header"> 131 <h5 class="fs-bold-16 mb-0" id="terms_conditions_modal_label">AIappOnsite Access Key</h5> 132 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 133 </div> 134 <div class="modal-body"> 135 <form method="POST" id="license-validation-form" enctype="multipart/form-data"> 136 <?php wp_nonce_field('ai_app_onsite_app_verify_license_key_nonce', 'ai_app_onsite_app_verify_license_key_nonce_field'); ?> 137 <p class="fs-regular-14 neutral-black-fs-100">Enter your access key to enable Aiapponsite premium features. For more details, visit our <a href="https://aiapponsite.com/pricing" class="open-new-tab">pricing page</a>. </p> 138 <div class="form-group mb-0"> 139 <label class="fs-medium-14 fw-semibold">Access Key *</label> 140 <div class="select-box-icon right-icon"> 141 <input type="text" id="licence_key" name="licence_key" class="border border-1 w-100 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8 mt-2" required> 142 <input type="hidden" id="licence_key_hidden" name="licence_key_hidden"> 143 </div> 144 </div> 145 <div class="row align-items-center my-2"> 146 <div class="col-md-12" id="key_note"> 147 <p class="fs-regular-12 text-opacity-50 text-dark fst-italic">Enter your Premium Add-On access key.</p> 148 </div> 149 </div> 150 <div class="divider-light mt-2 mb-3"></div> 151 <div class="row d-flex align-items-center mt-3 mb-3"> 152 <div class="col-md-12"> 153 <p class="text-muted text-center">You can find and manage your access key on <a href="https://aiapponsite.com/my-account/" class="open-new-tab">My Account</a>. </p> 154 </div> 155 </div> 156 <div class="flex-row alignment-items-center mt-3 mb-3"> 157 <div class="col-50"> 158 <button type="button" class="btn remove-btn align-items-center" id="remove_ai_app_plugin_license_key" onclick="ai_app_onsite_app_remove_license_key()"> 159 <span class="btn-icon me-1"> 160 <div class="assets-delete-icon"></div> 161 </span> Remove Key</button> 162 </div> 163 <div class="col-50"> 164 <div class="enable-switch-box d-flex justify-content-between align-items-baseline"> 165 <span class="fs-medium-14 text-switch me-2" id="license-text-switch">Disabled</span> 166 <label class="switch"> 167 <input type="checkbox" id="key-disable-btn" onchange="ai_app_onsite_disable_license_key()"> 168 <span class="slider round"></span> 169 </label> 170 </div> 171 </div> 17 172 </div> 18 <div class="terms-form-group form-group mb-0"> 19 <input type="checkbox" id="terms_of_service-old" onchange="uploadTermCondition(this)"> 20 <label for="terms_of_service-old" data-toggle="modal" data-target=".bd-example-modal-sm" class="custom-checkbox fs-medium-14 "><span class="ml-1">Agree to Terms of Service</span></label> 21 </div> 22 <p class="fs-regular-14 ml-25 mb-1 text-muted"> 23 You must agree to the terms of service to use this plugin. Please read the terms carefully before proceeding. 24 </p> 25 <p id="terms_of_service-error" class="ml-25 fields-error"></p> 26 </div> 27 28 <div class="mb-3"> 29 <label for="app-selector" class="d-block fs-medium-14 mb-only-4">App/Project Selector 30 <span class="fs-regular-14">(Multiple Apps With Premium)</span></label> 31 <div class="select-box-icon"> 32 <span class="field-icon"> 33 <div class="assets-folder-icon"></div> 34 </span> 35 <input type="text" id="app_selector" name="app_selector" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8" disabled> 36 </div> 37 </div> 38 39 40 <div class="mb-3"> 41 <label for="email-notification" class="d-block fs-medium-14 mb-only-4">App Email (for form data passing) 42 <span class="fs-regular-14"></span></label> 43 <div class="select-box-icon"> 44 <span class="field-icon"> 45 <div class="assets-email-icon"></div> 46 </span> 47 <input type="email" name="app_email" id="app_email" class="border border-1 w-100 mb-1 fs-regular-14 neutral-black-fs-60 radius-6 px-10 py-8"> 48 </div> 49 </div> 50 51 52 <div class="mb-3"> 53 <label class="d-block fs-medium-14 mb-only-4">Banned/blocked words (comma Separated)</label> 54 <div class="multi-select-container select-box-icon mb-20 fs-regular-14 neutral-black-fs-100 border border-1 radius-6 px-10 py-8"> 55 <span class="field-icon"> 56 <div class="assets-banned-icon"></div> 57 </span> 58 <div class="multi-select"> 59 <select multiple data-multi-select-plugin id="bannedWords"> 60 61 </select> 62 </div> 63 </div> 64 65 </div> 66 <div class="form-group"> 67 <label class="fs-medium-14">Upload Banned/Block CSV</label> 68 <div class="file-drop-area border "> 69 <span class="fake-btn"> 70 <div class="assets-upload-file-icon"></div> 71 </span> 72 <div> 73 <p class="file-msg-top mb-0 neutral-black-fs-110"><span class="text-purple">Click to upload</span> or drag and drop</p> 74 <p class="neutral-black-fs-50 mb-0 fs-regular-12">CSV</p> 75 </div> 76 <input class="file-input" type="file" id="csv-upload" name="csv-file" accept=".csv" onchange="validateCSVFile(this)"> 77 </div> 78 79 <p id="fileError" class="mt-1 fields-error"></p> 80 </div> 81 82 <div class="divider-light"></div> 83 84 <div class="text-end"> 85 <button type="button" id="cancel_ai_app_plugin_settings_data" role="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="save-plugin-settings">Cancel</button> 86 <button type="button" id="save_ai_app_plugin_settings_data" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" name="save-plugin-settings" onclick="ai_app_onsite_save_plugin_settings()">Save</button> 87 </div> 88 89 </form> 90 </div> 91 <div id="Plugin-settings-msg-container" class="message-container"></div> 92 93 94 <?php 173 <div class="button-wrap"> 174 <button type="button" role="button" id="cancel" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-white" name="save-plugin-settings" data-bs-dismiss="modal" data-role="cancel" >Cancel</button> 175 <button type="button" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-6 px-16 border border-2 bg-purple text-white" name="active-plugin-licence-key" id="active_ai_app_plugin_license_key" onclick="ai_app_onsite_app_verify_license_key()">Save</button> 176 </div> 177 </form> 178 <div id="app-license-msg-container" class="message-container mb-3"></div> 179 </div> 180 </div> 181 </div> 182 </div> 183 <!-- Modal --> 184 <div id="Plugin-settings-msg-container" class="message-container"></div> 185 </div> 186 <?php 95 187 return ob_get_clean(); 96 188 } -
ai-app-onsite/trunk/includes/class-ai-app-onsite-prompt-editor.php
r3272415 r3307540 10 10 <!-- Render your plugin setting tab page here --> 11 11 <div> 12 <form class="form-wrapper" >12 <form class="form-wrapper" id="prompt-editor"> 13 13 <?php wp_nonce_field('ai_app_onsite_prompt_editor_nonce', 'ai_app_onsite_prompt_editor_nonce_field'); ?> 14 14 <div class="form-group"> … … 52 52 <div class="text-end"> 53 53 <button type="button" class="btn fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-white" name="save-plugin-settings">Cancel</button> 54 <button type="button" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" onclick="ai_app_onsite_save_prompt_editor()">Save</button>54 <button type="button" class="btn btn-purple fs-medium-14 neutral-black-fs-60 radius-6 py-8 px-16 border border-2 bg-purple-100 text-white" id="ai_app_onsite_save_prompt_editor" onclick="ai_app_onsite_save_prompt_editor()">Save</button> 55 55 </div> 56 56 </div> -
ai-app-onsite/trunk/readme.md
r3281194 r3307540 5 5 **Requires at least:** 4.7 6 6 **Tested up to:** 6.7.1 7 **Stable tag:** 1.2. 27 **Stable tag:** 1.2.3 8 8 **Requires PHP:** 7.0 9 9 **License:** GPLv2 or later … … 75 75 - Initial release. 76 76 ### 1.1.0 77 - Improved script loading with conditional checks 78 - Enhanced Bootstrap conflict prevention 79 - Added settings link in plugins list 80 - Improved performance and stability 81 - Fixed CSS issues 82 - Added auto-open last active tab feature 83 ### 1.1.1 84 - Updated plugin settings parameters for improved compatibility 85 - Fixed getplugindata function for better performance 77 - CSS issue & Auto open last tab 78 79 ### 1.4.3 80 - Fix - the app would not load correctly on some themes. 81 - Update - Improved compatibility with the latest WordPress version. 82 - Update - Updated the plugin to use the latest API endpoints for better performance and reliability. 83 - Fix - Enhanced the user interface for easier navigation and app creation. 84 - Fix - Improved error handling and user feedback during app interactions. 85 - Add - Added a new feature to allow users to save and create multiple app configurations for easier management. 86 - Update - Enhanced security measures to protect user data and API keys. 87 - Add - Added a new feature to allow users to preview their app with shadow and border-radius settings before publishing. 88 - Update - Field selector now supports more number of fields. 89 86 90 87 91 --- 88 92 89 93 ## Upgrade Notice 90 91 ### 1.1.192 - Upgrade to version 1.1.1 for improved plugin settings compatibility and better performance.93 94 ### 1.1.095 - Upgrade to version 1.1.0 for improved performance, stability, and enhanced Bootstrap compatibility.96 94 97 95 ### 1.0.0 -
ai-app-onsite/trunk/readme.txt
r3281194 r3307540 4 4 Requires at least: 4.7 5 5 Tested up to: 6.7.1 6 Stable tag: 1.2. 26 Stable tag: 1.2.3 7 7 Requires PHP: 7.0 8 8 License: GPLv2 or later … … 56 56 == Changelog == 57 57 58 = 1.2.3 = 59 * Fix - Resolved app loading issues on certain themes 60 * Update - Improved compatibility with the latest WordPress version 61 * Update - Enhanced API endpoints for better performance and reliability 62 * Fix - Improved user interface for easier navigation and app creation 63 * Fix - Enhanced error handling and user feedback during app interactions 64 * Add - New feature to save and manage multiple app configurations 65 * Update - Enhanced security measures to protect user data and API keys 66 * Add - Preview feature with shadow and border-radius settings 67 * Update - Expanded field selector support 68 58 69 = 1.2.2 = 59 70 * Added ability for users to like or dislike a response from the app … … 75 86 == Upgrade Notice == 76 87 88 = 1.2.3 = 89 * Upgrade to version 1.2.3 for improved theme compatibility, enhanced user interface, better error handling, multiple app configurations, and expanded field selector support. 90 77 91 = 1.2.2 = 78 92 * Upgrade to version 1.2.2 to allow users to like or dislike responses from the app. … … 87 101 * First release of AI App Onsite, offering AI-powered app creation and customization within WordPress. 88 102 103 89 104 == External Services == 90 105
Note: See TracChangeset
for help on using the changeset viewer.