/** * İ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
Image
Image
Image
Image
Image
Image

MARCOMEN 18215 Gerçek Deri Erkek Casual Ayakkabı

5.719,00 ₺4.003,30 ₺(KDV Dahil)%30
2. ÜRÜNDE %40 İNDİRİM
0 Değerlendirme
RENK: BEYAZ
BEDEN:
*Kalın tabanı ve üzerindeki farklı renklerin uyumu ile dikkat çeken bu sneaker sezona damga vurmaya geliyor! Günlük ve spor kombinlerinize katacağı şıklık ve rahat tabanı ile sunduğu konforla favorileriniz arasında yerini alacak.
Ürün Özellikleri
Yaş Grubu
Cinsiyet
Bunları da beğenebilirsiniz!
Image
%50
Image
%50
Image
%50
Image
%30
Image
%50
Image
%50
Image
%30

Değerlendirmeler

0 Değerlendirme