Plugin Directory

Changeset 3446048


Ignore:
Timestamp:
01/24/2026 09:59:43 AM (2 months ago)
Author:
technodrome
Message:

4.0.4 version - functions fixes

Location:
technodrome-ai-content-assistant/trunk
Files:
33 edited

Legend:

Unmodified
Added
Removed
  • technodrome-ai-content-assistant/trunk/CHANGELOG.md

    r3434643 r3446048  
    66and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
    77
    8 ## [4.0.0] - 2026-01-07
     8## [4.0.4] - 2026-01-22
     9
     10### Added
     11- **Video Slot Renaming**: Slots now show descriptive names in video context modes:
     12  - "GENERATE AI CONTENT FROM VIDEO URL" for Slot 1 in AI + Video URL Context mode
     13  - "GENERATE AI CONTENT FROM VIDEO CHANNEL" for Slot 2 in AI + Video Channel Context mode
     14- **UNDER CONSTRUCTION Overlay**: Added visual overlay on Slot 2 when in video context modes, indicating that channel mode is not yet implemented
     15- **Mode-Specific Transformation**: Video slot renaming and overlays only apply when in video context modes, keeping regular modes unchanged
     16
     17### Changed
     18- Updated video-slot-transformation.js to handle slot renaming and UNDER CONSTRUCTION overlay
     19- Modified transformation logic to only apply in AI + Video URL Context and AI + Video Channel Context modes
     20- Added visual feedback with yellow/orange gradient UNDER CONSTRUCTION badge
     21
     22### Improved
     23- Better user guidance in video context modes
     24- Clearer distinction between active and locked slots
     25- Consistent UI experience across all modes
     26
     27## [4.0.3] - 2026-01-21
    928
    1029### Added
  • technodrome-ai-content-assistant/trunk/changelog.txt

    r3444453 r3446048  
    33## Version 4.0.3 - 2026-01-21
    44
    5 ### BUG FIXES
    6 - **Structure Name Not Persisting:** CRITICAL FIX - Structure Name field now properly saves and loads
    7   - structure_name was missing from collectCompleteProfileData() - FIXED (added to line 540, 751)
    8   - Now included in content_rules when autosave collects profile data
    9   - Structure Name properly persists across profile switches
    10   - Fixed 3000ms debounce delay - reduced to standard 500ms for faster saves (line 54-59)
    11   - Fixed save_profile() treating update_user_meta false return as error - was blocking save when data identical
     5### CRITICAL BUG FIXES
     6- **Structure Name Not Persisting + Profile Button Not Updating:** CRITICAL FIX - Structure Name now saves and updates profile button names
     7  - Problem: structure_name was collected and saved but profile buttons weren't being updated with the value
     8  - Root Cause: updateProfileButtonsStatus() didn't ažurirati button text; switchProfile() wasn't calling it
     9  - FIX #1: Enhanced updateProfileButtonsStatus() to extract structure_name from profile and display on button (max 7 chars, uppercase)
     10  - FIX #2: Added updateProfileButtonsStatus() call in switchProfile() to update button when profile changes
     11  - FIX #3: Fixed 500ms debounce for structure_name changes (was 3000ms) for faster response
     12  - FIX #4: Fixed save_profile() to properly handle update_user_meta false return (false = data identical, not an error)
     13  - Result: Structure Name now serves as profile nickname - type "SPORT" and button shows "SPORT" instead of "Profile 1"
    1214
    1315- **Default Tone AutoSave:** Fixed Default Tone field not saving to profile
    14   - Added missing AutoSave event listener for default tone changes
     16  - Added missing DefaultTone sync in loadCompleteProfileData()
    1517  - Default Tone now persists correctly across profile switches
    16   - AutoSave notification displays when default tone is changed
    17 
    18 ### IMPROVEMENTS
    19 - Enhanced field change detection in AutoSave system
    20 - Better profile data persistence for all fields
    21 - Faster AutoSave debounce timing for Structure Name field (500ms instead of 3000ms)
    2218
    2319---
  • technodrome-ai-content-assistant/trunk/dashboard/modules/footer/footer.php

    r3444346 r3446048  
    7878                    $taics_color = taics_get_profile_color($taics_i);
    7979                    $taics_is_active = ($taics_i == $taics_active_profile);
    80                     // v4.0.2: Get custom profile name from user_meta, fallback to "PROFILE"
    81                     $taics_custom_name = get_user_meta($taics_user_id, 'taics_profile_' . $taics_i . '_name', true);
    82                     $taics_profile_label = !empty($taics_custom_name) ? strtoupper(substr($taics_custom_name, 0, 7)) : 'PROFILE';
    8380                    /* translators: %d is the index number of the profile button */
    84                     $taics_title_text = sprintf(esc_attr__('Profile %d (%s)', 'technodrome-ai-content-assistant'), $taics_i, $taics_profile_label);
     81                    $taics_title_text = sprintf(esc_attr__('Profile %d', 'technodrome-ai-content-assistant'), $taics_i);
    8582                ?>
    8683                <button
     
    8986                    data-color="<?php echo esc_attr($taics_color); ?>"
    9087                    data-user-plan="<?php echo esc_attr($taics_user_plan); ?>"
    91                     title="<?php echo esc_attr($taics_title_text); ?>"
    92                     id="taics-profile-btn-<?php echo esc_attr($taics_i); ?>">
     88                    title="<?php echo esc_attr($taics_title_text); ?>">
    9389                    <span class="taics-profile-number taics-profile-number-<?php echo esc_attr($taics_color); ?>"><?php echo esc_html($taics_i); ?></span>
    94                     <span class="taics-profile-text" id="taics-profile-label-<?php echo esc_attr($taics_i); ?>"><?php echo esc_html($taics_profile_label); ?></span>
     90                    <span class="taics-profile-text">PROFILE</span>
    9591                </button>
    9692                <?php endfor; ?>
  • technodrome-ai-content-assistant/trunk/features/content-rules-tab/profile-name-sync.js

    r3444453 r3446048  
    66        isSaving: false,
    77        syncTimeout: null,
     8        isLoading: false, // FIX: Use this flag instead of checking non-existent flag
    89
    910        init: function() {
    1011            this.bindEvents();
    11             this.loadCurrentProfileName();
    1212        },
    1313
    1414        bindEvents: function() {
    15             // Listen for profile changes to load the Structure Name from profile data
     15            // DVT v4.0.5.2: Listen for ALL profiles loaded event - updates ALL button labels
     16            $(document).off('taics_all_profiles_loaded.profile-name');
     17            $(document).on('taics_all_profiles_loaded.profile-name', (e, profiles) => {
     18                this.updateAllProfileButtonLabels();
     19            });
     20
     21            // DVT v4.0.5.2: Listen for ALL profile loads (both initial and changes)
     22            $(document).off('taics_profile_loaded.taics-all-profiles');
     23            $(document).on('taics_profile_loaded.taics-all-profiles', (e) => {
     24                // After any profile load, update ALL profile button labels
     25                this.updateAllProfileButtonLabels();
     26            });
     27
     28            // Listen for FIRST profile load to load the Structure Name from profile data
    1629            $(document).off('taics_profile_loaded.profile-name');
    1730            $(document).on('taics_profile_loaded.profile-name', (e, profileNumber, profileData) => {
     31                this.isLoading = true;
    1832                this.activeProfile = profileNumber;
    19                 // Load structure_name from profile data, not from button label
    2033                this.loadStructureNameFromProfile(profileData);
     34                setTimeout(() => { this.isLoading = false; }, 50);
     35            });
     36
     37            // DVT v4.0.5.2: Listen for PROFILE CHANGES to load the Structure Name from profile data
     38            $(document).off('taics_profile_changed.profile-name');
     39            $(document).on('taics_profile_changed.profile-name', (e, profileNumber) => {
     40                this.isLoading = true;
     41                this.activeProfile = profileNumber;
     42               
     43                // Get profile data from TAICS_Profile_Buttons
     44                let actualProfileData = null;
     45                if (window.TAICS_Profile_Buttons && window.TAICS_Profile_Buttons.profiles) {
     46                    actualProfileData = window.TAICS_Profile_Buttons.profiles[profileNumber];
     47                }
     48               
     49                this.loadStructureNameFromProfile(actualProfileData);
     50                setTimeout(() => { this.isLoading = false; }, 50);
    2151            });
    2252
     
    2555            $('#taics-structure-name').on('input.profile-name blur.profile-name', () => {
    2656                // Only sync if NOT currently loading profile data
    27                 // Check flag from profile-buttons.js
    28                 const isLoading = window.TAICS_Profile_Buttons && window.TAICS_Profile_Buttons.isLoadingProfileData;
    29                 if (!isLoading) {
     57                if (!this.isLoading) {
    3058                    this.syncProfileName();
    3159                }
     
    3361        },
    3462
     63        // DVT v4.0.5.2: Update ALL profile button labels based on their Structure Names
     64        updateAllProfileButtonLabels: function() {
     65            if (!window.TAICS_Profile_Buttons || !window.TAICS_Profile_Buttons.profiles) {
     66                console.log('TAICS: profiles not loaded yet, skipping');
     67                return;
     68            }
     69           
     70            const profiles = window.TAICS_Profile_Buttons.profiles;
     71            for (const profileNum in profiles) {
     72                if (profiles.hasOwnProperty(profileNum)) {
     73                    const profileData = profiles[profileNum];
     74                    const structureName = profileData.content_rules?.structure_name || '';
     75                    this.updateButtonLabelForProfile(profileNum, structureName);
     76                }
     77            }
     78        },
     79       
     80        updateButtonLabelForProfile: function(profileNumber, customName) {
     81            // DVT v4.0.5.2: Add defensive check - ensure button element exists
     82            const $profileBtn = $(`.taics-profile-btn-wide[data-profile="${profileNumber}"]`);
     83            if ($profileBtn.length === 0) {
     84                console.log('TAICS: Button for profile ' + profileNumber + ' does not exist yet, skipping label update');
     85                return;
     86            }
     87           
     88            let displayLabel = customName.substring(0, 7).toUpperCase();
     89            displayLabel = displayLabel || 'PROFILE';
     90
     91            // DVT v4.0.5.2: Direct DOM manipulation to ensure label updates
     92            const $profileLabel = $profileBtn.find('.taics-profile-text');
     93            if ($profileLabel.length === 0) {
     94                return;
     95            }
     96           
     97            // Force text update - using both jQuery and native DOM methods
     98            $profileLabel.text(displayLabel);
     99            $profileLabel[0].textContent = displayLabel; // Native DOM update
     100
     101            const titleText = `Profile ${profileNumber} (${displayLabel})`;
     102            $profileBtn.attr('title', titleText);
     103            $profileBtn[0].title = titleText; // Native DOM update
     104        },
     105
    35106        loadStructureNameFromProfile: function(profileData) {
    36             // Load structure_name from profile data
    37107            if (profileData && profileData.content_rules && profileData.content_rules.structure_name) {
    38                 // Profile has a custom structure name - use it
    39108                const structureName = profileData.content_rules.structure_name;
    40109                $('#taics-structure-name').val(structureName);
    41                 // Update button label to match loaded name
    42110                this.updateButtonLabel(structureName);
    43111            } else {
    44                 // Profile doesn't have structure name - clear the field
    45112                $('#taics-structure-name').val('');
    46                 // Restore default button label
    47113                this.updateButtonLabel('');
    48114            }
     
    50116
    51117        updateButtonLabel: function(customName) {
    52             // Apply 7-character limit and UPPERCASE conversion
    53118            let displayLabel = customName.substring(0, 7).toUpperCase();
    54             // If empty, use "PROFILE" as fallback
    55119            displayLabel = displayLabel || 'PROFILE';
    56120
    57             // Update the profile button label
    58121            const $profileBtn = $(`.taics-profile-btn-wide[data-profile="${this.activeProfile}"]`);
    59122            const $profileLabel = $profileBtn.find('.taics-profile-text');
    60123            $profileLabel.text(displayLabel);
    61124
    62             // Update the title attribute
    63125            const titleText = `Profile ${this.activeProfile} (${displayLabel})`;
    64126            $profileBtn.attr('title', titleText);
    65127        },
    66128
    67         loadCurrentProfileName: function() {
    68             // This method is no longer used - kept for backward compatibility
    69         },
    70 
    71129        syncProfileName: function() {
    72             // Get the value from Structure Name field
    73130            let value = $('#taics-structure-name').val().trim();
    74 
    75             // Apply 7-character limit and UPPERCASE conversion
    76131            value = value.substring(0, 7).toUpperCase();
    77 
    78             // If empty, use "PROFILE" as fallback
    79132            const displayLabel = value || 'PROFILE';
    80133
    81             // Update the profile button label in real-time
    82134            const $profileBtn = $(`.taics-profile-btn-wide[data-profile="${this.activeProfile}"]`);
    83135            const $profileLabel = $profileBtn.find('.taics-profile-text');
    84136            $profileLabel.text(displayLabel);
    85137
    86             // Update the title attribute
    87138            const titleText = `Profile ${this.activeProfile} (${displayLabel})`;
    88139            $profileBtn.attr('title', titleText);
    89140
    90             // Debounce the save to server (wait 1 second after user stops typing)
     141            // Simple debounced save
    91142            clearTimeout(this.syncTimeout);
    92143            this.syncTimeout = setTimeout(() => {
    93144                this.saveProfileNameToServer(value);
    94             }, 1000);
     145            }, 500); // Reduced delay
    95146        },
    96147
     
    122173                success: (response) => {
    123174                    if (response.success) {
    124                         // Show notification
    125175                        if (window.TAICS_Notifications && typeof window.TAICS_Notifications.show === 'function') {
    126176                            const displayName = customName || 'PROFILE';
     
    154204
    155205    $(document).ready(function() {
    156         // Wait 200ms to ensure profile-buttons.js initializes first (it uses 100ms)
    157         setTimeout(() => {
    158             TAICS_Profile_Name_Sync.init();
    159             window.TAICS_Profile_Name_Sync = TAICS_Profile_Name_Sync;
    160         }, 200);
     206        TAICS_Profile_Name_Sync.init();
     207        window.TAICS_Profile_Name_Sync = TAICS_Profile_Name_Sync;
    161208    });
    162209
  • technodrome-ai-content-assistant/trunk/features/content-rules-tab/websources-input.js

    r3421276 r3446048  
    1818         */
    1919        init: function(forceInit = false) {
    20             console.log('🚀 TAICS_Websources_Input: Initializing...');
    21 
    22             console.log('🔍 Step 1: Locating DOM elements...');
     20
    2321
    2422            this.$container = $('#taics-web-sources-list');
     
    2725
    2826            // ENHANCED: Detailed DOM element logging
    29             console.log('📦 DOM Elements Check:');
    30             console.log('   - Container (#taics-web-sources-list):', this.$container.length > 0 ? 'FOUND' : 'MISSING');
    31             console.log('   - Add Button (#taics-add-source):', this.$addButton.length > 0 ? 'FOUND' : 'MISSING');
    32             console.log('   - Counter (#taics-sources-counter):', this.$counter.length > 0 ? 'FOUND' : 'MISSING');
    3327
    3428            if (!this.$container.length) {
    35                 console.log('❌ TAICS_Websources_Input: Container not found, aborting');
    3629                return;
    3730            }
     
    3932            this.$list = this.$container;
    4033
    41             console.log('🔍 Step 3: Setting up initial data...');
    4234
    4335            // Load empty slots if list is empty
    4436            if (this.$list.children().length === 0) {
    45                 console.log('📝 TAICS_Websources_Input: Loading empty slots...');
    4637                this.setValue(['', '', '', '', '']);
    4738            }
    4839
    49             console.log('🔍 Step 4: Binding events...');
    5040            this.bindEvents();
    5141
    52             console.log('🔍 Step 5: Updating UI...');
    5342            this.updateCounter();
    5443            this.updateAllStatusLights();
    5544
    56             console.log('✅ TAICS_Websources_Input: Initialized successfully');
    5745
    5846            // Log final state for debugging
     
    6755        logFinalState: function() {
    6856            const itemCount = this.$list ? this.$list.find('.taics-web-source-item').length : 0;
    69             console.log('📊 Final State:');
    70             console.log('   - Total source items:', itemCount);
    71             console.log('   - Container exists:', !!this.$container);
    72             console.log('   - Add button exists:', !!this.$addButton);
    73             console.log('   - Counter exists:', !!this.$counter);
    7457
    7558            // Log each source item
     
    7962                    const $input = $item.find('.taics-web-source-input');
    8063                    const $light = $item.find('.taics-url-status-light');
    81                     console.log(`   Item ${index + 1}:`, {
     64                    console.log('Source item:', index, {
    8265                        value: $input.val(),
    8366                        status: $light.attr('class'),
     
    9275         */
    9376        bindEvents: function() {
    94             console.log('TAICS_Websources_Input: Binding events...');
    9577
    9678            // Add source button
    9779            if (this.$addButton.length) {
    9880                this.$addButton.on('click.taicsSources', this.handleAddSource.bind(this));
    99                 console.log('TAICS_Websources_Input: Add source button event bound');
    10081            }
    10182
     
    10384            if ($('#taics-check-sources').length) {
    10485                $('#taics-check-sources').on('click.taicsSources', this.handleCheckAllSources.bind(this));
    105                 console.log('TAICS_Websources_Input: Check sources button event bound');
    10686            }
    10787
    10888            // Remove source buttons
    10989            $(document).on('click.taicsSources', '.taics-remove-source', this.handleRemoveSource.bind(this));
    110             console.log('TAICS_Websources_Input: Remove source events bound');
    11190
    11291            // Input change - update counter AND real-time validation feedback
     
    132111                $(document).trigger('taics_websources_changed.autosave');
    133112            }.bind(this));
    134             console.log('TAICS_Websources_Input: Input events bound');
    135113
    136114            // Enter key to add new source
    137115            $(document).on('keypress.taicsSources', '.taics-web-source-input', this.handleKeyPress.bind(this));
    138             console.log('TAICS_Websources_Input: Keypress events bound');
    139116        },
    140117
     
    144121        handleAddSource: function(e) {
    145122            e.preventDefault();
    146             console.log('TAICS_Websources_Input: Add source clicked');
    147123
    148124            const currentCount = this.getSourcesCount();
    149125
    150126            if (currentCount >= this.maxSources) {
    151                 console.log('TAICS_Websources_Input: Maximum sources reached');
    152127                if (window.TAICS_Notifications) {
    153128                    window.TAICS_Notifications.show('Maximum ' + this.maxSources + ' sources allowed', 'warning');
     
    208183        handleCheckAllSources: function(e) {
    209184            e.preventDefault();
    210             console.log('🔍 TAICS_Websources_Input: Check sources clicked');
    211185
    212186            if (!this.$list || !this.$list.length) {
    213                 console.log('❌ TAICS_Websources_Input: No sources list found');
    214187                this.showNotificationWithFallback('No sources found to check', 'warning');
    215188                return;
     
    234207                if (url) {
    235208                    checkedCount++;
    236                     console.log(`🔍 TAICS_Websources_Input: Checking URL ${i + 1}/${$sources.length}:`, url);
    237209                    const isValid = this.performSimpleCheck(url);
    238210                    const $light = $item.find('.taics-url-status-light');
     
    241213                        $light.removeClass('status-typing status-empty').addClass('status-valid');
    242214                        validCount++;
    243                         console.log(`✅ TAICS_Websources_Input: Valid URL ${i + 1} found`);
    244215                    } else {
    245216                        $light.removeClass('status-typing status-valid').addClass('status-empty');
    246                         console.log(`❌ TAICS_Websources_Input: Invalid URL ${i + 1} found`);
    247217                    }
    248218                }
     
    252222            try {
    253223                $checkButton.prop('disabled', false).text('🔍 Check the entered websources');
    254                 console.log('✅ TAICS_Websources_Input: Check completed. Valid domains:', validCount, 'out of', checkedCount, 'checked');
    255224
    256225                // Enhanced feedback - log the check process
    257                 console.log(`📊 Check Results Summary:`);
    258                 console.log(`   - Total sources found: ${$sources.length}`);
    259                 console.log(`   - Sources checked: ${checkedCount}`);
    260                 console.log(`   - Valid domains: ${validCount}`);
    261                 console.log(`   - Invalid domains: ${checkedCount - validCount}`);
    262226
    263227                if (checkedCount === 0) {
    264                     console.log('🔍 No URLs entered - showing notification');
    265228                    this.showNotificationWithFallback('No URLs entered to check', 'warning');
    266229                } else if (validCount > 0) {
    267                     console.log('✅ Valid domains found - showing success notification');
    268230                    this.showSaveNotificationSummaryWithFallback(validCount, $sources.length);
    269231                } else {
    270                     console.log('❌ No valid domains - showing error with suggestions');
    271232                    this.showNotificationWithFallback(`No valid domains found. Try: wikipedia.org, google.com, bbc.com`, 'warning');
    272233                }
     
    338299         */
    339300        performSimpleCheck: function(url) {
    340             console.log('🔍 Checking domain:', url);
    341301
    342302            // Clean URL (remove http://, https://, www.)
     
    345305            // Basic format validation - must match domain.tld pattern
    346306            if (!cleanDomain.match(/^[a-z0-9.-]+\.[a-z]{2,}$/i)) {
    347                 console.log('❌ Invalid domain format:', cleanDomain);
    348307                return false;
    349308            }
     
    352311            const parts = cleanDomain.split('.');
    353312            if (parts.length < 2) {
    354                 console.log('❌ Domain too short:', cleanDomain);
    355313                return false;
    356314            }
     
    359317            for (let part of parts) {
    360318                if (part.length === 0 || part.length > 63) {
    361                     console.log('❌ Invalid part length:', part);
    362319                    return false;
    363320                }
    364321                if (part.startsWith('-') || part.endsWith('-')) {
    365                     console.log('❌ Invalid domain part (dash):', part);
    366322                    return false;
    367323                }
    368324                if (!/^[a-z0-9-]+$/i.test(part)) {
    369                     console.log('❌ Invalid characters in:', part);
    370325                    return false;
    371326                }
     
    375330            const tld = parts[parts.length - 1];
    376331            if (tld.length < 2) {
    377                 console.log('❌ TLD too short:', tld);
    378                 return false;
    379             }
    380 
    381             console.log('✅ Valid domain:', cleanDomain);
     332                return false;
     333            }
     334
    382335            return true;
    383336        },
     
    539492            // v3.4.2: Debug logging for profile-save verification
    540493            if (window.console && window.console.log && window.taicsData && window.taicsData.debug_enabled) {
    541                 console.log('TAICS Web Sources getValue():', sources);
    542494            }
    543495
     
    625577         */
    626578        showNotificationWithFallback: function(message, type = 'info') {
    627             console.log(`🔔 Notification (${type}): ${message}`);
    628579
    629580            // Try to use notifications system if available
     
    633584                    return;
    634585                } catch (e) {
    635                     console.log('❌ TAICS_Notifications failed:', e);
    636586                }
    637587            }
     
    643593                    return;
    644594                } catch (e) {
    645                     console.log('❌ Dashboard notification failed:', e);
    646595                }
    647596            }
    648597
    649598            // Fallback to browser console
    650             console.log(`%cTAICS: ${message}`, `color: ${type === 'success' ? 'green' : type === 'error' ? 'red' : 'blue'}; font-weight: bold;`);
    651599
    652600            // Last resort - simple alert
     
    654602                alert(message);
    655603            } catch (e) {
    656                 console.log('❌ All notification methods failed');
    657604            }
    658605        },
  • technodrome-ai-content-assistant/trunk/features/dashboard.js

    r3444346 r3446048  
    1313            window.TAICS_Notifications.showNotification(message, type);
    1414        } else {
    15             console.log(`📢 ${type.toUpperCase()}: ${message}`);
    1615        }
    1716    }
     
    2726            if (this.isInitialized) return;
    2827           
    29             console.log('TAICS Dashboard v2.0.1 initializing...');
    3028           
    3129            this.bindCoreEvents();
     
    3432            this.isInitialized = true;
    3533           
    36             console.log('TAICS Dashboard v2.0.1 initialized successfully');
    3734
    3835            // Inicijalizuj licencno ograničavanje
     
    5148            // Proverava da li postoje potrebni podaci za AJAX
    5249            if (!window.taicsData || !window.taicsData.ajax_url) {
    53                 console.warn('TAICS: Missing AJAX data, using fallback restrictions');
    5450                callback(this.getFallbackRestrictions());
    5551                return;
     
    6561                success: function(response) {
    6662                    if (response.success) {
    67                         console.log('License restrictions fetched successfully:', response.data);
    6863                        // CRITICAL FIX: Update the global state so all modules have the correct plan.
    6964                        if (window.taicsData && window.taicsData.user) {
     
    110105
    111106        applyRestrictions: function(restrictions) {
    112             console.log('Applying license restrictions:', restrictions);
    113107
    114108            // Log web sources status specifically
    115             console.log('TAICS: Web sources locked status:', restrictions.features_locked.web_sources);
    116109
    117110            // Ensure core fields are always enabled regardless of plan
     
    225218            }, 100);
    226219
    227             console.log(`TAICS: Switched to tab ${tabId}`);
    228220
    229221            // v3.5.4: Scroll to top tab navigation smoothly
     
    253245                   
    254246                case 'tab-content-rules':
    255                     console.log('🔀 TAICS: Switching to content-rules tab, initializing modules...');
    256247
    257248                    // ENHANCED: Apply license restrictions first, then initialize modules
     
    265256                    // ENHANCED: Web sources initialization with delay to ensure DOM is ready
    266257                    setTimeout(() => {
    267                         console.log('🔄 TAICS: Web sources delayed initialization...');
    268258                        this.initModule('TAICS_Websources_Input');
    269259                    }, 200);
     
    314304                    this.activeModules[moduleName] = true;
    315305                } else {
    316                     console.warn(`❌ TAICS: Module ${moduleName} not found or missing init method`);
    317                     console.warn(`📋 TAICS: Available modules:`, Object.keys(window).filter(key => key.startsWith('TAICS_')));
    318306                }
    319307            } catch (error) {
     
    332320                        window[moduleName].cleanup();
    333321                        this.activeModules[moduleName] = false;
    334                         console.log(`TAICS: Cleaned up ${moduleName}`);
    335322                    } catch (error) {
    336323                        console.error(`TAICS: Error cleaning up ${moduleName}:`, error);
     
    471458            setTimeout(function() {
    472459                if (window.TAICS_Websources_Input && typeof window.TAICS_Websources_Input.init === 'function') {
    473                     console.log('TAICS: Forcing web sources initialization...');
    474460                    window.TAICS_Websources_Input.init();
    475461                } else {
    476                     console.log('TAICS: Web sources module not available for forced initialization');
    477462                }
    478463            }, 500);
  • technodrome-ai-content-assistant/trunk/features/extras-tab/bulk-generator.js

    r3421276 r3446048  
    3030
    3131        init: function() {
    32             console.log('TAICS Bulk Generator initializing...');
    3332
    3433            this.activeProfileId = window.TAICS_Profile_Buttons?.activeProfile || null;
     
    5655            $('#taics-bulk-batch-size').on('change', (e) => {
    5756                this.batchSize = parseInt($(e.target).val());
    58                 console.log('Batch size changed to:', this.batchSize);
    5957            });
    6058
    6159            $('#taics-bulk-delay').on('change', (e) => {
    6260                this.delayBetweenBatches = parseInt($(e.target).val()) * 1000;
    63                 console.log('Delay changed to:', this.delayBetweenBatches, 'ms');
    6461            });
    6562        },
     
    161158
    162159            if (!this.isProcessing) {
    163                 console.log('⛔ Processing stopped');
    164160                return;
    165161            }
     
    181177
    182178            Promise.all(promises).then(() => {
    183                 console.log('✅ Batch completed');
    184179
    185180                // Update stats
     
    190185                // Delay before next batch
    191186                if (this.delayBetweenBatches > 0) {
    192                     console.log('⏳ Waiting', this.delayBetweenBatches / 1000, 'seconds before next batch...');
    193187                    setTimeout(() => {
    194188                        this.processBatch();
     
    216210                this.renderQueue();
    217211
    218                 console.log('🔄 Processing:', item.topic);
    219212
    220213                // Make AJAX request
     
    243236                            this.stats.completed++;
    244237                            this.stats.completionTimes.push(duration);
    245                             console.log('✅ Completed:', item.topic, '(' + (duration / 1000).toFixed(1) + 's)');
    246238                        } else {
    247239                            item.status = 'failed';
     
    275267         */
    276268        handleCompletion: function() {
    277             console.log('🎉 Bulk generation completed!');
    278269            this.isProcessing = false;
    279270            this.toggleButtons('idle');
     
    293284         */
    294285        handlePause: function() {
    295             console.log('⏸️ Pausing queue...');
    296286            this.isPaused = true;
    297287            this.toggleButtons('paused');
     
    303293         */
    304294        handleResume: function() {
    305             console.log('▶️ Resuming queue...');
    306295            this.isPaused = false;
    307296            this.toggleButtons('processing');
     
    318307            }
    319308
    320             console.log('⛔ Cancelling queue...');
    321309            this.isProcessing = false;
    322310            this.isPaused = false;
  • technodrome-ai-content-assistant/trunk/features/extras-tab/schedule-picker.js

    r3415822 r3446048  
    1010            this.updateSchedulerData(); // Initial load
    1111            this.schedulerInterval = setInterval(this.updateSchedulerData.bind(this), 20000); // Refresh every 20 seconds
    12             console.log('TAICS Schedule Picker Initialized');
    1312        },
    1413       
     
    1716            $('#taics-clear-schedule').on('click', this.handleClearForm.bind(this));
    1817        },
    19        
    20                         handleScheduleClick: function(e) {
     18
     19        handleScheduleClick: function(e) {
    2120            e.preventDefault();
    2221            const self = this; // Save the correct context
     
    3130
    3231            // Debug: Log values to console
    33             console.log('Schedule Click Debug:', {
     32            console.log('Schedule click debug:', {
    3433                title: title,
    3534                date: date,
     
    146145                clearInterval(this.schedulerInterval);
    147146            }
    148             console.log('TAICS Schedule Picker Cleaned Up');
    149147        }
    150148    };
  • technodrome-ai-content-assistant/trunk/features/footer/api-status.js

    r3421276 r3446048  
    1313        init: function() {
    1414            if (this.isInitialized) {
    15                 console.log('TAICS API Status already initialized, skipping...');
    1615                return;
    1716            }
    1817           
    19             console.log('Initializing API Status module');
    2018           
    2119            // Cache DOM elements
     
    3028           
    3129            this.isInitialized = true;
    32             console.log('API Status module initialized successfully');
    3330        },
    3431
     
    10299                    if (keyChanged && !this.isValidating) {
    103100                        // Only call API validation if key changed and we're not already validating
    104                         console.log('TAICS API Status: Key changed, performing API validation');
    105101                        this.lastCheckedApiKey = apiKey;
    106102                        this.validateApiKeyWithAPI(provider, apiKey);
     
    141137            const nonce = (window.taics_license && window.taics_license.nonce) ? window.taics_license.nonce : '';
    142138
    143             console.log('TAICS API Status: validateApiKeyWithAPI called for provider:', provider);
    144             console.log('TAICS API Status: Nonce available:', !!nonce);
    145139
    146140            if (!nonce) {
    147                 console.warn('TAICS API Status: Nonce not available, using format validation only');
    148141                // Fall back to format validation
    149142                if (this.validateApiKeyFormat(provider, apiKey)) {
     
    174167                },
    175168                success: function(response) {
    176                     console.log('TAICS API Status: AJAX success response:', response);
    177169                    self.isValidating = false; // Mark validation complete
    178170
     
    183175                    } else {
    184176                        // API returned error
    185                         console.warn('TAICS API Status: API returned error or empty models:', response);
    186177                        self.lastValidStatus = 'error';
    187178                        self.setStatus('error', 'Invalid API Key');
     
    233224
    234225        refresh: function() {
    235             console.log('API Status refresh clicked');
    236226            this.setStatus('checking', 'Checking...');
    237227           
     
    304294           
    305295            this.isInitialized = false;
    306             console.log('API Status module cleaned up');
    307296        }
    308297    };
  • technodrome-ai-content-assistant/trunk/features/footer/credit-toggle.js

    r3431889 r3446048  
    2020
    2121        init: function() {
    22             console.log('Initializing credit toggle module');
    2322            this.loadInitialState();
    2423            this.bindEvents();
     
    5756            this.saveCreditPreference();
    5857
    59             console.log('Credits toggled:', this.isCreditsEnabled ? 'ON' : 'OFF');
    6058        },
    6159
     
    109107                success: (response) => {
    110108                    if (response.success) {
    111                         console.log('Credit preference saved successfully');
    112109                    } else {
    113                         console.warn('Failed to save credit preference:', response.data);
    114110                    }
    115111                },
    116112                error: (xhr, status, error) => {
    117                     console.warn('AJAX error saving credit preference:', error);
    118113                },
    119114                complete: () => {
  • technodrome-ai-content-assistant/trunk/features/footer/dark-mode-toggle.js

    r3401081 r3446048  
    1313       
    1414        init: function() {
    15             console.log('Initializing dark mode toggle module');
    1615            this.loadInitialState();
    1716            this.bindEvents();
     
    4140            this.saveDarkModePreference();
    4241           
    43             console.log('Dark mode toggled:', this.isDarkModeEnabled ? 'ON' : 'OFF');
    4442        },
    4543
     
    102100                success: (response) => {
    103101                    if (response.success) {
    104                         console.log('Dark mode preference saved successfully');
    105102                    } else {
    106                         console.warn('Failed to save dark mode preference:', response.data);
    107103                    }
    108104                },
    109105                error: (xhr, status, error) => {
    110                     console.warn('AJAX error saving dark mode preference:', error);
    111106                }
    112107            });
  • technodrome-ai-content-assistant/trunk/features/footer/profile-buttons.js

    r3444453 r3446048  
    99        apiKeys: {},
    1010        isInitializing: false,
    11         isFirstProfileLoad: true,
    12         isLoadingProfileData: false,
     11        isFirstProfileLoad: true, // Track if this is the first profile load (on page init)
     12        isLoadingProfileData: false, // FIX: Flag for profile-name-sync.js compatibility
     13
     14        // AutoSave Revolution v3.4.0 - Properties
    1315        autoSaveTimeout: null,
    1416        autoSaveInProgress: false,
    15         lastChangedField: null,
    16         structureNameTimeout: null,
     17        lastChangedField: null,  // Za specifičnu notifikaciju
     18
     19        // v4.0.5 KRITIČNO FIX: Flag da sprečimo AutoSave pri promeni profila
     20        // Bez ovoga, AutoSave može biti triggeran sa starim podacima pre nego što se novi profil učita
     21        isProfileSwitching: false,
     22
     23        /**
     24         * v4.0.4 KRITIČNO: Deep copy profila za sprečavanje dijeljenja referenci između profila
     25         * Bez ovoga, izmjena u jedan profil može utjecati na drugi profil
     26         */
     27        deepCopyProfile: function(profile) {
     28            if (!profile || typeof profile !== 'object') {
     29                return profile;
     30            }
     31            return JSON.parse(JSON.stringify(profile));
     32        },
    1733
    1834        init: function() {
     
    2541            this.loadProfiles();
    2642            this.setDefaultActiveProfile();
    27         },
    28        
     43            console.log('TAICS Profile Buttons initialized successfully');
     44        },
     45
    2946        bindEvents: function() {
    3047            $('.taics-profile-btn-wide').off('click.taics-profile');
    3148            $('.taics-profile-btn-wide').on('click.taics-profile', this.handleProfileClick.bind(this));
    3249
    33             // AutoSave event listeners na svim poljima
     50            // AUTOSAVE REVOLUCIJA: Save dugme je uklonjeno - AutoSave sistem je aktivan
     51            // Komentarišem event listener jer više nije potreban
     52            // Sve izmene se automatski čuvaju u profil kroz AutoSave sistem
     53            /*
     54            $('#taics-save-profile-btn').off('click.taics-save-profile');
     55            $('#taics-save-profile-btn').on('click.taics-save-profile', this.handleSaveProfileClick.bind(this));
     56            */
     57
     58            // AutoSave Revolution v3.4.0 - Event listeners na svim poljima
    3459            $('#taics-ai-provider').on('change.autosave', () => this.autoSaveField('ai_settings.ai_provider'));
    3560            $('#taics-ai-model').on('change.autosave', () => this.autoSaveField('ai_settings.ai_model'));
     
    5075            $(document).on('taics_headings_changed.autosave', () => this.autoSaveField('content_rules.headings'));
    5176
    52             // Content Rules fields - Structure Name with auto-sync to autosave
     77            // v3.4.0: Content Rules fields - Structure Name with 3s debounce
     78            let structureNameTimeout;
    5379            $('#taics-structure-name').on('input.autosave', () => {
    54                 // v4.0.3 FIX: Use consistent 500ms debounce with main autosave system
    55                 // This ensures structure_name is saved immediately when user stops typing
    56                 clearTimeout(this.structureNameTimeout);
    57                 this.structureNameTimeout = setTimeout(() => {
     80                clearTimeout(structureNameTimeout);
     81                structureNameTimeout = setTimeout(() => {
    5882                    this.autoSaveField('content_rules.structure_name');
    59                 }, 500);
     83                }, 3000);
    6084            });
    6185            $(document).on('taics_guidelines_changed.autosave', () => this.autoSaveField('content_rules.guidelines'));
     
    6387            $(document).on('taics_canvas_changed.autosave', () => this.autoSaveField('layout_template.advanced_template_canvas'));
    6488        },
    65        
     89
    6690        setDefaultActiveProfile: function() {
    6791            const activeBtn = $('.taics-profile-btn-wide.active');
     
    7296            this.activeProfile = profileNum;
    7397            this.updateProfileStatus();
    74         },
    75        
     98            // NOTE: We don't update button label here because profiles aren't loaded yet
     99            // The label will be updated after profiles load in loadProfiles() AJAX callback
     100        },
     101
    76102        loadSavedSettings: function() {
    77103            // Delegirano na TAICS_AI_Provider_Select
     
    101127            }
    102128        },
    103        
     129
    104130        getNonce: function() {
    105131            return (window.taicsData && window.taicsData.nonce) ? window.taicsData.nonce : '';
    106132        },
    107        
     133
    108134        getAjaxUrl: function() {
    109135            return (window.taicsData && window.taicsData.ajax_url) ? window.taicsData.ajax_url : ajaxurl || '/wp-admin/admin-ajax.php';
    110136        },
    111        
     137
    112138        loadProfiles: function() {
    113139            const nonce = this.getNonce();
     
    121147                success: (response) => {
    122148                    if (response.success) {
    123                         this.profiles = response.data || {};
     149                        // v4.0.4 KRITIČNO FIX: Napravi deep copy svakog profila iz odgovora servera
     150                        const rawProfiles = response.data || {};
     151                        this.profiles = {};
     152                        for (const profileNum in rawProfiles) {
     153                            if (rawProfiles.hasOwnProperty(profileNum)) {
     154                                this.profiles[profileNum] = this.deepCopyProfile(rawProfiles[profileNum]);
     155                            }
     156                        }
    124157                        this.updateProfileButtonsStatus();
    125158
    126                         // CRITICAL FIX: Only load profile data on FIRST page load (during init)
    127                         // Don't reload on subsequent calls (e.g., when returning to Generate tab)
    128                         // This prevents resetting user's in-session provider/model changes
    129159                        if (this.isFirstProfileLoad) {
    130160                            this.loadCompleteProfileData(this.activeProfile);
    131                             this.isFirstProfileLoad = false; // Mark that initial load is done
    132                            
    133                             // FIX: Trigger profile_loaded event for first profile load
    134                             // This ensures video-context-mode.js and video-slot-transformation.js initialize properly
     161                            this.isFirstProfileLoad = false;
     162
    135163                            setTimeout(() => {
    136                                 const profileData = this.profiles[this.activeProfile] || {};
    137                                 $(document).trigger('taics_profile_loaded', [this.activeProfile, profileData]);
     164                                $(document).trigger('taics_profile_loaded', [this.activeProfile]);
    138165                            }, 100);
    139166                        }
    140167
    141                         // Show notification about profiles loaded
    142168                        this.showNotification(
    143169                            `Profiles loaded - ${Object.keys(this.profiles).length} saved profiles found`,
    144170                            'info'
    145171                        );
     172                       
     173                        $(document).trigger('taics_all_profiles_loaded', [this.profiles]);
    146174                    } else {
    147175                        console.error('Failed to load profiles:', response.data);
     
    155183            });
    156184        },
    157        
     185
    158186        handleProfilesLoaded: function(response) {
    159187            if (response.success) {
    160                 this.profiles = response.data || {};
     188                // v4.0.4 KRITIČNO FIX: Napravi deep copy svakog profila iz odgovora servera
     189                const rawProfiles = response.data || {};
     190                this.profiles = {};
     191                for (const profileNum in rawProfiles) {
     192                    if (rawProfiles.hasOwnProperty(profileNum)) {
     193                        this.profiles[profileNum] = this.deepCopyProfile(rawProfiles[profileNum]);
     194                    }
     195                }
    161196                this.updateProfileButtonsStatus();
    162197                this.loadCompleteProfileData(this.activeProfile);
    163198            }
    164199        },
    165        
     200
    166201        handleLoadError: function(_xhr, _status, _error) {
    167202            console.error('Failed to load profiles:', _error);
    168203        },
    169        
     204
    170205        updateProfileButtonsStatus: function() {
    171206            $('.taics-profile-btn-wide').each((_index, button) => {
    172207                const $button = $(button);
    173208                const profileNumber = $button.data('profile');
    174                 const hasProfileData = this.profiles[profileNumber] && 
     209                const hasProfileData = this.profiles[profileNumber] &&
    175210                    Object.keys(this.profiles[profileNumber]).length > 0;
    176211                $button.toggleClass('taics-profile-has-data', hasProfileData);
    177212            });
    178213        },
    179        
     214
    180215        handleProfileClick: function(e) {
    181216            e.preventDefault();
    182217            const $button = $(e.currentTarget);
    183218            const profileNumber = parseInt($button.data('profile'));
     219           
     220            // KRITIČNO: Spreči brzu promenu profila ako je prethodna promena još uvek u toku
     221            if (this.isProfileSwitching) {
     222                console.log('TAICS: Profile switch ignored - switching already in progress');
     223                return;
     224            }
     225           
    184226            if (profileNumber === this.activeProfile) {
    185227                return;
     
    189231
    190232        switchProfile: function(profileNumber) {
    191             // 🔥 v4.0.4 FIX: Set flag to prevent autosave while loading profile data
     233            if (this.autoSaveTimeout) {
     234                clearTimeout(this.autoSaveTimeout);
     235                this.autoSaveTimeout = null;
     236            }
     237
     238            this.isProfileSwitching = true;
    192239            this.isLoadingProfileData = true;
    193 
     240           
    194241            $('.taics-profile-btn-wide').removeClass('active');
    195242            $(`.taics-profile-btn-wide[data-profile="${profileNumber}"]`).addClass('active');
    196243            this.activeProfile = profileNumber;
    197244
    198             const profileData = this.profiles[profileNumber];
     245            const profileData = this.deepCopyProfile(this.profiles[profileNumber]);
    199246
    200247            if (profileData && Object.keys(profileData).length > 0) {
    201248                this.loadCompleteProfileDataFromObject(profileData);
    202249
    203                 // Show detailed profile loaded notification
    204                 this.showProfileLoadedNotification(profileNumber, profileData);
     250                setTimeout(() => {
     251                    this.showProfileLoadedNotification(profileNumber, profileData);
     252                    this.updateProfileStatus();
     253                    $(document).trigger('taics_profile_changed', [profileNumber]);
     254
     255                    this.isProfileSwitching = false;
     256                    this.isLoadingProfileData = false;
     257                }, 500);
    205258            } else {
    206259                this.loadCompleteProfileData(profileNumber);
    207260
    208                 // Show empty profile notification
    209261                this.showNotification(
    210262                    `Profile ${profileNumber} loaded (empty profile)`,
    211263                    'info'
    212264                );
    213             }
    214 
    215             this.updateProfileStatus();
    216             $(document).trigger('taics_profile_changed', [profileNumber]);
    217 
    218             // 🔥 FIX v4.0.3: Trigger taics_profile_loaded BEFORE clearing flag
    219             // This ensures profile-name-sync.js receives the flag as true during load
    220             const switchProfileData = profileData || {};
    221             $(document).trigger('taics_profile_loaded', [profileNumber, switchProfileData]);
    222 
    223             // 🔥 v4.0.4 FIX: Clear flag after profile data loading completes
    224             // This allows autosave to work again for user changes
    225             this.isLoadingProfileData = false;
     265
     266                setTimeout(() => {
     267                    this.updateProfileStatus();
     268                    $(document).trigger('taics_profile_changed', [profileNumber]);
     269
     270                    this.isProfileSwitching = false;
     271                    this.isLoadingProfileData = false;
     272                }, 500);
     273            }
    226274        },
    227275
     
    232280            const language = profileData.language || 'en-US';
    233281            const templateId = profileData.layout_template?.template_id || '1';
    234            
     282
    235283            // Show main notification
    236284            if (window.TAICS_Notifications && typeof window.TAICS_Notifications.showProfileLoaded === 'function') {
    237285                window.TAICS_Notifications.showProfileLoaded(profileNumber);
    238286            }
    239            
     287
    240288            // Show detailed settings in a batch notification (slight delay for better UX)
    241289            setTimeout(() => {
     
    246294                    `Template: ${templateId}`
    247295                ];
    248                
     296
    249297                if (window.TAICS_Notifications && typeof window.TAICS_Notifications.showBatchNotification === 'function') {
    250298                    window.TAICS_Notifications.showBatchNotification(details, 'info', 4000);
     
    262310                window.TAICS_AI_Provider_Select.syncWithProfileData(profileData);
    263311            }
    264            
     312
    265313            // FIX: Also sync Default Tone module with profile data
    266314            if (window.TAICS_Default_Tone && typeof window.TAICS_Default_Tone.setValue === 'function') {
     
    268316            }
    269317        },
    270        
     318
    271319        loadCompleteProfileData: function(profileNumber) {
    272             const profileData = this.profiles[profileNumber] || {};
     320            const profileData = this.deepCopyProfile(this.profiles[profileNumber]) || {};
    273321            if (Object.keys(profileData).length === 0) {
    274322                this.resetAllFields();
     
    283331                window.TAICS_AI_Provider_Select.syncWithProfileData(profileData);
    284332            }
    285         },
    286        
     333           
     334            // DVT v4.0.5.2: DIRECT DOM UPDATE - Update Profile 1 button label directly
     335            // This is a fallback that bypasses TAICS_Profile_Name_Sync to ensure it works on first load
     336            if (profileNumber === 1 && profileData.content_rules && profileData.content_rules.structure_name) {
     337                const structureName = profileData.content_rules.structure_name;
     338                const displayLabel = structureName.substring(0, 7).toUpperCase() || 'PROFILE';
     339                const $profileBtn = $('.taics-profile-btn-wide[data-profile="1"]');
     340                const $profileLabel = $profileBtn.find('.taics-profile-text');
     341                if ($profileLabel.length > 0) {
     342                    $profileLabel.text(displayLabel);
     343                    $profileLabel[0].textContent = displayLabel; // Native DOM update
     344                    $profileBtn.attr('title', 'Profile 1 (' + displayLabel + ')');
     345                    $profileBtn[0].title = 'Profile 1 (' + displayLabel + ')'; // Native DOM update
     346                }
     347            }
     348        },
     349
     350        updateProfileButtonLabel: function(profileNumber, structureName) {
     351            if (!window.TAICS_Profile_Name_Sync) {
     352                return;
     353            }
     354            window.TAICS_Profile_Name_Sync.updateButtonLabelForProfile(profileNumber, structureName);
     355        },
     356
    287357        loadGenerateTabData: function(profileData) {
    288358            const aiSettings = profileData.ai_settings || {};
     
    324394            }
    325395        },
    326        
     396
    327397        loadContentRulesData: function(contentRules) {
    328398            // Load Structure Name
    329             const structureName = contentRules.structure_name || '';
    330             $('#taics-structure-name').val(structureName);
    331 
    332             // 🔥 v4.0.4 FIX: Only trigger input if NOT currently loading profile data
    333             // This allows profile-name-sync to detect the new value without triggering autosave
    334             // when the field is being loaded from profile (not user-changed)
    335             if (!this.isLoadingProfileData) {
    336                 $('#taics-structure-name').trigger('input.autosave');
    337             }
     399            $('#taics-structure-name').val(contentRules.structure_name || '');
    338400
    339401            if (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.setValue === 'function') {
     
    425487            }
    426488        },
    427        
     489
    428490        resetAllFields: function() {
    429491            $('#taics-topic').val('');
     
    459521            if (window.TAICS_AI_Provider_Select && typeof window.TAICS_AI_Provider_Select.updateProviderAndModel === 'function') {
    460522                // Note: Profile data should be loaded already, this just resets UI to defaults
    461                 const profileData = this.profiles[this.activeProfile];
     523                // v4.0.4 FIX: Koristi deep copy za sigurnost
     524                const profileData = this.deepCopyProfile(this.profiles[this.activeProfile]);
    462525                if (profileData && profileData.ai_settings) {
    463526                    window.TAICS_AI_Provider_Select.updateProviderAndModel(
     
    549612                              window.TAICS_Default_Tone.getValue() : 'article-specific',
    550613                content_rules: {
     614                    // v4.0.4 KRITIČNO: Dodaj structure_name u prikupljanje podataka
    551615                    structure_name: $('#taics-structure-name').val() || '',
    552616                    headings: (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.getValue === 'function') ?
     
    579643                            this.showNotification('Profile saved successfully', 'success');
    580644                        }
    581                        
    582                         this.profiles[profileNumber] = profileData;
     645
     646                        // v4.0.4 KRITIČNO FIX: Koristi deep copy za cache update
     647                        this.profiles[profileNumber] = this.deepCopyProfile(profileData);
    583648                        this.updateProfileButtonsStatus();
    584649                        this.updateProfileStatus();
    585650                        $(document).trigger('taics_profile_saved', [profileNumber, profileData]);
    586                        
     651
    587652                        // Show additional details about what was saved
    588653                        setTimeout(() => {
     
    593658                                `Mode: ${profileData.generation_mode}`
    594659                            ];
    595                            
     660
    596661                            if (window.TAICS_Notifications && typeof window.TAICS_Notifications.showBatchNotification === 'function') {
    597662                                window.TAICS_Notifications.showBatchNotification(savedDetails, 'info', 3000);
     
    633698            return sources;
    634699        },
    635        
     700
    636701        collectLayoutTemplateData: function() {
    637702            // Get template ID from TAICS_Template_Selector module
     
    686751            const templateId = $('input[name="taics-template"]:checked').val() || '1';
    687752            const photos = [];
    688            
     753
    689754            $('.taics-photo-upload-slot.has-photo').each(function() {
    690755                const $slot = $(this);
     
    705770            };
    706771        },
    707        
     772
    708773        collectExtrasData: function() {
    709774            return {
     
    761826                              window.TAICS_Default_Tone.getValue() : 'article-specific',
    762827                content_rules: {
     828                    // v4.0.4 KRITIČNO: Dodaj structure_name u prikupljanje podataka
    763829                    structure_name: $('#taics-structure-name').val() || '',
    764830                    headings: (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.getValue === 'function') ?
     
    780846            }
    781847        },
    782        
     848
    783849        saveCurrentSettings: function() {
    784850            if (window.TAICS_AI_Provider_Select && typeof window.TAICS_AI_Provider_Select.saveCurrentSettings === 'function') {
     
    802868
    803869        autoSaveField: function(fieldPath) {
     870            // DVT v4.0.5.1: EXTRA SAFETY - Double check profile switching flag
     871            // Even if isProfileSwitching is somehow not set, this provides additional protection
     872            if (this.isProfileSwitching) {
     873                console.log('TAICS: AutoSave BLOCKED - profile switching in progress (' + fieldPath + ')');
     874                return;
     875            }
     876           
     877            // v4.0.5 KRITIČNO FIX: Preskoči AutoSave ako se trenutno menja profil
     878            // Bez ovoga, AutoSave će biti triggeran sa starim podacima pre nego što se novi profil učita
     879            if (this.isProfileSwitching) {
     880                console.log('TAICS: AutoSave skipped - profile switching in progress');
     881                return;
     882            }
     883
    804884            // Sačuvaj koje polje je izmenjeno (za specifičnu notifikaciju)
    805885            this.lastChangedField = fieldPath;
     
    862942                        this.showNotification(message, 'success');
    863943
    864                         // Ažuriraj lokalni cache
    865                         this.profiles[this.activeProfile] = profileData;
     944                        // v4.0.4 KRITIČNO FIX: Ažuriraj lokalni cache sa deep copy profila
     945                        // Bez ovoga, lokalni cache može biti kontaminiran jer dijeli iste reference
     946                        this.profiles[this.activeProfile] = this.deepCopyProfile(profileData);
    866947                        this.updateProfileButtonsStatus();
    867948                    } else {
     
    9351016        }, 200);
    9361017    });
    937    
     1018
    9381019    window.TAICS_Profile_Buttons = TAICS_Profile_Buttons;
    9391020
  • technodrome-ai-content-assistant/trunk/features/footer/publish-toggle.js

    r3401081 r3446048  
    66       
    77        init: function() {
    8             console.log('Initializing publish toggle module');
    98            this.loadInitialState();
    109            this.bindEvents();
     
    3534            $(document).trigger('taics_publish_toggle_changed', [this.isPublishEnabled]);
    3635           
    37             console.log('Auto-publish toggled:', this.isPublishEnabled ? 'ON' : 'OFF');
    3836        },
    3937       
     
    8583                success: (response) => {
    8684                    if (response.success) {
    87                         console.log('Auto-publish preference saved successfully');
    8885                    } else {
    89                         console.warn('Failed to save auto-publish preference:', response.data);
    9086                    }
    9187                },
    9288                error: (xhr, status, error) => {
    93                     console.warn('AJAX error saving auto-publish preference:', error);
    9489                }
    9590            });
  • technodrome-ai-content-assistant/trunk/features/footer/save-button.js

    r3401081 r3446048  
    1414        init: function() {
    1515            this.bindEvents();
    16             console.log('TAICS Save Button initialized - no edit mode');
    1716        },
    1817       
     
    2625
    2726            if (this.isProcessing) {
    28                 console.log('TAICS: Save processing in progress, ignoring click');
    2927                return;
    3028            }
    3129           
    3230            this.isProcessing = true;
    33             console.log('TAICS: Save clicked');
    3431
    3532            // CRITICAL FIX: Save video data explicitly if Video Manager exists
    3633            if (window.taicsVideoManager && typeof window.taicsVideoManager.saveVideoData === 'function') {
    37                 console.log('TAICS: Triggering explicit video data save');
    3834                window.taicsVideoManager.saveVideoData();
    3935            }
     
    4137            this.saveProfile()
    4238                .then((response) => {
    43                     console.log('TAICS: Save promise resolved:', response);
    4439                    if (response && response.success) {
    4540                        this.showNotification('Profile saved successfully', 'success');
     
    6560                const profileData = this.collectProfileData();
    6661                const activeProfile = this.getActiveProfile();
    67                 console.log('TAICS Save: Preparing to send profile data:', profileData, 'for profile:', activeProfile);
    6862               
    6963                if (!window.taicsData || !window.taicsData.ajax_url || !window.taicsData.nonce) {
     
    8579                    },
    8680                    success: (response) => {
    87                         console.log('TAICS Save: AJAX response:', response);
    8881                        if (response.success) {
    89                             console.log('TAICS: Profile saved, refreshing profiles cache');
    9082                            if (window.TAICS_Profile_Buttons) {
    9183                                window.TAICS_Profile_Buttons.loadProfiles();
     
    197189            if (parseInt(templateId) === 6 && window.TAICS_Advanced_Template && typeof window.TAICS_Advanced_Template.getValue === 'function') {
    198190                advancedTemplateData = window.TAICS_Advanced_Template.getValue();
    199                 console.log('Advanced Template canvas data:', advancedTemplateData);
    200191            }
    201192
    202193            // IMPORTANT: Photos are NOT saved in profile - they are global and persist in user_meta
    203194            // Photos and their links remain visible across all profiles until manually removed
    204 
    205             console.log('Layout template data collected (save-button):', {
    206                 template_id: parseInt(templateId),
    207                 advanced_template_canvas: advancedTemplateData
    208             });
    209195
    210196            return {
     
    242228
    243229        showNotification: function(message, type) {
    244             console.log('TAICS: Attempting to show notification:', message, type);
    245230           
    246231            if (window.TAICS_Notifications && typeof window.TAICS_Notifications.showNotification === 'function') {
    247                 console.log('TAICS: Using TAICS_Notifications');
    248232                window.TAICS_Notifications.showNotification(message, type);
    249233            } else if (window.TAICS_Dashboard && typeof window.TAICS_Dashboard.showNotification === 'function') {
    250                 console.log('TAICS: Using TAICS_Dashboard notifications');
    251234                window.TAICS_Dashboard.showNotification(message, type);
    252235            } else {
    253                 console.log('TAICS: No notification system found, using console');
    254                 console.log(`${type.toUpperCase()}: ${message}`);
    255236               
    256237                // Fallback: show alert for critical messages
  • technodrome-ai-content-assistant/trunk/features/generate-tab/add-content-title.js

    r3361244 r3446048  
    1616            this.updateCharCount();
    1717            this.updateMaxLengthAttribute();
    18             console.log('TAICS Content Title v2.0.0 initialized (max chars: ' + this.maxChars + ')');
    1918        },
    2019
     
    105104                window.TAICS_Dashboard.showNotification(message, type, 2000);
    106105            } else {
    107                 console.log(`${type.toUpperCase()}: ${message}`);
    108106            }
    109107        },
     
    139137        cleanup: function() {
    140138            $('#taics-topic').off('input paste keydown');
    141             console.log('TAICS Content Title cleaned up');
    142139        }
    143140    };
  • technodrome-ai-content-assistant/trunk/features/generate-tab/ai-image-toggle.js

    r3421276 r3446048  
    114114                this.isImageEnabled = false;
    115115                this.updateToggleUI();
    116                 console.log('TAICS AI Image: Loaded from profile (default OFF)');
    117116                return;
    118117            }
     
    122121            this.updateToggleUI();
    123122
    124             console.log('TAICS AI Image: Loaded from profile:', aiImageEnabled);
    125123        },
    126124
     
    163161            this.isImageEnabled = false;
    164162            this.updateToggleUI();
    165             console.log('TAICS AI Image: Reset on profile load (legacy)');
    166163        },
    167164
  • technodrome-ai-content-assistant/trunk/features/generate-tab/ai-provider-select.js

    r3434643 r3446048  
    2222            }
    2323
    24             console.log('TAICS AI Provider Select: INITIALIZING v3.5.1');
    2524            this.isInitializing = true;
    2625
     
    3130            // Check if already initialized - don't reset provider on tab switch
    3231            if (this.currentProvider && this.currentProvider !== 'google' && $('#taics-ai-provider').length) {
    33                 console.log('TAICS AI Provider Select: Already initialized with provider:', this.currentProvider);
    3432                // v3.5.1: Update model options with newly loaded models
    3533                this.updateModelOptions();
     
    178176        // Removed loadSavedSettings() - no longer needed as settings come from profile
    179177        loadSavedSettings: function() {
    180             console.log('TAICS AI Provider Select: loadSavedSettings is deprecated. Using profile data.');
    181178            // This function is no longer active. All settings should come from profile data.
    182179        },
     
    271268            this.updateProviderInfo();
    272269           
    273             console.log('Demo mode activated - API fields hidden');
    274270        },
    275271       
     
    283279            $('.taics-demo-info').hide();
    284280           
    285             console.log('API mode activated - API fields shown');
    286281        },
    287282       
     
    412407        validateApiKey: function() {
    413408            if (this.currentProvider === 'demo') {
    414                 console.log('TAICS: Demo mode, API key not required for validation.');
    415409                return true;
    416410            }
     
    418412            const apiKey = this.getApiKey();
    419413            if (!apiKey) {
    420                 console.log('TAICS: No API key provided for validation.');
    421414                return false;
    422415            }
    423416
    424417            const isValid = this.isValidApiKeyFormat(apiKey);
    425             console.log('TAICS: API key validation result:', isValid ? 'Valid' : 'Invalid format');
    426418            return isValid;
    427419        },
     
    464456                        const cacheMsg = response.data.cached ? ' (cached)' : ' (fresh)';
    465457                        self.showNotification('Updated model list from ' + provider + cacheMsg, 'success');
    466                         console.log('TAICS: Using API models for ' + provider + ', count: ' + response.data.models.length);
    467458                    } else {
    468459                        // Keep hardcoded models only on actual API error/failure
    469                         console.log('TAICS: API returned no models for ' + provider + ', using built-in models');
    470460                        self.showNotification('Using built-in model list for ' + provider, 'info');
    471461                    }
     
    473463                error: function() {
    474464                    // Fallback to hardcoded models on AJAX error only
    475                     console.log('TAICS: API error for ' + provider + ', using built-in models');
    476465                    self.showNotification('Using built-in model list for ' + provider, 'info');
    477466                }
     
    606595            });
    607596
    608             console.log('TAICS AI Provider Select: Internal settings updated.', {provider: this.currentProvider, model: currentModelFromDOM});
    609597        },
    610598        // --- END MODIFICATION ---
     
    614602                window.TAICS_Dashboard.showNotification(message, type);
    615603            } else {
    616                 console.log(`${type.toUpperCase()}: ${message}`);
    617604            }
    618605        },
     
    709696        syncWithProfileData: function(profileData) {
    710697            if (!profileData) {
     698                console.log('TAICS: syncWithProfileData - no profile data provided');
    711699                return;
    712700            }
     
    721709            const model = aiSettings.ai_model || '';
    722710            const apiKey = aiSettings.api_key || '';
    723 
     711           
     712            // DVT v4.0.5.2: Log API key loading for debugging
     713            console.log('TAICS: syncWithProfileData - API Key from profile: ' + (apiKey ? apiKey.substring(0, 10) + '...' : 'EMPTY'));
     714           
    724715            this.updateProviderAndModel(provider, model, apiKey);
    725716
     
    812803                }
    813804
    814                 console.log('TAICS: AI Image enabled for', this.currentProvider, ':', selectedModel);
    815805            } else {
    816806                // Disable toggle
     
    835825                }
    836826
    837                 console.log('TAICS: AI Image disabled for', this.currentProvider, ':', selectedModel);
    838827            }
    839828        },
  • technodrome-ai-content-assistant/trunk/features/generate-tab/content-type.js

    r3361244 r3446048  
    1212       
    1313        init: function() {
    14             console.log('TAICS Content Type initialized');
    1514            this.bindEvents();
    1615            this.updateDisplay();
     
    2423        handleContentTypeChange: function(e) {
    2524            const selectedType = $(e.target).val();
    26             console.log('TAICS: Content type changed to:', selectedType);
    2725           
    2826            // Update UI based on content type
     
    7270        cleanup: function() {
    7371            $('#taics-content-type').off('.taics-content-type');
    74             console.log('TAICS Content Type cleaned up');
    7572        }
    7673    };
  • technodrome-ai-content-assistant/trunk/features/generate-tab/default-tone.js

    r3444453 r3446048  
    2121        },
    2222
    23         // State management
     23        // State management - simplified, always unlocked for AutoSave
    2424        state: {
    2525            initialized: false,
    26             currentValue: 'article-specific',
    27             isLocked: true
     26            currentValue: 'article-specific'
    2827        },
    2928
     
    3534                return;
    3635            }
    37 
    38             // Bind events
    3936            this.bindEvents();
    40 
    41             // Set initial field state based on save/edit button
    42             this.updateFieldState();
    43 
    4437            this.state.initialized = true;
    4538        },
     
    5750            });
    5851
    59             // Listen for profile switches
    60             $(document).on('taics_profile_switched.default-tone', function(e, profileId) {
    61                 self.handleProfileSwitch(profileId);
    62             });
    63 
    6452            // Listen for profile loaded events
    65             // v4.0.3 FIX: Event now passes (profileNumber, profileData) as parameters
    6653            $(document).on('taics_profile_loaded.default-tone', function(e, profileNumber, profileData) {
    6754                self.handleProfileLoaded(profileData);
    68             });
    69 
    70             // Listen for field lock/unlock events
    71             $(document).on('taics_fields_locked.default-tone', function() {
    72                 self.lockField();
    73             });
    74 
    75             $(document).on('taics_fields_unlocked.default-tone', function() {
    76                 self.unlockField();
    7755            });
    7856        },
     
    8361         */
    8462        handleToneChange: function(selectedValue) {
    85             if (this.state.isLocked) {
    86                 return;
    87             }
    88 
    8963            this.state.currentValue = selectedValue;
    90 
    9164            // Event is already triggered by the dropdown change - no need to trigger again!
    9265            // profile-buttons.js will catch the change.autosave event automatically
    93         },
    94 
    95         /**
    96          * Handle profile switch
    97          */
    98         handleProfileSwitch: function() {
    99             // Profile data will be loaded via profile_loaded event
    10066        },
    10167
     
    12490
    12591        /**
    126          * Get current field value
    127          * Used by AutoSave to collect profile data
     92         * Get current field value - FIX: Added for AutoSave compatibility
    12893         */
    12994        getValue: function() {
    130             const $field = $(this.config.fieldId);
    131             return $field.length ? $field.val() : this.config.defaultValue;
    132         },
    133 
    134         /**
    135          * Update field state based on save/edit button
    136          */
    137         updateFieldState: function() {
    138             if (window.TAICS_Save_Edit_Button && typeof window.TAICS_Save_Edit_Button.isInEditMode === 'function') {
    139                 const isEditMode = window.TAICS_Save_Edit_Button.isInEditMode();
    140                 if (isEditMode) {
    141                     this.unlockField();
    142                 } else {
    143                     this.lockField();
    144                 }
    145             } else {
    146                 // Default to locked if save/edit button not available
    147                 this.lockField();
    148             }
    149         },
    150 
    151         /**
    152          * Lock the field
    153          */
    154         lockField: function() {
    155             const $field = $(this.config.fieldId);
    156             $field.prop('disabled', true).addClass('taics-field-locked');
    157             this.state.isLocked = true;
    158         },
    159 
    160         /**
    161          * Unlock the field
    162          */
    163         unlockField: function() {
    164             const $field = $(this.config.fieldId);
    165             $field.prop('disabled', false).removeClass('taics-field-locked');
    166             this.state.isLocked = false;
     95            return this.state.currentValue || this.config.defaultValue;
    16796        },
    16897
     
    182111    // Initialize when document is ready
    183112    $(document).ready(function() {
    184         // Small delay to ensure other modules are loaded
    185         setTimeout(function() {
    186             if (!TAICS_Default_Tone.state.initialized) {
    187                 TAICS_Default_Tone.init();
    188             }
    189         }, 150);
     113        TAICS_Default_Tone.init();
    190114    });
    191115
  • technodrome-ai-content-assistant/trunk/features/generate-tab/generation-mode.js

    r3421276 r3446048  
    77            this.bindEvents();
    88            // Profile data will be loaded by profile system, no localStorage
    9             console.log('TAICS Generation Mode initialized (v3.4.0 - AutoSave)');
    109        },
    1110
     
    1918
    2019            // Listen for profile loaded events
    21             $(document).on('taics_profile_loaded.generation-mode', function(e, data) {
    22                 if (data && data.generation_mode) {
    23                     $('#taics-generation-mode').val(data.generation_mode);
    24                 }
     20            $(document).on('taics_profile_loaded.generation-mode', function(e, profileNumber) {
     21                // v4.0.4 KRITIČNO FIX: Trigger mode change sa razlicitim delay vrijednostima
     22                // Prvo triggeruj odmah, zatim ponovi nakon 150ms za sigurnost
     23                const currentMode = $('#taics-generation-mode').val();
     24
     25                // Immediate trigger
     26                $(document).trigger('taics_generation_mode_changed', [currentMode]);
     27
     28                // Secondary trigger after delay to ensure video-context-mode.js processes it
     29                setTimeout(function() {
     30                    $(document).trigger('taics_generation_mode_changed', [currentMode]);
     31                }, 150);
    2532            });
    2633        },
     
    3138            // Trigger AutoSave event
    3239            $(document).trigger('taics_field_changed.autosave', ['generation_mode', mode]);
     40
     41            // Trigger video context mode change to update title field lock/unlock
     42            $(document).trigger('taics_generation_mode_changed', [mode]);
    3343
    3444            // Check plan restrictions
  • technodrome-ai-content-assistant/trunk/features/generate-tab/language-select.js

    r3361244 r3446048  
    88
    99            this.bindEvents();
    10             console.log('TAICS Language Select module initialized');
    1110        },
    1211
     
    2120            // Trigger custom event for other modules
    2221            $(document).trigger('taics_language_changed', [selectedLanguage]);
    23             console.log('Language changed to:', selectedLanguage);
    2422        },
    2523
     
    3432            // Trigger change event to ensure other modules react
    3533            $(document).trigger('taics_language_changed', [languageCode]);
    36             console.log('Language set to:', languageCode);
    3734        },
    3835
     
    4138                this.$languageSelect.off('.taics-language-select');
    4239            }
    43             console.log('TAICS Language Select module cleaned up');
    4440        }
    4541    };
  • technodrome-ai-content-assistant/trunk/features/generate-tab/video-context-mode.js

    r3434643 r3446048  
    1818    // Wait for DOM to be ready
    1919    $(document).ready(function() {
    20         console.log('[VIDEO CONTEXT] Initializing video context mode handler...');
    2120       
    2221        // Generation mode dropdown
     
    5756         */
    5857        function activateVideoContextMode(mode) {
    59             console.log('[VIDEO CONTEXT] Activating video context mode:', mode);
    60            
     58
    6159            // Lock the input
    6260            $topicInput.prop('disabled', true);
    63            
     61
    6462            // Style the input to indicate it's locked - BIGGER FONT FOR VISIBILITY
    6563            $topicInput.css({
     
    103101         */
    104102        function deactivateVideoContextMode() {
    105             console.log('[VIDEO CONTEXT] Deactivating video context mode');
    106            
     103
    107104            // Unlock the input
    108105            $topicInput.prop('disabled', false);
    109            
    110             // Restore normal styling
    111             $topicInput.css({
    112                 'background-color': '',
    113                 'color': '',
    114                 'opacity': '',
    115                 'font-weight': '',
    116                 'font-size': ''
    117             });
    118            
     106
     107            // Restore normal styling - important to clear ALL inline styles
     108            $topicInput.removeAttr('style');
     109
    119110            // Remove dynamic placeholder styles
    120111            var topicId = $topicInput.attr('id');
    121112            var placeholderStyleId = 'taics-video-context-style-' + topicId;
    122             $('#' + placeholderStyleId).remove();
    123            
     113            var styleElement = $('#' + placeholderStyleId);
     114            if (styleElement.length) {
     115                styleElement.remove();
     116            }
     117
    124118            // Restore default placeholder
    125119            $topicInput.attr('placeholder', defaultPlaceholder);
    126            
     120
    127121            // v4.0.1: Show video URL input for other modes (container may not exist)
    128122            if ($videoUrlContainer.length) {
    129123                $videoUrlContainer.show();
    130124            }
    131            
     125
    132126            // Trigger event to reset video slots
    133127            $(document).trigger('taics:videoContextModeChanged', [null]);
    134128            $(document).trigger('taics_videoContextModeChanged', [null]);
    135129        }
    136        
     130
    137131        /**
    138132         * Handle generation mode change
     
    140134        function handleGenerationModeChange() {
    141135            var selectedMode = $generationMode.val();
    142             console.log('[VIDEO CONTEXT] Generation mode changed to:', selectedMode);
    143            
     136
    144137            if (isVideoContextMode(selectedMode)) {
    145138                activateVideoContextMode(selectedMode);
     
    154147        function initializeVideoContextMode() {
    155148            var currentMode = $generationMode.val();
    156             console.log('[VIDEO CONTEXT] Initializing with mode:', currentMode);
    157            
     149
    158150            if (isVideoContextMode(currentMode)) {
    159151                activateVideoContextMode(currentMode);
     152            } else {
     153                deactivateVideoContextMode();
    160154            }
    161155        }
     
    163157        // Bind change event to generation mode dropdown
    164158        $generationMode.on('change', handleGenerationModeChange);
     159
     160        // v4.0.4 FIX: Also listen for programmatic mode changes via custom event
     161        // This ensures title field unlock/lock works when mode is changed programmatically
     162        $(document).on('taics_generation_mode_changed', function(e, mode) {
     163            // v4.0.4 KRITIČNO: Proveri mode ODMAH, zatim sa delay za sigurnost
     164            var currentMode = $generationMode.val();
     165
     166            // Immediate check (mode je možda već ažuriran)
     167            if (isVideoContextMode(currentMode)) {
     168                activateVideoContextMode(currentMode);
     169            } else {
     170                deactivateVideoContextMode();
     171            }
     172
     173            // Secondary check after small delay to ensure value is fully updated
     174            setTimeout(function() {
     175                var updatedMode = $generationMode.val();
     176                if (isVideoContextMode(updatedMode)) {
     177                    activateVideoContextMode(updatedMode);
     178                } else {
     179                    deactivateVideoContextMode();
     180                }
     181            }, 50);
     182        });
    165183       
    166184        // Listen for profile loaded event to re-initialize video context mode
    167185        $(document).on('taics_profile_loaded taics_profile_changed', function(e, profileNumber) {
    168             console.log('[VIDEO CONTEXT] Profile loaded/changed:', profileNumber);
    169            
    170             // Small delay to allow generation mode to be set from profile data
    171             setTimeout(function() {
    172                 initializeVideoContextMode();
    173             }, 100);
     186
     187            // v4.0.4 FIX: Trebam izvršiti sa razlicitim delay vrijednostima za sigurnost
     188            // Prvo nakon 50ms
     189            setTimeout(function() {
     190                initializeVideoContextMode();
     191            }, 50);
     192
     193            // Ponovi nakon 150ms (kada se generation-mode.js triggeruje event)
     194            setTimeout(function() {
     195                initializeVideoContextMode();
     196            }, 150);
     197
     198            // Finalno nakon 250ms za sigurnost
     199            setTimeout(function() {
     200                initializeVideoContextMode();
     201            }, 250);
    174202        });
    175203       
     
    212240        };
    213241       
    214         console.log('[VIDEO CONTEXT] Video context mode handler initialized');
    215242    });
    216243
  • technodrome-ai-content-assistant/trunk/features/header/add-licence.js

    r3432273 r3446048  
    1212        init: function() {
    1313            this.bindEvents();
    14             console.log('TAICS License Handler initialized');
    1514        },
    1615
     
    130129        resetToFree: function() {
    131130            // v3.5.4: Auto-reset to FREE when license key is empty or invalid
    132             console.log('Resetting license to FREE tier...');
    133131
    134132            const $licenseInput = $('#taics-license-key');
  • technodrome-ai-content-assistant/trunk/features/layout-templates-tab/advanced-template.js

    r3401188 r3446048  
    312312
    313313            $(document).on('taics_template_changed.advanced-builder', function(_, templateId) {
    314                 console.log('🔄 Template changed to:', templateId);
    315314
    316315                // Always show builder buttons (MAJOR FIX: Always visible in Layout Tab)
     
    599598
    600599            this.showNotification('Element removed', 'info');
    601             console.log('Element removed:', elementType);
    602600        },
    603601
     
    631629                this.canvasData = [];
    632630                this.showNotification('Canvas cleared', 'success');
    633                 console.log('Canvas cleared');
    634631            }
    635632        },
     
    842839            });
    843840
    844             console.log('Preview shown');
    845841        },
    846842
     
    849845                window.TAICS_Dashboard.showNotification(message, type);
    850846            } else {
    851                 console.log('[' + type.toUpperCase() + '] ' + message);
    852847            }
    853848        },
  • technodrome-ai-content-assistant/trunk/features/layout-templates-tab/photo-positions.js

    r3434643 r3446048  
    102102                    $(document).trigger('taics_photo_link_changed.autosave', [position, this.getValue()]);
    103103                } else {
    104                     console.warn('Invalid URL format:', finalUrl);
    105104                }
    106105            }
     
    194193                window.TAICS_Dashboard.showNotification(message, type);
    195194            } else {
    196                 console.warn(`[${type.toUpperCase()}] ${message}`);
    197195            }
    198196        },
     
    227225            // If no selected photos and no profile photos loaded yet, try to load from user_meta
    228226            if (Object.keys(this.selectedPhotos).length === 0) {
    229                 console.log('TAICS Photo Positions: No photos selected, loading from user_meta...');
    230227                this.loadPhotosFromUserMeta();
    231228            }
  • technodrome-ai-content-assistant/trunk/features/layout-templates-tab/template-selector.js

    r3401081 r3446048  
    1818            this.bindEvents();
    1919            this.loadInitialState();
    20             console.log('TAICS Template Selector module initialized');
    2120        },
    2221
     
    4443            $selectedCard.addClass('selected');
    4544
    46             console.log(`Template changed to: ${templateId}`);
    4745            $(document).trigger('taics_template_changed', [templateId]);
    4846
     
    121119                this.$container.off('.taics-template-selector');
    122120            }
    123             console.log('TAICS Template Selector module cleaned up');
    124121        }
    125122    };
  • technodrome-ai-content-assistant/trunk/features/layout-templates-tab/video-manager.js

    r3421276 r3446048  
    2424         */
    2525        init: function() {
    26             console.log('[VIDEO MANAGER] Initializing simplified version...');
    2726            this.bindEvents();
    2827            this.loadVideoData();
    29             console.log('[VIDEO MANAGER] Initialized.');
    3028        },
    3129
     
    4139                const slot = $input.data('slot');
    4240                const url = $input.val();
    43                 console.log(`[VIDEO MANAGER] URL input changed for slot ${slot}:`, url);
    4441                self.videoData[`video-url-${slot}`] = url;
    4542            });
     
    4946                const slot = $input.data('slot');
    5047                const title = $input.val();
    51                 console.log(`[VIDEO MANAGER] Title input changed for slot ${slot}:`, title);
    5248                self.videoData[`video-title-${slot}`] = title;
    5349            });
     
    5753                const $input = $(e.target);
    5854                const slot = $input.data('slot');
    59                 console.log(`[VIDEO MANAGER] Blur detected on slot ${slot}. Triggering autosave.`);
    6055                // AUTOSAVE REVOLUCIJA: Triggeruj autosave event umesto direktnog čuvanja
    6156                $(document).trigger('taics_video_changed.autosave', [slot, self.getValue()]);
     
    6661                const $btn = $(e.target);
    6762                const slot = $btn.data('slot');
    68                 console.log(`[VIDEO MANAGER] Remove clicked for slot ${slot}.`);
    6963                self.removeVideo(slot);
    7064            });
    7165
    72             console.log('[VIDEO MANAGER] Events bound.');
    7366        },
    7467
     
    7871         */
    7972        loadVideoData: function() {
    80             console.log('[VIDEO MANAGER] v3.4.0: Videos are loaded from profile via AutoSave system');
    8173            // Initialize with empty data - profile will be loaded separately
    8274            this.videoData = {
     
    9486         */
    9587        saveVideoData: function() {
    96             console.log('[VIDEO MANAGER] v3.4.0: Videos saved through AutoSave system');
    9788            // Saving is now handled by AutoSave, this method is kept for compatibility
    9889        },
     
    10394        updateUI: function() {
    10495            const self = this;
    105             console.log('[VIDEO MANAGER] Updating UI with data:', self.videoData);
    10696
    10797            for (let i = 1; i <= 2; i++) {
     
    183173         */
    184174        removeVideo: function(slot) {
    185             console.log(`[VIDEO MANAGER] Removing video from slot ${slot}.`);
    186175            this.videoData[`video-url-${slot}`] = '';
    187176            this.videoData[`video-title-${slot}`] = '';
     
    280269
    281270})(jQuery);
    282             console.log('[VIDEO MANAGER] CRITICAL: Adding high-priority card click handler.');
  • technodrome-ai-content-assistant/trunk/features/layout-templates-tab/video-slot-transformation.js

    r3434643 r3446048  
    2121
    2222    $(document).ready(function() {
    23         console.log('[VIDEO TRANSFORM] Initializing video slot transformation...');
    2423
    2524        var $generationMode = $('#taics-generation-mode');
     
    4645         */
    4746        function transformForVideoUrlContext() {
    48             console.log('[VIDEO TRANSFORM] Applying Video URL Context transformation');
    4947
    5048            // Slot 1 - ACTIVE with new name
     
    8785            );
    8886
    89             console.log('[VIDEO TRANSFORM] Video URL Context transformation complete');
    9087        }
    9188
     
    9491         */
    9592        function transformForVideoChannelContext() {
    96             console.log('[VIDEO TRANSFORM] Applying Video Channel Context transformation');
    9793
    9894            // Slot 1 - LOCKED with info
     
    132128            }
    133129
    134             console.log('[VIDEO TRANSFORM] Video Channel Context transformation complete');
    135130        }
    136131
     
    139134         */
    140135        function resetSlotsToNormal() {
    141             console.log('[VIDEO TRANSFORM] Resetting slots to normal mode');
    142136
    143137            // Remove any UNDER CONSTRUCTION overlays
     
    163157            $slot2.find('.taics-locked-info').remove();
    164158
    165             console.log('[VIDEO TRANSFORM] Slots reset to normal mode');
    166159        }
    167160
     
    171164        function applyTransformation() {
    172165            var currentMode = $generationMode.val();
    173             console.log('[VIDEO TRANSFORM] Current generation mode:', currentMode);
    174166
    175167            if (currentMode === VIDEO_URL_CONTEXT_MODE) {
     
    191183         */
    192184        function initializeTransformation() {
    193             console.log('[VIDEO TRANSFORM] Initializing transformation...');
    194185            applyTransformation();
    195186        }
     
    202193        // Listen for profile loaded/changed events
    203194        $(document).on('taics_profile_loaded taics_profile_changed', function(e, profileNumber) {
    204             console.log('[VIDEO TRANSFORM] Profile loaded/changed:', profileNumber);
    205195            // Small delay to ensure generation mode is set from profile
    206196            setTimeout(function() {
     
    211201        // Listen for video context mode changed events from video-context-mode.js
    212202        $(document).on('taics:videoContextModeChanged taics_videoContextModeChanged', function(e, mode) {
    213             console.log('[VIDEO TRANSFORM] Video context mode changed event:', mode);
    214203            if (mode) {
    215204                // Mode was set, apply transformation
     
    243232        // Handle window load event
    244233        $(window).on('load', function() {
    245             console.log('[VIDEO TRANSFORM] Window loaded, re-applying transformation');
    246234            applyTransformation();
    247235        });
     
    252240        };
    253241
    254         console.log('[VIDEO TRANSFORM] Video slot transformation initialized successfully');
    255242    });
    256243
  • technodrome-ai-content-assistant/trunk/features/notifications.js

    r3379631 r3446048  
    1717            }, 300);
    1818           
    19             console.log('TAICS_Notifications initialized');
    2019        },
    2120
     
    244243            }
    245244            this.isInitialized = false;
    246             console.log('TAICS_Notifications cleaned up');
    247245        },
    248246
  • technodrome-ai-content-assistant/trunk/includes/class-ajax-handler.php

    r3444453 r3446048  
    403403                    $input_data = $decoded;
    404404                } else {
    405                     if (defined('WP_DEBUG') && WP_DEBUG) {
    406                         // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    407                         error_log('TAICS AutoSave - JSON decode failed: ' . json_last_error_msg());
    408                     }
    409405                    wp_send_json_error(array(
    410406                        'message' => 'Invalid profile data format'
     
    413409                }
    414410            } else {
    415                 if (defined('WP_DEBUG') && WP_DEBUG) {
    416                     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    417                     error_log('TAICS AutoSave - profile_data missing from POST');
    418                 }
    419411                wp_send_json_error(array('message' => 'Profile data missing'));
    420412                return;
     
    423415            // Nonce verification - iz $_POST jer je FormData
    424416            if (empty($_POST['nonce'])) {
    425                 if (defined('WP_DEBUG') && WP_DEBUG) {
    426                     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    427                     error_log('TAICS AutoSave - Nonce missing from POST');
    428                 }
    429417                wp_send_json_error(array('message' => 'Nonce missing'));
    430418                return;
     
    432420
    433421            $nonce_result = wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'taics_ajax_nonce');
    434             if (defined('WP_DEBUG') && WP_DEBUG) {
    435                 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    436                 error_log('TAICS AutoSave - Nonce verification result: ' . $nonce_result);
    437             }
    438422
    439423            if (!$nonce_result) {
    440                 if (defined('WP_DEBUG') && WP_DEBUG) {
    441                     // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
    442                     error_log('TAICS AutoSave - Nonce verification FAILED');
    443                 }
    444424                wp_send_json_error(array('message' => 'Security verification failed'));
    445425                return;
     
    800780            $profile_manager = new TAICS_Profile_Manager();
    801781            $profiles = $profile_manager->get_all_profiles();
    802            
     782
    803783            wp_send_json_success($profiles);
    804            
     784
    805785        } catch (Exception $e) {
    806786            wp_send_json_error(esc_html__('Failed to load profiles', 'technodrome-ai-content-assistant'));
  • technodrome-ai-content-assistant/trunk/includes/class-profile-manager.php

    r3444453 r3446048  
    251251            return [];
    252252        }
    253        
     253
    254254        if (!$user_id) {
    255255            $user_id = get_current_user_id();
     
    258258            return [];
    259259        }
    260        
     260
    261261        $meta_key = self::PROFILE_META_PREFIX . $profile_number;
    262262        $profile_data = get_user_meta($user_id, $meta_key, true);
    263263        if (!$profile_data) {
    264             return self::$default_profile; // FIXED: Return default profile if not found
     264            // v4.0.4 KRITIČNO FIX: Vrati KOPIJU default profila, ne referencu!
     265            // Bez ovoga, svi profili dijele istu referencu na self::$default_profile
     266            // što uzrokuje da promjena u jedan profil utiče na sve ostale
     267            return json_decode(json_encode(self::$default_profile), true);
    265268        }
    266269
     
    268271            $decoded = json_decode($profile_data, true);
    269272            if (json_last_error() !== JSON_ERROR_NONE) {
    270                 return self::$default_profile; // FIXED: Return default profile on JSON decode error
     273                // v4.0.4 KRITIČNO FIX: Vrati KOPIJU default profila, ne referencu!
     274                return json_decode(json_encode(self::$default_profile), true);
    271275            }
    272276            return $decoded;
     
    274278            return $profile_data;
    275279        } else {
    276             return self::$default_profile; // FIXED: Return default profile for unexpected data type
     280            // v4.0.4 KRITIČNO FIX: Vrati KOPIJU default profila, ne referencu!
     281            return json_decode(json_encode(self::$default_profile), true);
    277282        }
    278283    }
  • technodrome-ai-content-assistant/trunk/readme.txt

    r3444453 r3446048  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 4.0.3
     7Stable tag: 4.0.4
    88License: GPL v2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4646*   **IMPROVED**: Better control flow for profile data synchronization
    4747
    48 = 4.0.4 (2026-01-21) =
    49 *   **FIX**: Structure Name field now clears properly when switching profiles
    50 *   **FIX**: Profile button labels update correctly with saved custom names
    51 *   **IMPROVED**: Better event listener timing for profile data synchronization
     48= 4.0.4 (2026-01-22) =
     49*   **NEW**: Video slot renamed to "GENERATE AI CONTENT FROM VIDEO URL" in AI + Video URL mode
     50*   **NEW**: Video slot renamed to "GENERATE AI CONTENT FROM VIDEO CHANNEL" in AI + Video Channel mode
     51*   **NEW**: UNDER CONSTRUCTION overlay on Slot 2 when in Video URL mode (channel not yet implemented)
     52*   **NEW**: UNDER CONSTRUCTION overlay on Slot 2 when in Video Channel mode
     53*   **IMPROVED**: Video slot transformation only applies in video context modes
    5254
    5355= 4.0.3 (2026-01-21) =
     
    8991== Upgrade Notice ==
    9092
    91 = 4.0.3 =
    92 Important bug fix - Default Tone field now saves correctly with AutoSave. Recommended for all users.
     93= 4.0.4 =
     94Video slot renaming and UNDER CONSTRUCTION overlay for video context modes.
    9395
    9496= 4.0.2 =
  • technodrome-ai-content-assistant/trunk/technodrome-ai-content-assistant.php

    r3444453 r3446048  
    44 * Plugin URI: https://technodrome.org/ai-content-assistant
    55 * Description: Advanced AI content generation plugin with multiple AI providers, profile system, layout templates, and content rules for WordPress.
    6  * Version: 4.0.3
     6 * Version: 4.0.4
    77 * Author: Technodrome Team
    88 * Author URI: https://technodrome.org
     
    3030
    3131// Plugin constants
    32 define('TAICS_VERSION', '4.0.3');
     32define('TAICS_VERSION', '4.0.4');
    3333define('TAICS_PLUGIN_FILE', __FILE__);
    3434define('TAICS_PLUGIN_DIR', plugin_dir_path(__FILE__));
Note: See TracChangeset for help on using the changeset viewer.