Created
June 18, 2025 11:58
-
-
Save mehmetsagir/2238895c3cba40ff44d9516f47c63d0c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // --- ConfigManager --- | |
| export class ConfigManager { | |
| constructor(config) { | |
| this.config = this.validateConfig(config); | |
| } | |
| validateConfig(config) { | |
| // Basit doğrulama (geliştirilebilir) | |
| return config; | |
| } | |
| get() { | |
| if (!this.config) throw new Error("Config yüklenmedi!"); | |
| // Hedef klasörler config'te yoksa default değerleri kullan | |
| const defaultTargetUrlFolders = [ | |
| { name: "urunresimleri", checkThumb: true, forceBigKey: true, customValues: { quality: 85 }, imageType: "product" }, | |
| { name: "ilgiliurunresim", checkThumb: true, forceBigKey: false, customValues: { quality: 85 }, imageType: "product" }, | |
| { name: "aksesuarurunresim", checkThumb: true, forceBigKey: false, customValues: { quality: 85 }, imageType: "product" }, | |
| { name: "sayfatasarim", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "design" }, | |
| { name: "editoruploads", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "design" }, | |
| { name: "images", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "design" }, | |
| { name: "dosyalar", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "design" }, | |
| { name: "kampanyabanner", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "design" }, | |
| { name: "marka", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "brand" }, | |
| { name: "blog", checkThumb: false, forceBigKey: false, customValues: { quality: 99 }, imageType: "blog" }, | |
| ]; | |
| return { | |
| ...this.config, | |
| targetUrlFolders: this.config.targetUrlFolders || defaultTargetUrlFolders | |
| }; | |
| } | |
| } | |
| // --- ObserverManager --- | |
| export class ObserverManager { | |
| constructor(targetConfig, callback) { | |
| this.observer = null; | |
| this.callback = callback; | |
| this.init(targetConfig); | |
| } | |
| init(targetConfig) { | |
| const target = document.querySelector(targetConfig.rootSelector); | |
| if (target) { | |
| this.observer = new MutationObserver(this.callback); | |
| this.observer.observe(target, { | |
| childList: true, | |
| subtree: true, | |
| attributes: true, | |
| attributeFilter: targetConfig.watchAttributes | |
| }); | |
| } | |
| } | |
| disconnect() { | |
| if (this.observer) this.observer.disconnect(); | |
| } | |
| } | |
| // --- ImageResizePlugin --- | |
| function createOptimizedUrl({ cdnTarget, width, height, quality, path, targetUrlFolders }) { | |
| // Klasöre göre spesifik kalite varsa onu kullan, yoksa parametreyle gelen quality'yi kullan | |
| let usedQuality = quality; | |
| let matchedFolder = null; | |
| for (let folder of targetUrlFolders) { | |
| if (path.indexOf(folder.name) > -1) { | |
| matchedFolder = folder; | |
| if (folder.customValues && typeof folder.customValues.quality !== 'undefined') { | |
| usedQuality = folder.customValues.quality; | |
| } | |
| break; | |
| } | |
| } | |
| let paramStr = `width=${width}`; | |
| if (height && height !== '-') paramStr += `,height=${height}`; | |
| paramStr += `,quality=${usedQuality}`; | |
| let optimizedUrl = `${cdnTarget}/${paramStr}${path}`; | |
| // /thumb/ -> /buyuk/ düzeltmesi ve forceBigKey uygula | |
| if (matchedFolder) { | |
| if (matchedFolder.checkThumb) { | |
| optimizedUrl = optimizedUrl.replace('/thumb/', '/buyuk/'); | |
| } | |
| if (matchedFolder.forceBigKey) { | |
| if (optimizedUrl.indexOf(`/${matchedFolder.name}/`) > -1 && optimizedUrl.indexOf(`/${matchedFolder.name}/buyuk/`) === -1) { | |
| optimizedUrl = optimizedUrl.replace(`/${matchedFolder.name}/`, `/${matchedFolder.name}/buyuk/`); | |
| } | |
| } | |
| } | |
| return optimizedUrl; | |
| } | |
| export class ImageResizePlugin { | |
| constructor(config) { | |
| this.configManager = new ConfigManager(config); | |
| this.observerManager = null; | |
| } | |
| init() { | |
| const config = this.configManager.get(); | |
| this.observerManager = new ObserverManager( | |
| config.target, | |
| this.handleMutations.bind(this) | |
| ); | |
| this.optimizeAllImages(); // Sayfa yüklenince tüm görselleri optimize et | |
| } | |
| // Tüm hedef container içindeki görselleri optimize et | |
| optimizeAllImages() { | |
| const config = this.configManager.get(); | |
| const container = document.querySelector(config.target.rootSelector); | |
| if (!container) return; | |
| container.querySelectorAll("img").forEach(img => { | |
| this.optimizeImage(img); | |
| }); | |
| } | |
| handleMutations(mutations) { | |
| mutations.forEach((mutation) => { | |
| if (mutation.type === "childList" && mutation.addedNodes.length > 0) { | |
| mutation.addedNodes.forEach((node) => { | |
| if (node.nodeType === Node.ELEMENT_NODE && node.tagName === "IMG") { | |
| this.optimizeImage(node); | |
| } | |
| // Eğer birden fazla img içeren bir element eklendiyse: | |
| if (node.nodeType === Node.ELEMENT_NODE) { | |
| node.querySelectorAll?.("img").forEach(img => this.optimizeImage(img)); | |
| } | |
| }); | |
| } | |
| if (mutation.type === "attributes") { | |
| // İstersen burada da optimizeImage çağrısı yapılabilir | |
| // this.optimizeImage(mutation.target); | |
| } | |
| }); | |
| } | |
| // Optimize fonksiyonu: CDN parametreli url oluştur (parent alanına göre width/height) | |
| optimizeImage(img) { | |
| const config = this.configManager.get(); | |
| const cdnSource = config.cdn.sourceUrl; | |
| const cdnTarget = config.cdn.targetUrl; | |
| // Genişlik ve yükseklik: Önce parent (ebeveyn) elemandan, yoksa img'den alınır | |
| let width, height; | |
| if (img.parentElement) { | |
| const parentRect = img.parentElement.getBoundingClientRect(); | |
| width = Math.round(parentRect.width); | |
| height = Math.round(parentRect.height); | |
| } | |
| if (!width) width = img.width || img.naturalWidth || 1920; | |
| if (!height) height = img.height || img.naturalHeight || undefined; | |
| // Optimize edilecek tüm attribute'lar için döngü | |
| const allowedSrcAttributes = ["src", "data-original", "data-src", "data-second", "data-zoom", "data-bigimg"]; | |
| // Kaynak olarak öncelikle data-src, yoksa data-original, yoksa src kullan | |
| let originalSrc = img.getAttribute("data-src") || img.getAttribute("data-original") || img.getAttribute("src"); | |
| if (!originalSrc || !originalSrc.startsWith(cdnSource)) return; | |
| // Eğer img'de src varsa ve optimize edilmemişse, src'yi geçici olarak boşalt | |
| if (img.hasAttribute("src") && img.getAttribute("src") === originalSrc) { | |
| img.setAttribute("src", ""); | |
| } | |
| for (const attr of allowedSrcAttributes) { | |
| // Her attribute için mevcutsa onu, yoksa originalSrc'yi kullan | |
| let src = img.getAttribute(attr); | |
| if (!src) src = originalSrc; | |
| if (!src.startsWith(cdnSource)) continue; | |
| const url = new URL(src); | |
| // Zaten optimize edilmişse atla | |
| if (url.pathname.startsWith('/cdn-cgi/image/')) { | |
| continue; | |
| } | |
| // /uploads/ dizininden itibaren path'i al | |
| const pathIndex = url.pathname.indexOf('/uploads/'); | |
| const path = pathIndex !== -1 ? url.pathname.substring(pathIndex - 5) : url.pathname; | |
| // data-original için optimize edilmemiş (orijinal) src atanır | |
| if (attr === 'data-original') { | |
| img.setAttribute(attr, originalSrc); | |
| console.log(`Görsel (data-original) orijinal olarak eklendi:`, originalSrc); | |
| continue; | |
| } | |
| // Her attribute için config'den özel değerleri al, yoksa genel değerleri kullan | |
| const attrConfig = config.image[attr] || {}; | |
| let attrWidth = attrConfig.width !== undefined ? attrConfig.width : width; | |
| let attrHeight = attrConfig.height !== undefined ? attrConfig.height : height; | |
| let attrQuality = attrConfig.quality !== undefined ? attrConfig.quality : (config.image.quality || 95); | |
| // data-zoom ve data-bigimg için width ve height her zaman '-' olmalı | |
| if (attr === 'data-zoom' || attr === 'data-bigimg') { | |
| attrWidth = '-'; | |
| attrHeight = '-'; | |
| } | |
| // data-zoom için özel durum: width negatif ise orijinal URL kullanılır | |
| if (attr === 'data-zoom' && attrWidth < 0) { | |
| img.setAttribute(attr, src); | |
| console.log(`Görsel optimize edildi (${attr}): orijinal URL kullanıldı`, src); | |
| continue; | |
| } | |
| // Klasöre göre kalite ve path düzeltmesi ile optimize edilmiş URL oluştur (config'ten targetUrlFolders alınır) | |
| const optimizedUrl = createOptimizedUrl({ | |
| cdnTarget, | |
| width: attrWidth, | |
| height: attrHeight, | |
| quality: attrQuality, | |
| path, | |
| targetUrlFolders: config.targetUrlFolders | |
| }); | |
| // Her zaman ilgili attribute'u güncelle (veya ekle) | |
| img.setAttribute(attr, optimizedUrl); | |
| // src attribute'u için optimize edilen URL'yi de yaz | |
| if (attr === 'src') { | |
| img.setAttribute('src', optimizedUrl); | |
| } | |
| console.log(`Görsel optimize edildi (${attr}):`, optimizedUrl); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment