/** * İncelebi Widget JavaScript * Generated for: Unknown Store * Platform: ikas * Features: singleProduct, bulkCart * Widget ID: A137FAE62056C858 * Generated: 2025-07-26 04:15:36 */ (function() { 'use strict'; // === DOM UTILITIES === /** * İncelebi Widget - DOM Utilities * Centralized DOM manipulation utilities */ class DOMUtils { /** * Smart element selection with multiple selector support */ static selectElement(selectors) { if (typeof selectors === 'string') { return document.querySelector(selectors); } if (Array.isArray(selectors)) { for (const selector of selectors) { const element = document.querySelector(selector); if (element) return element; } } return null; } /** * Select all elements matching selectors */ static selectElements(selectors) { if (typeof selectors === 'string') { return document.querySelectorAll(selectors); } if (Array.isArray(selectors)) { const elements = []; for (const selector of selectors) { const found = document.querySelectorAll(selector); elements.push(...found); } return elements; } return []; } /** * Universal value setting for different element types */ static setElementValue(element, value) { if (!element) return false; try { if (element.tagName === 'SELECT') { return this.setSelectValue(element, value); } else if (element.tagName === 'INPUT') { return this.setInputValue(element, value); } else { element.textContent = value; return true; } } catch (error) { console.warn('Failed to set element value:', error); return false; } } /** * Set select element value with fallback strategies */ static setSelectValue(selectElement, value) { const strategies = [ // Exact match () => { const option = selectElement.querySelector(`option[value="${value}"]`); if (option) { selectElement.value = value; return true; } return false; }, // URL decoded value () => { const decodedValue = decodeURIComponent(value); const option = selectElement.querySelector(`option[value="${decodedValue}"]`); if (option) { selectElement.value = decodedValue; return true; } return false; }, // Text content match () => { const options = selectElement.querySelectorAll('option'); for (const opt of options) { if (opt.textContent.trim().toUpperCase() === value.toUpperCase()) { selectElement.value = opt.value; return true; } } return false; }, // Partial text match () => { const options = selectElement.querySelectorAll('option'); for (const opt of options) { if (opt.textContent.trim().toUpperCase().includes(value.toUpperCase())) { selectElement.value = opt.value; return true; } } return false; } ]; for (const strategy of strategies) { if (strategy()) { this.triggerEvent(selectElement, 'change'); return true; } } return false; } /** * Set input element value based on type */ static setInputValue(inputElement, value) { if (inputElement.type === 'radio' || inputElement.type === 'checkbox') { inputElement.checked = (value === inputElement.value || value === true); } else { inputElement.value = value; } this.triggerEvent(inputElement, 'change'); return true; } /** * Centralized event triggering */ static triggerEvent(element, eventType, options = {}) { if (!element) return false; const eventOptions = { bubbles: true, cancelable: true, ...options }; try { const event = new Event(eventType, eventOptions); element.dispatchEvent(event); return true; } catch (error) { console.warn(`Failed to trigger ${eventType} event:`, error); return false; } } /** * Wait for element to appear */ static waitForElement(selectors, timeout = 5000) { return new Promise((resolve, reject) => { const element = this.selectElement(selectors); if (element) { resolve(element); return; } const observer = new MutationObserver(() => { const element = this.selectElement(selectors); if (element) { observer.disconnect(); resolve(element); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(() => { observer.disconnect(); reject(new Error(`Element not found: ${selectors}`)); }, timeout); }); } /** * Check if element is visible */ static isVisible(element) { if (!element) return false; const style = getComputedStyle(element); return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0'; } /** * Create element with attributes */ static createElement(tag, attributes = {}, textContent = '') { const element = document.createElement(tag); Object.keys(attributes).forEach(key => { if (key === 'style' && typeof attributes[key] === 'object') { Object.assign(element.style, attributes[key]); } else { element.setAttribute(key, attributes[key]); } }); if (textContent) { element.textContent = textContent; } return element; } } // === BASE PLATFORM ADAPTER === /** * İncelebi Widget - Base Platform Adapter * Abstract base class for platform-specific implementations */ class BasePlatformAdapter { constructor() { this.platformName = 'generic'; this.config = null; this.timing = { waitBeforeClick: 500, waitAfterClick: 1000, variantSelectionDelay: 200 }; } /** * Initialize adapter with widget config */ init(config) { this.config = config; console.log(`${this.platformName} adapter initialized`); } /** * Get platform-specific selectors */ getSelectors() { return { addToCart: this.config?.selectors?.addToCartButton || 'button', quantity: this.config?.selectors?.quantityInput || 'input[name="quantity"]' }; } /** * Handle variant selection - to be overridden by platform adapters */ handleVariants(urlParams) { console.log(`${this.platformName}: Processing variants`); const variants = this.parseVariantParams(urlParams); if (variants.length === 0) { console.log(`${this.platformName}: No variants found`); return Promise.resolve(true); } return this.processVariants(variants); } /** * Parse variant parameters from URL */ parseVariantParams(urlParams) { const variants = []; for (const [key, value] of urlParams) { if (key.startsWith('variant_')) { const variantName = key.replace('variant_', ''); variants.push({ name: variantName, value: value }); } } return variants; } /** * Process variants - can be overridden for platform-specific logic */ async processVariants(variants) { let successCount = 0; for (let i = 0; i < variants.length; i++) { const variant = variants[i]; if (await this.processVariant(variant)) { successCount++; } // Delay between variants if (i < variants.length - 1) { await this.delay(this.timing.variantSelectionDelay); } } return successCount > 0; } /** * Process single variant - to be overridden */ async processVariant(variant) { console.log(`${this.platformName}: Processing variant ${variant.name} = ${variant.value}`); // Generic implementation const selectors = this.getVariantSelectors(variant); for (const selector of selectors) { const element = DOMUtils.selectElement(selector); if (element && DOMUtils.setElementValue(element, variant.value)) { console.log(`${this.platformName}: Variant set via ${selector}`); return true; } } console.warn(`${this.platformName}: Could not set variant ${variant.name}`); return false; } /** * Get variant selectors for a specific variant */ getVariantSelectors(variant) { return [ `select[name="${variant.name}"]`, `select[name="variant_${variant.name}"]`, `input[name="${variant.name}"][value="${variant.value}"]`, `input[name="variant_${variant.name}"][value="${variant.value}"]` ]; } /** * Detect errors on page - to be overridden */ detectErrors() { const errorSelectors = [ '.error', '.alert-error', '.message-error', '.form-error', '.alert-danger' ]; for (const selector of errorSelectors) { const errorElement = DOMUtils.selectElement(selector); if (errorElement && DOMUtils.isVisible(errorElement) && errorElement.textContent.trim()) { console.warn(`${this.platformName}: Error detected - ${errorElement.textContent.trim()}`); return true; } } return false; } /** * Wait for platform to be ready */ waitForReady() { return new Promise((resolve) => { const checkReady = () => { const selectors = this.getSelectors(); const addToCartBtn = DOMUtils.selectElement(selectors.addToCart); if (addToCartBtn && document.readyState === 'complete') { setTimeout(() => resolve(true), 300); // DOM settle time } else { setTimeout(checkReady, 500); } }; checkReady(); }); } /** * Click add to cart button */ async clickAddToCart() { const selectors = this.getSelectors(); const addToCartBtn = DOMUtils.selectElement(selectors.addToCart); if (!addToCartBtn) { console.warn(`${this.platformName}: Add to cart button not found`); return false; } // Wait before clicking await this.delay(this.timing.waitBeforeClick); addToCartBtn.click(); console.log(`${this.platformName}: Add to cart clicked`); // Wait after clicking await this.delay(this.timing.waitAfterClick); return true; } /** * Set quantity */ setQuantity(quantity) { const selectors = this.getSelectors(); const quantityInput = DOMUtils.selectElement(selectors.quantity); if (!quantityInput) { console.warn(`${this.platformName}: Quantity input not found`); return false; } return DOMUtils.setElementValue(quantityInput, quantity); } /** * Utility delay function */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // === IKAS PLATFORM ADAPTER === /** * İncelebi Widget - ikas Platform Adapter * Specialized implementation for ikas e-commerce platform */ class IkasAdapter extends BasePlatformAdapter { constructor() { super(); this.platformName = 'ikas'; // ikas-specific timing (faster platform) this.timing = { waitBeforeClick: 500, waitAfterClick: 800, variantSelectionDelay: 200 }; } /** * Get ikas-specific selectors */ getSelectors() { return { addToCart: '[data-add-to-cart], .add-to-cart, #add-to-cart-button, .sepete-ekle', quantity: 'input[name="quantity"], .quantity-input, #quantity, [data-quantity]' }; } /** * Get variant selectors for ikas platform */ getVariantSelectors(variant) { const variantName = variant.name.toLowerCase(); // ikas-specific variant selectors if (variantName === 'renk' || variantName === 'color') { return [ 'select[name*="Renk"]', 'select[name*="renk"]', 'select[name*="color"]', '[data-variant="color"]', '[data-option="renk"]' ]; } if (variantName === 'beden' || variantName === 'size') { return [ 'select[name*="Beden"]', 'select[name*="beden"]', 'select[name*="size"]', '[data-variant="size"]', '[data-option="beden"]' ]; } // Generic ikas selectors return [ `select[name*="${variant.name}"]`, `[data-variant="${variant.name}"]`, `[data-option="${variant.name}"]`, `.variant-${variant.name}`, `#${variant.name}-select`, ...super.getVariantSelectors(variant) ]; } /** * ikas-specific variant processing */ async processVariant(variant) { console.log(`ikas: Processing variant ${variant.name} = ${variant.value}`); const selectors = this.getVariantSelectors(variant); // Strategy 1: Try select elements with ikas value matching for (const selector of selectors) { const element = DOMUtils.selectElement(selector); if (element && element.tagName === 'SELECT') { if (await this.setIkasSelectValue(element, variant.value)) { console.log(`ikas: Variant set via select ${selector}`); return true; } } } // Strategy 2: Try button/clickable elements for (const selector of selectors) { const element = DOMUtils.selectElement(selector); if (element && (element.tagName === 'BUTTON' || element.classList.contains('variant-button'))) { element.click(); console.log(`ikas: Variant button clicked - ${variant.value}`); await this.delay(this.timing.variantSelectionDelay); return true; } } // Strategy 3: Fallback to generic processing return super.processVariant(variant); } /** * ikas-specific select value setting with advanced strategies */ async setIkasSelectValue(selectElement, value) { const strategies = [ // Exact match () => { const option = selectElement.querySelector(`option[value="${value}"]`); if (option) { selectElement.value = value; return true; } return false; }, // URL decode match (ikas common: SÜET-BEJ → SÜET-BEJ) () => { const decodedValue = decodeURIComponent(value); const option = selectElement.querySelector(`option[value="${decodedValue}"]`); if (option) { selectElement.value = decodedValue; return true; } return false; }, // Text content match (case insensitive) () => { const options = selectElement.querySelectorAll('option'); for (const opt of options) { if (opt.textContent.trim().toUpperCase() === value.toUpperCase()) { selectElement.value = opt.value; return true; } } return false; }, // Partial match (for complex ikas values) () => { const options = selectElement.querySelectorAll('option'); const searchValue = value.toUpperCase(); for (const opt of options) { const optText = opt.textContent.trim().toUpperCase(); if (optText.includes(searchValue) || searchValue.includes(optText)) { selectElement.value = opt.value; return true; } } return false; }, // ikas-specific: dash-separated matching (SÜET-BEJ matches BEJ) () => { if (value.includes('-')) { const parts = value.split('-'); const options = selectElement.querySelectorAll('option'); for (const part of parts) { for (const opt of options) { if (opt.textContent.trim().toUpperCase().includes(part.toUpperCase())) { selectElement.value = opt.value; return true; } } } } return false; } ]; for (const strategy of strategies) { if (strategy()) { // Trigger change event DOMUtils.triggerEvent(selectElement, 'change'); // ikas-specific: trigger custom events if available if (window.IkasEvents) { window.IkasEvents.trigger('variant:changed', { element: selectElement, value: selectElement.value }); } console.log(`ikas: Select value set to ${selectElement.value}`); await this.delay(100); // Let ikas process the change return true; } } return false; } /** * ikas-specific error detection */ detectErrors() { const ikasErrorSelectors = [ '.error-message', '.alert-danger', '.notification-error', '[data-error]', '.form-error', '.validation-message', // ikas-specific error selectors '.modal[data-error]', '[data-modal-error]' ]; for (const selector of ikasErrorSelectors) { const errorElement = DOMUtils.selectElement(selector); if (errorElement && DOMUtils.isVisible(errorElement) && errorElement.textContent.trim()) { console.warn(`ikas: Error detected - ${errorElement.textContent.trim()}`); return true; } } // Check for modal errors const modal = DOMUtils.selectElement('.modal[data-error], [data-modal-error]'); if (modal && DOMUtils.isVisible(modal)) { console.warn('ikas: Modal error detected'); return true; } return false; } /** * Wait for ikas platform to be ready */ waitForReady() { return new Promise((resolve) => { const checkReady = () => { // Check for ikas-specific elements const productDetail = DOMUtils.selectElement('.product-detail, [data-product]'); const addToCartBtn = DOMUtils.selectElement(this.getSelectors().addToCart); if (productDetail && addToCartBtn) { // Wait for IkasEvents if available if (window.IkasEvents || document.readyState === 'complete') { setTimeout(() => resolve(true), 300); } else { setTimeout(checkReady, 200); } } else { setTimeout(checkReady, 500); } }; checkReady(); }); } /** * ikas-specific additional checks before processing */ async preProcessCheck() { // Wait for ikas to be ready await this.waitForReady(); // Check for any loading indicators const loadingIndicators = DOMUtils.selectElements('.loading, .spinner, [data-loading]'); if (loadingIndicators.length > 0) { console.log('ikas: Waiting for loading indicators to disappear'); await this.waitForLoadingComplete(); } return true; } /** * Wait for loading indicators to disappear */ waitForLoadingComplete(timeout = 5000) { return new Promise((resolve) => { const startTime = Date.now(); const checkLoading = () => { const loadingElements = DOMUtils.selectElements('.loading, .spinner, [data-loading]'); const visibleLoading = Array.from(loadingElements).some(el => DOMUtils.isVisible(el)); if (!visibleLoading || (Date.now() - startTime) > timeout) { resolve(true); } else { setTimeout(checkLoading, 200); } }; checkLoading(); }); } } // === WIDGET CORE === /** * İncelebi Widget - Core Module * Modular widget architecture core */ class IncelebiWidgetCore { constructor(config) { this.config = config; this.plugins = new Map(); this.platform = null; this.eventBus = new EventBus(); // Initialize platform adapter this.platform = PlatformAdapterFactory.create(config.platform); console.log(`İncelebi Widget Core initialized for ${config.platformDisplay}`); } /** * Register a plugin */ use(plugin) { if (typeof plugin.install === 'function') { plugin.install(this); console.log(`Plugin registered: ${plugin.name || 'Unknown'}`); } return this; } /** * Initialize widget */ init(options = {}) { console.log("İncelebi Widget initializing..."); // Domain validation if (!this.checkDomain()) { console.warn("İncelebi Widget: Bu domain için yetkilendirilmemiş"); return false; } // Platform-specific initialization if (this.platform && typeof this.platform.init === 'function') { this.platform.init(this.config); } // Check for İncelebi parameters const paramType = this.checkIncelebiParams(); if (paramType === 'single') { this.handleSingleProduct(); } else if (paramType === 'bulk') { this.handleBulkCart(); } this.eventBus.emit('widget:initialized', { config: this.config }); return true; } /** * Domain validation */ checkDomain() { if (!this.config.allowedDomain) return true; const currentDomain = window.location.hostname.toLowerCase(); return currentDomain === this.config.allowedDomain || currentDomain.endsWith('.' + this.config.allowedDomain); } /** * Check for İncelebi URL parameters */ checkIncelebiParams() { const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('incelebi_cart') === '1') { return 'single'; } if (urlParams.get('incelebi_bulk_cart') === '1') { return 'bulk'; } return false; } /** * Handle single product addition */ handleSingleProduct() { const singleProductPlugin = this.plugins.get('singleProduct'); if (singleProductPlugin) { singleProductPlugin.process(); } else { console.warn('Single product plugin not registered'); } } /** * Handle bulk cart processing */ handleBulkCart() { const bulkCartPlugin = this.plugins.get('bulkCart'); if (bulkCartPlugin) { bulkCartPlugin.process(); } else { console.warn('Bulk cart plugin not registered'); } } } /** * Simple Event Bus for inter-module communication */ class EventBus { constructor() { this.events = {}; } on(event, callback) { if (!this.events[event]) { this.events[event] = []; } this.events[event].push(callback); } emit(event, data) { if (this.events[event]) { this.events[event].forEach(callback => callback(data)); } } } /** * Platform Adapter Factory */ class PlatformAdapterFactory { static create(platform) { const adapters = { 'woocommerce': WooCommerceAdapter, 'opencart': OpenCartAdapter, 'prestashop': PrestaShopAdapter, 'ikas': IkasAdapter, 'generic': GenericAdapter }; const AdapterClass = adapters[platform] || GenericAdapter; return new AdapterClass(); } } // === SINGLEPRODUCT PLUGIN === /** * İncelebi Widget - Single Product Plugin * Handles individual product addition to cart */ const SingleProductPlugin = { name: 'SingleProduct', install(widget) { const processor = new SingleProductProcessor(widget); widget.plugins.set('singleProduct', processor); // Listen to widget events widget.eventBus.on('widget:initialized', () => { console.log('Single Product Plugin: Ready'); }); } }; class SingleProductProcessor { constructor(widget) { this.widget = widget; this.config = widget.config; this.platform = widget.platform; this.eventBus = widget.eventBus; } /** * Process single product addition */ async process() { console.log('Single Product: Processing started'); try { // Pre-process checks if (this.platform && typeof this.platform.preProcessCheck === 'function') { await this.platform.preProcessCheck(); } // Parse URL parameters const urlParams = new URLSearchParams(window.location.search); const productId = urlParams.get('product_id'); const quantity = urlParams.get('quantity') || '1'; console.log(`Single Product: Processing product ${productId}, quantity ${quantity}`); // Emit processing started event this.eventBus.emit('singleProduct:started', { productId, quantity }); // Step 1: Set quantity await this.setQuantity(quantity); // Step 2: Handle variants await this.handleVariants(urlParams); // Step 3: Add to cart await this.addToCart(productId); // Success this.eventBus.emit('singleProduct:completed', { productId, quantity }); console.log('Single Product: Processing completed successfully'); } catch (error) { console.error('Single Product: Processing failed', error); this.eventBus.emit('singleProduct:failed', { error: error.message }); } } /** * Set product quantity */ async setQuantity(quantity) { console.log(`Single Product: Setting quantity to ${quantity}`); if (this.platform && typeof this.platform.setQuantity === 'function') { const success = this.platform.setQuantity(quantity); if (success) { console.log('Single Product: Quantity set successfully'); this.eventBus.emit('singleProduct:quantitySet', { quantity }); return; } } // Fallback to generic quantity setting const selectors = this.config.selectors || {}; const quantitySelector = selectors.quantityInput || 'input[name="quantity"]'; const quantityInput = DOMUtils.selectElement(quantitySelector); if (quantityInput) { if (DOMUtils.setElementValue(quantityInput, quantity)) { console.log('Single Product: Quantity set via fallback method'); this.eventBus.emit('singleProduct:quantitySet', { quantity }); } else { console.warn('Single Product: Failed to set quantity'); } } else { console.warn(`Single Product: Quantity input not found: ${quantitySelector}`); } } /** * Handle product variants */ async handleVariants(urlParams) { console.log('Single Product: Processing variants'); if (this.platform && typeof this.platform.handleVariants === 'function') { try { const success = await this.platform.handleVariants(urlParams); if (success) { console.log('Single Product: Variants processed successfully'); this.eventBus.emit('singleProduct:variantsSet', { success: true }); } else { console.log('Single Product: No variants processed or failed'); this.eventBus.emit('singleProduct:variantsSet', { success: false }); } } catch (error) { console.error('Single Product: Variant processing error', error); this.eventBus.emit('singleProduct:variantsSet', { success: false, error: error.message }); } } else { // Fallback variant processing await this.handleVariantsFallback(urlParams); } } /** * Fallback variant handling */ async handleVariantsFallback(urlParams) { console.log('Single Product: Using fallback variant processing'); const variants = []; for (const [key, value] of urlParams) { if (key.startsWith('variant_')) { const variantName = key.replace('variant_', ''); variants.push({ name: variantName, value: value }); } } if (variants.length === 0) { console.log('Single Product: No variants found'); return; } let successCount = 0; for (const variant of variants) { const selectors = [ `select[name="${variant.name}"]`, `select[name="variant_${variant.name}"]`, `input[name="${variant.name}"][value="${variant.value}"]`, `input[name="variant_${variant.name}"][value="${variant.value}"]` ]; let variantSet = false; for (const selector of selectors) { const element = DOMUtils.selectElement(selector); if (element && DOMUtils.setElementValue(element, variant.value)) { console.log(`Single Product: Variant ${variant.name} set via ${selector}`); successCount++; variantSet = true; break; } } if (!variantSet) { console.warn(`Single Product: Could not set variant ${variant.name} = ${variant.value}`); } // Small delay between variants await this.delay(200); } this.eventBus.emit('singleProduct:variantsSet', { success: successCount > 0, processedCount: successCount, totalCount: variants.length }); } /** * Add product to cart */ async addToCart(productId) { console.log('Single Product: Adding to cart'); // Check for errors before adding to cart if (this.platform && typeof this.platform.detectErrors === 'function') { if (this.platform.detectErrors()) { throw new Error('Errors detected on page before adding to cart'); } } // Use platform-specific add to cart if available if (this.platform && typeof this.platform.clickAddToCart === 'function') { const success = await this.platform.clickAddToCart(); if (success) { console.log('Single Product: Successfully added to cart'); this.trackUsage(productId); this.eventBus.emit('singleProduct:addedToCart', { productId }); return; } } // Fallback to generic add to cart await this.addToCartFallback(productId); } /** * Fallback add to cart method */ async addToCartFallback(productId) { console.log('Single Product: Using fallback add to cart'); const selectors = this.config.selectors || {}; const addToCartSelector = selectors.addToCartButton || 'button'; const addToCartBtn = DOMUtils.selectElement(addToCartSelector); if (!addToCartBtn) { throw new Error(`Add to cart button not found: ${addToCartSelector}`); } // Wait a bit before clicking await this.delay(500); addToCartBtn.click(); console.log('Single Product: Add to cart button clicked'); // Wait after clicking await this.delay(1000); // Track usage this.trackUsage(productId); this.eventBus.emit('singleProduct:addedToCart', { productId }); } /** * Track usage analytics */ trackUsage(productId) { try { const trackingUrl = `${this.config.apiEndpoint}/track/`; fetch(trackingUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ widgetId: this.config.widgetId, storeId: this.config.storeId, productId: productId, success: true, timestamp: new Date().toISOString(), platform: this.config.platform }) }).then(response => { if (response.ok) { console.log('Single Product: Usage tracked successfully'); this.eventBus.emit('singleProduct:tracked', { productId }); } else { console.warn('Single Product: Usage tracking failed'); } }).catch(error => { console.warn('Single Product: Usage tracking error', error); }); } catch (error) { console.warn('Single Product: Usage tracking setup failed', error); } } /** * Utility delay function */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // === BULKCART PLUGIN === /** * İncelebi Widget - Bulk Cart Plugin * Handles multiple product addition to cart via iframe */ const BulkCartPlugin = { name: 'BulkCart', install(widget) { const processor = new BulkCartProcessor(widget); widget.plugins.set('bulkCart', processor); // Listen to widget events widget.eventBus.on('widget:initialized', () => { console.log('Bulk Cart Plugin: Ready'); }); } }; class BulkCartProcessor { constructor(widget) { this.widget = widget; this.config = widget.config; this.platform = widget.platform; this.eventBus = widget.eventBus; // Bulk cart state this.currentIndex = 0; this.products = []; this.results = []; this.isProcessing = false; this.iframe = null; } /** * Process bulk cart addition */ async process() { if (this.isProcessing) { console.log('Bulk Cart: Already processing, ignoring request'); return; } console.log('Bulk Cart: Processing started'); this.isProcessing = true; try { // Parse products from URL parameters this.products = this.parseProductsFromUrl(); if (this.products.length === 0) { throw new Error('No products found in URL parameters'); } console.log(`Bulk Cart: Found ${this.products.length} products to process`); this.eventBus.emit('bulkCart:started', { productCount: this.products.length, products: this.products }); // Create processing iframe await this.createProcessingIframe(); // Process each product for (let i = 0; i < this.products.length; i++) { this.currentIndex = i; const product = this.products[i]; console.log(`Bulk Cart: Processing product ${i + 1}/${this.products.length} - ${product.id}`); this.eventBus.emit('bulkCart:processingProduct', { index: i, product, total: this.products.length }); try { await this.processProduct(product); this.results.push({ product, success: true, error: null }); this.eventBus.emit('bulkCart:productCompleted', { index: i, product, success: true }); } catch (error) { console.error(`Bulk Cart: Failed to process product ${product.id}:`, error); this.results.push({ product, success: false, error: error.message }); this.eventBus.emit('bulkCart:productCompleted', { index: i, product, success: false, error: error.message }); } // Delay between products if (i < this.products.length - 1) { await this.delay(1000); } } // Cleanup and finalize await this.finalizeProcessing(); console.log('Bulk Cart: Processing completed successfully'); this.eventBus.emit('bulkCart:completed', { products: this.products, results: this.results, successCount: this.results.filter(r => r.success).length }); } catch (error) { console.error('Bulk Cart: Processing failed', error); this.eventBus.emit('bulkCart:failed', { error: error.message }); } finally { this.isProcessing = false; this.cleanupIframe(); } } /** * Parse products from URL parameters */ parseProductsFromUrl() { const urlParams = new URLSearchParams(window.location.search); const products = []; // Parse products in format: products[0][id]=123&products[0][quantity]=2&products[0][variant_size]=L const productMap = new Map(); for (const [key, value] of urlParams) { const match = key.match(/^products\[(\d+)\]\[([^\]]+)\]$/); if (match) { const index = parseInt(match[1]); const field = match[2]; if (!productMap.has(index)) { productMap.set(index, { index }); } const product = productMap.get(index); if (field === 'id') { product.id = value; } else if (field === 'quantity') { product.quantity = parseInt(value) || 1; } else if (field.startsWith('variant_')) { if (!product.variants) product.variants = {}; product.variants[field] = value; } } } // Convert map to array and validate for (const product of productMap.values()) { if (product.id) { if (!product.quantity) product.quantity = 1; products.push(product); } } // Sort by index to maintain order products.sort((a, b) => a.index - b.index); return products; } /** * Create hidden iframe for processing */ async createProcessingIframe() { console.log('Bulk Cart: Creating processing iframe'); // Remove any existing iframe this.cleanupIframe(); // Create iframe element this.iframe = DOMUtils.createElement('iframe', { id: 'incelebi-bulk-iframe', style: { position: 'fixed', top: '-9999px', left: '-9999px', width: '1px', height: '1px', border: 'none', visibility: 'hidden', opacity: '0' } }); document.body.appendChild(this.iframe); // Wait for iframe to be ready await new Promise((resolve) => { this.iframe.onload = resolve; setTimeout(resolve, 1000); // Fallback timeout }); console.log('Bulk Cart: Processing iframe created'); } /** * Process single product in iframe */ async processProduct(product) { console.log(`Bulk Cart: Processing product ${product.id} with quantity ${product.quantity}`); // Build product URL with İncelebi parameters const productUrl = this.buildProductUrl(product); console.log(`Bulk Cart: Loading URL - ${productUrl}`); // Load product page in iframe await this.loadProductInIframe(productUrl); // Wait for page to load and process await this.waitForIframeProcessing(); // Track success this.trackProductUsage(product); console.log(`Bulk Cart: Product ${product.id} processed successfully`); } /** * Build product URL with İncelebi parameters */ buildProductUrl(product) { const baseUrl = this.getCurrentPageUrl(); const url = new URL(baseUrl); // Add İncelebi parameters url.searchParams.set('incelebi_cart', '1'); url.searchParams.set('product_id', product.id); url.searchParams.set('quantity', product.quantity.toString()); // Add variant parameters if (product.variants) { for (const [variantKey, variantValue] of Object.entries(product.variants)) { url.searchParams.set(variantKey, variantValue); } } return url.toString(); } /** * Get current page URL without query parameters */ getCurrentPageUrl() { const url = new URL(window.location.href); url.search = ''; // Remove all query parameters return url.toString(); } /** * Load product page in iframe */ loadProductInIframe(url) { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error('Iframe load timeout')); }, 30000); // 30 second timeout const onLoad = () => { clearTimeout(timeout); this.iframe.removeEventListener('load', onLoad); resolve(); }; this.iframe.addEventListener('load', onLoad); this.iframe.src = url; }); } /** * Wait for iframe processing to complete */ async waitForIframeProcessing() { console.log('Bulk Cart: Waiting for iframe processing'); // Wait for the widget in iframe to process let attempts = 0; const maxAttempts = 50; // 25 seconds max while (attempts < maxAttempts) { try { // Check iframe document for completion indicators const iframeDoc = this.iframe.contentDocument || this.iframe.contentWindow.document; // Look for success indicators if (this.checkIframeSuccess(iframeDoc)) { console.log('Bulk Cart: Iframe processing completed successfully'); return; } // Look for error indicators if (this.checkIframeErrors(iframeDoc)) { throw new Error('Error detected in iframe processing'); } // Check for specific platform success indicators if (this.platform && typeof this.platform.checkIframeSuccess === 'function') { if (this.platform.checkIframeSuccess(iframeDoc)) { console.log('Bulk Cart: Platform-specific success detected'); return; } } } catch (crossOriginError) { // Cross-origin access blocked, use timing-based approach console.log('Bulk Cart: Cross-origin access blocked, using timing approach'); await this.delay(5000); // Wait 5 seconds return; } await this.delay(500); attempts++; } // Timeout reached console.warn('Bulk Cart: Iframe processing timeout'); } /** * Check iframe for success indicators */ checkIframeSuccess(iframeDoc) { const successSelectors = [ '.success-message', '.alert-success', '.cart-success', '.add-to-cart-success', '[data-success="true"]' ]; for (const selector of successSelectors) { const element = iframeDoc.querySelector(selector); if (element && DOMUtils.isVisible(element)) { return true; } } // Check for cart count increase or similar indicators const cartElements = iframeDoc.querySelectorAll('.cart-count, .cart-counter, [data-cart-count]'); for (const element of cartElements) { const count = parseInt(element.textContent) || 0; if (count > 0) { return true; } } return false; } /** * Check iframe for error indicators */ checkIframeErrors(iframeDoc) { const errorSelectors = [ '.error-message', '.alert-error', '.alert-danger', '.form-error', '[data-error]' ]; for (const selector of errorSelectors) { const element = iframeDoc.querySelector(selector); if (element && DOMUtils.isVisible(element) && element.textContent.trim()) { console.error(`Bulk Cart: Error detected - ${element.textContent.trim()}`); return true; } } return false; } /** * Track product usage for analytics */ trackProductUsage(product) { try { const trackingUrl = `${this.config.apiEndpoint}/track/`; fetch(trackingUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ widgetId: this.config.widgetId, storeId: this.config.storeId, productId: product.id, quantity: product.quantity, variants: product.variants || {}, success: true, timestamp: new Date().toISOString(), platform: this.config.platform, processingType: 'bulk' }) }).then(response => { if (response.ok) { console.log(`Bulk Cart: Usage tracked for product ${product.id}`); this.eventBus.emit('bulkCart:productTracked', { product }); } else { console.warn(`Bulk Cart: Usage tracking failed for product ${product.id}`); } }).catch(error => { console.warn(`Bulk Cart: Usage tracking error for product ${product.id}:`, error); }); } catch (error) { console.warn(`Bulk Cart: Usage tracking setup failed for product ${product.id}:`, error); } } /** * Finalize bulk processing */ async finalizeProcessing() { console.log('Bulk Cart: Finalizing processing'); const successCount = this.results.filter(r => r.success).length; const failedCount = this.results.length - successCount; console.log(`Bulk Cart: Processed ${this.results.length} products (${successCount} success, ${failedCount} failed)`); // Platform-specific finalization if (this.platform && typeof this.platform.finalizeBulkProcessing === 'function') { try { await this.platform.finalizeBulkProcessing(this.results); } catch (error) { console.warn('Bulk Cart: Platform finalization failed:', error); } } // Show summary if configured if (this.config.showBulkSummary !== false) { this.showProcessingSummary(); } } /** * Show processing summary to user */ showProcessingSummary() { const successCount = this.results.filter(r => r.success).length; const failedCount = this.results.length - successCount; const summaryMessage = `İncelebi Toplu Sepet: ${successCount} ürün başarıyla eklendi${failedCount > 0 ? `, ${failedCount} ürün eklenemedi` : ''}`; // Create summary notification const notification = DOMUtils.createElement('div', { style: { position: 'fixed', top: '20px', right: '20px', backgroundColor: successCount > 0 ? '#28a745' : '#dc3545', color: 'white', padding: '15px 20px', borderRadius: '5px', boxShadow: '0 4px 6px rgba(0,0,0,0.1)', zIndex: '9999', fontFamily: 'Arial, sans-serif', fontSize: '14px', maxWidth: '300px' } }, summaryMessage); document.body.appendChild(notification); // Auto-remove after 5 seconds setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 5000); console.log('Bulk Cart: Summary notification shown'); } /** * Cleanup iframe */ cleanupIframe() { if (this.iframe && this.iframe.parentNode) { this.iframe.parentNode.removeChild(this.iframe); this.iframe = null; console.log('Bulk Cart: Iframe cleaned up'); } } /** * Utility delay function */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // === WIDGET INITIALIZATION === // Widget configuration const widgetConfig = {"widget_id": "A137FAE62056C858", "store_id": "2", "store_name": "Unknown Store", "api_endpoint": "https://incelebi.com", "platform": "ikas", "platform_display": "ikas", "allowed_domain": "www.dericlub.com.tr", "selectors": {"addToCartButton": "[data-add-to-cart], .add-to-cart, #add-to-cart-button, .sepete-ekle", "quantityInput": "input[name=\"quantity\"], .quantity-input, #quantity, [data-quantity]"}, "showBulkSummary": true, "trackUsage": true}; // Initialize widget const widget = new IncelebiWidgetCore(widgetConfig); // Register plugins widget.use(SingleProductPlugin); widget.use(BulkCartPlugin); // Start widget widget.init(); })(); // End IIFE Select element Send logs Screenshot
Image
Image
Image
Image
Image
Image
Image

DERİCLUB Hakiki Deri 3.5cm Erkek Takım Elbise Dikişli Klasik Kemer 501

999,00 ₺699,30 ₺Including Tax%30
0 Review
RENK: SİYAH
BEDEN:
*Kemer genişliği 3,5 cm''dir.
*Klasik kıyafetler için idealdir.
*1. Hakiki deri olan kemeri uzun yıllar kullanmaktan keyif alacağınız bir aksesuar olacak.
Product Details
Yaş Grubu
Gender

Reviews

0 Review