/** * İncelebi Widget JavaScript * Generated for: Unknown Store * Platform: ikas * Features: singleProduct, bulkCart * Widget ID: C3E52782866F4D15 * Generated: 2025-07-26 05:04:22 */ // Browser compatibility check if (typeof window === 'undefined' || typeof document === 'undefined') { console.warn('İncelebi Widget: Browser environment required'); // Stop execution in non-browser environments } (function() { 'use strict'; // Prevent text display if JavaScript fails try { // === 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..."); // Check if we're in an iframe - if so, don't initialize to prevent duplicate processing if (window !== window.top) { console.log("İncelebi Widget: Iframe içinde, widget kapatılıyor"); return false; } // 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) { // Skip tracking if disabled in config if (!this.config.trackUsage) { console.log('Single Product: Usage tracking disabled'); return; } try { const trackingUrl = `${this.config.apiEndpoint}/api/widget/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 direct page navigation */ 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 with overlay UI */ 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`); // Create overlay UI this.createOverlay(); this.eventBus.emit('bulkCart:started', { productCount: this.products.length, products: this.products }); // Process each product with overlay updates for (let i = 0; i < this.products.length; i++) { this.currentIndex = i; const product = this.products[i]; // Update overlay progress this.updateOverlayProgress(i + 1, this.products.length, `İşleniyor: ${product.id}`); 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.processProductDirectly(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(1500); } } // Finalize with success message 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.showOverlayError(error.message); this.eventBus.emit('bulkCart:failed', { error: error.message }); } finally { this.isProcessing = false; // Close overlay after delay to show final result setTimeout(() => this.closeOverlay(), 3000); } } /** * 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 overlay with progress bar */ createOverlay() { console.log('Bulk Cart: Creating overlay'); // Remove any existing overlay this.closeOverlay(); // Create overlay container this.overlay = DOMUtils.createElement('div', { id: 'incelebi-bulk-overlay', style: { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(0, 0, 0, 0.8)', zIndex: '999999', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'Arial, sans-serif' } }); // Create progress container const progressContainer = DOMUtils.createElement('div', { style: { backgroundColor: 'white', borderRadius: '10px', padding: '30px', minWidth: '400px', textAlign: 'center', boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)' } }); // Title this.overlayTitle = DOMUtils.createElement('h3', { style: { margin: '0 0 20px 0', color: '#333', fontSize: '18px' } }, 'İncelebi Toplu Sepet İşlemi'); // Progress text this.overlayText = DOMUtils.createElement('p', { style: { margin: '0 0 20px 0', color: '#666', fontSize: '14px' } }, 'İşlem başlatılıyor...'); // Progress bar container const progressBarContainer = DOMUtils.createElement('div', { style: { width: '100%', height: '20px', backgroundColor: '#f0f0f0', borderRadius: '10px', overflow: 'hidden', marginBottom: '20px' } }); // Progress bar this.progressBar = DOMUtils.createElement('div', { style: { width: '0%', height: '100%', backgroundColor: '#28a745', borderRadius: '10px', transition: 'width 0.3s ease' } }); // Progress percentage this.progressPercent = DOMUtils.createElement('div', { style: { color: '#333', fontSize: '16px', fontWeight: 'bold', marginBottom: '10px' } }, '0%'); // Assemble overlay progressBarContainer.appendChild(this.progressBar); progressContainer.appendChild(this.overlayTitle); progressContainer.appendChild(this.overlayText); progressContainer.appendChild(progressBarContainer); progressContainer.appendChild(this.progressPercent); this.overlay.appendChild(progressContainer); document.body.appendChild(this.overlay); console.log('Bulk Cart: Overlay created'); } /** * Process single product directly on current page */ async processProductDirectly(product) { console.log(`Bulk Cart: Processing product ${product.id} with quantity ${product.quantity}`); try { // Set quantity if platform supports it if (this.platform && typeof this.platform.setQuantity === 'function') { this.platform.setQuantity(product.quantity); await this.delay(300); } // Handle variants if (product.variants) { await this.handleProductVariants(product.variants); } // Add to cart await this.addProductToCart(product); // Track success this.trackProductUsage(product); console.log(`Bulk Cart: Product ${product.id} processed successfully`); } catch (error) { console.error(`Bulk Cart: Failed to process product ${product.id}:`, error); throw error; } } /** * 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) { // Skip tracking if disabled in config if (!this.config.trackUsage) { console.log('Bulk Cart: Usage tracking disabled'); return; } try { const trackingUrl = `${this.config.apiEndpoint}/api/widget/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)`); // Show success in overlay this.showOverlaySuccess(); // 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 notification 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'); } /** * Update overlay progress */ updateOverlayProgress(current, total, message) { if (!this.overlay) return; const percentage = Math.round((current / total) * 100); // Update progress bar if (this.progressBar) { this.progressBar.style.width = `${percentage}%`; } // Update percentage text if (this.progressPercent) { this.progressPercent.textContent = `${percentage}%`; } // Update message if (this.overlayText) { this.overlayText.textContent = message || `İşlem ${current}/${total}`; } console.log(`Bulk Cart: Progress updated - ${percentage}%`); } /** * Show error in overlay */ showOverlayError(errorMessage) { if (!this.overlay) return; // Update progress bar to red if (this.progressBar) { this.progressBar.style.backgroundColor = '#dc3545'; } // Update title to error if (this.overlayTitle) { this.overlayTitle.textContent = 'İşlem Hatası'; this.overlayTitle.style.color = '#dc3545'; } // Update message if (this.overlayText) { this.overlayText.textContent = errorMessage || 'Bir hata oluştu'; this.overlayText.style.color = '#dc3545'; } console.log('Bulk Cart: Error shown in overlay'); } /** * Show success in overlay */ showOverlaySuccess() { if (!this.overlay) return; const successCount = this.results.filter(r => r.success).length; const failedCount = this.results.length - successCount; // Update title to success if (this.overlayTitle) { this.overlayTitle.textContent = 'İşlem Tamamlandı'; this.overlayTitle.style.color = '#28a745'; } // Update message if (this.overlayText) { this.overlayText.textContent = `${successCount} ürün başarıyla sepete eklendi${failedCount > 0 ? `, ${failedCount} ürün eklenemedi` : ''}`; } // Complete progress bar if (this.progressBar) { this.progressBar.style.width = '100%'; } if (this.progressPercent) { this.progressPercent.textContent = '100%'; } console.log('Bulk Cart: Success shown in overlay'); } /** * Close overlay */ closeOverlay() { if (this.overlay && this.overlay.parentNode) { this.overlay.parentNode.removeChild(this.overlay); this.overlay = null; console.log('Bulk Cart: Overlay closed'); } } /** * Handle product variants directly */ async handleProductVariants(variants) { console.log('Bulk Cart: Processing variants:', variants); for (const [variantKey, variantValue] of Object.entries(variants)) { const variantName = variantKey.replace('variant_', ''); if (this.platform && typeof this.platform.processVariant === 'function') { await this.platform.processVariant({ name: variantName, value: variantValue }); } else { // Fallback variant processing await this.setVariantDirectly(variantName, variantValue); } await this.delay(200); } } /** * Set variant directly using selectors */ async setVariantDirectly(variantName, variantValue) { const selectors = [ `select[name="${variantName}"]`, `select[name="variant_${variantName}"]`, `input[name="${variantName}"][value="${variantValue}"]`, `input[name="variant_${variantName}"][value="${variantValue}"]` ]; for (const selector of selectors) { const element = DOMUtils.selectElement(selector); if (element && DOMUtils.setElementValue(element, variantValue)) { console.log(`Bulk Cart: Variant ${variantName} set to ${variantValue}`); return true; } } console.warn(`Bulk Cart: Could not set variant ${variantName} = ${variantValue}`); return false; } /** * Add product to cart directly */ async addProductToCart(product) { console.log(`Bulk Cart: Adding product ${product.id} to cart`); if (this.platform && typeof this.platform.clickAddToCart === 'function') { const success = await this.platform.clickAddToCart(); if (!success) { throw new Error(`Failed to add product ${product.id} to cart via platform adapter`); } } else { // Fallback to generic 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 for product ${product.id}`); } addToCartBtn.click(); await this.delay(1000); // Wait for cart update } console.log(`Bulk Cart: Product ${product.id} added to cart`); } /** * Utility delay function */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // === WIDGET INITIALIZATION === // Widget configuration const widgetConfig = {"widget_id": "C3E52782866F4D15", "store_id": "2", "store_name": "Unknown Store", "api_endpoint": "http://localhost:8000", "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": false}; // Initialize widget const widget = new IncelebiWidgetCore(widgetConfig); // Register plugins widget.use(SingleProductPlugin); widget.use(BulkCartPlugin); // Start widget widget.init(); } catch (error) { console.error('İncelebi Widget Error:', error); // Prevent any text display on error if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { // Hide any potential text fallback var elements = document.querySelectorAll('script[src*="incelebi"]'); elements.forEach(function(el) { if (el.nextSibling && el.nextSibling.nodeType === 3) { el.nextSibling.remove(); } }); }); } } })(); // End IIFE Select element Send logs Screenshot
Image
Image
Image
Image
Image
Image
Image
Image
Image

DERİCLUB WM030 Hakiki Deri Kadın Uzun Trençkot

13.199,00 ₺9.239,30 ₺(KDV Dahil)%30
2. ÜRÜNDE %40 İNDİRİM
1 Değerlendirme
RENK: SİYAH
BEDEN:
WM030 Kadın Geniş Yaka Relax Kalıp Deri Trençkot
Geniş ve sivri yakalı tasarımı modern ve etkileyici bir görünüm sunar.
Önden düz kesimle kapanan, kuşaksız sade formdadır.
Yanlarda iki adet dikey cep mevcuttur.
Arka etekteki açıklık hareket özgürlüğü sağlar.
%100 gerçek koyun derisiyle üretilmiş olup iç kısmı astarlıdır.
Dört mevsim kullanım için idealdir, hem günlük hem şehir şıklığında değerlendirilebilir.
Modelin boyu 172 cm, kilosu 57 kg olup üzerindeki ürün S bedendir.
Ürün Özellikleri
Yaş Grubu
Cinsiyet

Değerlendirmeler

0 Değerlendirme