@adstage/web-sdk 2.1.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +100 -8
- package/dist/index.d.ts +5 -1
- package/dist/index.esm.js +100 -8
- package/dist/index.standalone.js +100 -8
- package/package.json +1 -1
- package/src/modules/ads/AdsModule.ts +111 -8
package/dist/index.cjs.js
CHANGED
|
@@ -2217,6 +2217,10 @@ class AdsModule {
|
|
|
2217
2217
|
const adElement = document.createElement('div');
|
|
2218
2218
|
adElement.id = slotId;
|
|
2219
2219
|
adElement.className = `adstage-slot adstage-${type.toLowerCase()}`;
|
|
2220
|
+
// 확실한 컨테이너 식별을 위한 데이터 속성 추가
|
|
2221
|
+
adElement.setAttribute('data-adstage-container', 'true');
|
|
2222
|
+
adElement.setAttribute('data-adstage-type', type);
|
|
2223
|
+
adElement.setAttribute('data-adstage-slot', slotId);
|
|
2220
2224
|
adElement.style.width = typeof options.width === 'number' ? `${options.width}px` : (options.width || '100%');
|
|
2221
2225
|
adElement.style.height = typeof options.height === 'number' ? `${options.height}px` : (options.height || '250px');
|
|
2222
2226
|
adElement.style.border = '1px dashed #ccc';
|
|
@@ -2314,22 +2318,110 @@ class AdsModule {
|
|
|
2314
2318
|
}
|
|
2315
2319
|
}
|
|
2316
2320
|
/**
|
|
2317
|
-
* Fallback 광고 렌더링 -
|
|
2321
|
+
* Fallback 광고 렌더링 - AdStage 확실한 컨테이너 우선 탐지
|
|
2318
2322
|
*/
|
|
2319
2323
|
renderFallback(slot) {
|
|
2320
2324
|
const element = document.getElementById(slot.id);
|
|
2321
2325
|
if (element) {
|
|
2322
|
-
//
|
|
2323
|
-
const
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
+
// 1순위: AdStage가 생성한 확실한 컨테이너들 (데이터 속성 기반)
|
|
2327
|
+
const adstageContainers = [
|
|
2328
|
+
element.querySelector('[data-adstage-container="true"]'), // 내부 AdStage 컨테이너
|
|
2329
|
+
element.closest('[data-adstage-container="true"]'), // 상위 AdStage 컨테이너
|
|
2330
|
+
element, // 자기 자신이 AdStage 컨테이너인 경우
|
|
2331
|
+
].filter(el => el && el.hasAttribute('data-adstage-container'));
|
|
2332
|
+
// 2순위: AdStage 클래스 기반 컨테이너들
|
|
2333
|
+
const classBasedContainers = [
|
|
2334
|
+
element.closest('.adstage-slot'),
|
|
2335
|
+
element.closest('.adstage-banner'),
|
|
2336
|
+
element.closest('.adstage-text'),
|
|
2337
|
+
element.closest('.adstage-video'),
|
|
2338
|
+
element.closest('.adstage-native'),
|
|
2339
|
+
element.closest('.adstage-interstitial'),
|
|
2340
|
+
].filter(Boolean);
|
|
2341
|
+
// 3순위: 일반적인 광고 컨테이너 패턴들 (fallback)
|
|
2342
|
+
const generalContainers = [
|
|
2343
|
+
element.closest('[class*="ad"]'),
|
|
2344
|
+
element.closest('[class*="banner"]'),
|
|
2345
|
+
element.closest('[class*="container"]'),
|
|
2346
|
+
element.closest('div[style*="height"]'),
|
|
2347
|
+
element.closest('div[style*="min-height"]'),
|
|
2348
|
+
element.parentElement
|
|
2349
|
+
].filter(Boolean);
|
|
2350
|
+
// 우선순위에 따라 컨테이너 선택
|
|
2351
|
+
const possibleContainers = [
|
|
2352
|
+
...adstageContainers,
|
|
2353
|
+
...classBasedContainers,
|
|
2354
|
+
...generalContainers
|
|
2355
|
+
];
|
|
2356
|
+
// 가장 적절한 컨테이너 선택
|
|
2357
|
+
const targetContainer = possibleContainers[0];
|
|
2358
|
+
if (targetContainer) {
|
|
2359
|
+
// 컨테이너 타입 로깅
|
|
2360
|
+
let containerType = 'unknown';
|
|
2361
|
+
if (targetContainer.hasAttribute('data-adstage-container')) {
|
|
2362
|
+
containerType = 'adstage-official';
|
|
2363
|
+
}
|
|
2364
|
+
else if (targetContainer.classList.contains('adstage-slot')) {
|
|
2365
|
+
containerType = 'adstage-class';
|
|
2366
|
+
}
|
|
2367
|
+
else {
|
|
2368
|
+
containerType = 'generic';
|
|
2369
|
+
}
|
|
2370
|
+
targetContainer.style.cssText += `
|
|
2371
|
+
height: 0px !important;
|
|
2372
|
+
min-height: 0px !important;
|
|
2373
|
+
padding: 0px !important;
|
|
2374
|
+
margin: 0px !important;
|
|
2375
|
+
border: none !important;
|
|
2376
|
+
overflow: hidden !important;
|
|
2377
|
+
display: block !important;
|
|
2378
|
+
`;
|
|
2379
|
+
// 내부 모든 요소 제거
|
|
2380
|
+
targetContainer.innerHTML = '';
|
|
2381
|
+
// 빈 상태임을 표시하는 속성 추가
|
|
2382
|
+
targetContainer.setAttribute('data-adstage-empty', 'true');
|
|
2326
2383
|
if (this._config?.debug) {
|
|
2327
|
-
console.warn(`⚠️ Ad
|
|
2384
|
+
console.warn(`⚠️ Ad container collapsed (${containerType}): ${slot.id}`, targetContainer);
|
|
2328
2385
|
}
|
|
2329
2386
|
}
|
|
2387
|
+
else {
|
|
2388
|
+
// 컨테이너를 찾지 못한 경우 새로운 빈 컨테이너 생성
|
|
2389
|
+
this.createEmptyContainer(slot);
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
// 슬롯 상태 업데이트 (제거하지 않고 빈 상태로 마킹)
|
|
2393
|
+
slot.advertisement = undefined;
|
|
2394
|
+
slot.isEmpty = true;
|
|
2395
|
+
}
|
|
2396
|
+
/**
|
|
2397
|
+
* 빈 컨테이너 생성 (컨테이너를 찾지 못한 경우)
|
|
2398
|
+
*/
|
|
2399
|
+
createEmptyContainer(slot) {
|
|
2400
|
+
const originalContainer = document.getElementById(slot.containerId);
|
|
2401
|
+
if (originalContainer) {
|
|
2402
|
+
// 기존 내용 제거
|
|
2403
|
+
originalContainer.innerHTML = '';
|
|
2404
|
+
// 빈 AdStage 컨테이너 생성
|
|
2405
|
+
const emptyElement = document.createElement('div');
|
|
2406
|
+
emptyElement.id = slot.id;
|
|
2407
|
+
emptyElement.className = 'adstage-slot adstage-empty';
|
|
2408
|
+
emptyElement.setAttribute('data-adstage-container', 'true');
|
|
2409
|
+
emptyElement.setAttribute('data-adstage-empty', 'true');
|
|
2410
|
+
emptyElement.setAttribute('data-adstage-slot', slot.id);
|
|
2411
|
+
emptyElement.style.cssText = `
|
|
2412
|
+
height: 0px !important;
|
|
2413
|
+
min-height: 0px !important;
|
|
2414
|
+
padding: 0px !important;
|
|
2415
|
+
margin: 0px !important;
|
|
2416
|
+
border: none !important;
|
|
2417
|
+
overflow: hidden !important;
|
|
2418
|
+
display: block !important;
|
|
2419
|
+
`;
|
|
2420
|
+
originalContainer.appendChild(emptyElement);
|
|
2421
|
+
if (this._config?.debug) {
|
|
2422
|
+
console.warn(`⚠️ Created empty AdStage container: ${slot.id}`);
|
|
2423
|
+
}
|
|
2330
2424
|
}
|
|
2331
|
-
// 슬롯 맵에서도 제거
|
|
2332
|
-
this.slots.delete(slot.id);
|
|
2333
2425
|
}
|
|
2334
2426
|
/**
|
|
2335
2427
|
* 광고 데이터 가져오기
|
package/dist/index.d.ts
CHANGED
|
@@ -295,9 +295,13 @@ declare class AdsModule implements BaseModule {
|
|
|
295
295
|
*/
|
|
296
296
|
private handleViewableEvent;
|
|
297
297
|
/**
|
|
298
|
-
* Fallback 광고 렌더링 -
|
|
298
|
+
* Fallback 광고 렌더링 - AdStage 확실한 컨테이너 우선 탐지
|
|
299
299
|
*/
|
|
300
300
|
private renderFallback;
|
|
301
|
+
/**
|
|
302
|
+
* 빈 컨테이너 생성 (컨테이너를 찾지 못한 경우)
|
|
303
|
+
*/
|
|
304
|
+
private createEmptyContainer;
|
|
301
305
|
/**
|
|
302
306
|
* 광고 데이터 가져오기
|
|
303
307
|
*/
|
package/dist/index.esm.js
CHANGED
|
@@ -2215,6 +2215,10 @@ class AdsModule {
|
|
|
2215
2215
|
const adElement = document.createElement('div');
|
|
2216
2216
|
adElement.id = slotId;
|
|
2217
2217
|
adElement.className = `adstage-slot adstage-${type.toLowerCase()}`;
|
|
2218
|
+
// 확실한 컨테이너 식별을 위한 데이터 속성 추가
|
|
2219
|
+
adElement.setAttribute('data-adstage-container', 'true');
|
|
2220
|
+
adElement.setAttribute('data-adstage-type', type);
|
|
2221
|
+
adElement.setAttribute('data-adstage-slot', slotId);
|
|
2218
2222
|
adElement.style.width = typeof options.width === 'number' ? `${options.width}px` : (options.width || '100%');
|
|
2219
2223
|
adElement.style.height = typeof options.height === 'number' ? `${options.height}px` : (options.height || '250px');
|
|
2220
2224
|
adElement.style.border = '1px dashed #ccc';
|
|
@@ -2312,22 +2316,110 @@ class AdsModule {
|
|
|
2312
2316
|
}
|
|
2313
2317
|
}
|
|
2314
2318
|
/**
|
|
2315
|
-
* Fallback 광고 렌더링 -
|
|
2319
|
+
* Fallback 광고 렌더링 - AdStage 확실한 컨테이너 우선 탐지
|
|
2316
2320
|
*/
|
|
2317
2321
|
renderFallback(slot) {
|
|
2318
2322
|
const element = document.getElementById(slot.id);
|
|
2319
2323
|
if (element) {
|
|
2320
|
-
//
|
|
2321
|
-
const
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
+
// 1순위: AdStage가 생성한 확실한 컨테이너들 (데이터 속성 기반)
|
|
2325
|
+
const adstageContainers = [
|
|
2326
|
+
element.querySelector('[data-adstage-container="true"]'), // 내부 AdStage 컨테이너
|
|
2327
|
+
element.closest('[data-adstage-container="true"]'), // 상위 AdStage 컨테이너
|
|
2328
|
+
element, // 자기 자신이 AdStage 컨테이너인 경우
|
|
2329
|
+
].filter(el => el && el.hasAttribute('data-adstage-container'));
|
|
2330
|
+
// 2순위: AdStage 클래스 기반 컨테이너들
|
|
2331
|
+
const classBasedContainers = [
|
|
2332
|
+
element.closest('.adstage-slot'),
|
|
2333
|
+
element.closest('.adstage-banner'),
|
|
2334
|
+
element.closest('.adstage-text'),
|
|
2335
|
+
element.closest('.adstage-video'),
|
|
2336
|
+
element.closest('.adstage-native'),
|
|
2337
|
+
element.closest('.adstage-interstitial'),
|
|
2338
|
+
].filter(Boolean);
|
|
2339
|
+
// 3순위: 일반적인 광고 컨테이너 패턴들 (fallback)
|
|
2340
|
+
const generalContainers = [
|
|
2341
|
+
element.closest('[class*="ad"]'),
|
|
2342
|
+
element.closest('[class*="banner"]'),
|
|
2343
|
+
element.closest('[class*="container"]'),
|
|
2344
|
+
element.closest('div[style*="height"]'),
|
|
2345
|
+
element.closest('div[style*="min-height"]'),
|
|
2346
|
+
element.parentElement
|
|
2347
|
+
].filter(Boolean);
|
|
2348
|
+
// 우선순위에 따라 컨테이너 선택
|
|
2349
|
+
const possibleContainers = [
|
|
2350
|
+
...adstageContainers,
|
|
2351
|
+
...classBasedContainers,
|
|
2352
|
+
...generalContainers
|
|
2353
|
+
];
|
|
2354
|
+
// 가장 적절한 컨테이너 선택
|
|
2355
|
+
const targetContainer = possibleContainers[0];
|
|
2356
|
+
if (targetContainer) {
|
|
2357
|
+
// 컨테이너 타입 로깅
|
|
2358
|
+
let containerType = 'unknown';
|
|
2359
|
+
if (targetContainer.hasAttribute('data-adstage-container')) {
|
|
2360
|
+
containerType = 'adstage-official';
|
|
2361
|
+
}
|
|
2362
|
+
else if (targetContainer.classList.contains('adstage-slot')) {
|
|
2363
|
+
containerType = 'adstage-class';
|
|
2364
|
+
}
|
|
2365
|
+
else {
|
|
2366
|
+
containerType = 'generic';
|
|
2367
|
+
}
|
|
2368
|
+
targetContainer.style.cssText += `
|
|
2369
|
+
height: 0px !important;
|
|
2370
|
+
min-height: 0px !important;
|
|
2371
|
+
padding: 0px !important;
|
|
2372
|
+
margin: 0px !important;
|
|
2373
|
+
border: none !important;
|
|
2374
|
+
overflow: hidden !important;
|
|
2375
|
+
display: block !important;
|
|
2376
|
+
`;
|
|
2377
|
+
// 내부 모든 요소 제거
|
|
2378
|
+
targetContainer.innerHTML = '';
|
|
2379
|
+
// 빈 상태임을 표시하는 속성 추가
|
|
2380
|
+
targetContainer.setAttribute('data-adstage-empty', 'true');
|
|
2324
2381
|
if (this._config?.debug) {
|
|
2325
|
-
console.warn(`⚠️ Ad
|
|
2382
|
+
console.warn(`⚠️ Ad container collapsed (${containerType}): ${slot.id}`, targetContainer);
|
|
2326
2383
|
}
|
|
2327
2384
|
}
|
|
2385
|
+
else {
|
|
2386
|
+
// 컨테이너를 찾지 못한 경우 새로운 빈 컨테이너 생성
|
|
2387
|
+
this.createEmptyContainer(slot);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
// 슬롯 상태 업데이트 (제거하지 않고 빈 상태로 마킹)
|
|
2391
|
+
slot.advertisement = undefined;
|
|
2392
|
+
slot.isEmpty = true;
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* 빈 컨테이너 생성 (컨테이너를 찾지 못한 경우)
|
|
2396
|
+
*/
|
|
2397
|
+
createEmptyContainer(slot) {
|
|
2398
|
+
const originalContainer = document.getElementById(slot.containerId);
|
|
2399
|
+
if (originalContainer) {
|
|
2400
|
+
// 기존 내용 제거
|
|
2401
|
+
originalContainer.innerHTML = '';
|
|
2402
|
+
// 빈 AdStage 컨테이너 생성
|
|
2403
|
+
const emptyElement = document.createElement('div');
|
|
2404
|
+
emptyElement.id = slot.id;
|
|
2405
|
+
emptyElement.className = 'adstage-slot adstage-empty';
|
|
2406
|
+
emptyElement.setAttribute('data-adstage-container', 'true');
|
|
2407
|
+
emptyElement.setAttribute('data-adstage-empty', 'true');
|
|
2408
|
+
emptyElement.setAttribute('data-adstage-slot', slot.id);
|
|
2409
|
+
emptyElement.style.cssText = `
|
|
2410
|
+
height: 0px !important;
|
|
2411
|
+
min-height: 0px !important;
|
|
2412
|
+
padding: 0px !important;
|
|
2413
|
+
margin: 0px !important;
|
|
2414
|
+
border: none !important;
|
|
2415
|
+
overflow: hidden !important;
|
|
2416
|
+
display: block !important;
|
|
2417
|
+
`;
|
|
2418
|
+
originalContainer.appendChild(emptyElement);
|
|
2419
|
+
if (this._config?.debug) {
|
|
2420
|
+
console.warn(`⚠️ Created empty AdStage container: ${slot.id}`);
|
|
2421
|
+
}
|
|
2328
2422
|
}
|
|
2329
|
-
// 슬롯 맵에서도 제거
|
|
2330
|
-
this.slots.delete(slot.id);
|
|
2331
2423
|
}
|
|
2332
2424
|
/**
|
|
2333
2425
|
* 광고 데이터 가져오기
|
package/dist/index.standalone.js
CHANGED
|
@@ -2215,6 +2215,10 @@ class AdsModule {
|
|
|
2215
2215
|
const adElement = document.createElement('div');
|
|
2216
2216
|
adElement.id = slotId;
|
|
2217
2217
|
adElement.className = `adstage-slot adstage-${type.toLowerCase()}`;
|
|
2218
|
+
// 확실한 컨테이너 식별을 위한 데이터 속성 추가
|
|
2219
|
+
adElement.setAttribute('data-adstage-container', 'true');
|
|
2220
|
+
adElement.setAttribute('data-adstage-type', type);
|
|
2221
|
+
adElement.setAttribute('data-adstage-slot', slotId);
|
|
2218
2222
|
adElement.style.width = typeof options.width === 'number' ? `${options.width}px` : (options.width || '100%');
|
|
2219
2223
|
adElement.style.height = typeof options.height === 'number' ? `${options.height}px` : (options.height || '250px');
|
|
2220
2224
|
adElement.style.border = '1px dashed #ccc';
|
|
@@ -2312,22 +2316,110 @@ class AdsModule {
|
|
|
2312
2316
|
}
|
|
2313
2317
|
}
|
|
2314
2318
|
/**
|
|
2315
|
-
* Fallback 광고 렌더링 -
|
|
2319
|
+
* Fallback 광고 렌더링 - AdStage 확실한 컨테이너 우선 탐지
|
|
2316
2320
|
*/
|
|
2317
2321
|
renderFallback(slot) {
|
|
2318
2322
|
const element = document.getElementById(slot.id);
|
|
2319
2323
|
if (element) {
|
|
2320
|
-
//
|
|
2321
|
-
const
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
+
// 1순위: AdStage가 생성한 확실한 컨테이너들 (데이터 속성 기반)
|
|
2325
|
+
const adstageContainers = [
|
|
2326
|
+
element.querySelector('[data-adstage-container="true"]'), // 내부 AdStage 컨테이너
|
|
2327
|
+
element.closest('[data-adstage-container="true"]'), // 상위 AdStage 컨테이너
|
|
2328
|
+
element, // 자기 자신이 AdStage 컨테이너인 경우
|
|
2329
|
+
].filter(el => el && el.hasAttribute('data-adstage-container'));
|
|
2330
|
+
// 2순위: AdStage 클래스 기반 컨테이너들
|
|
2331
|
+
const classBasedContainers = [
|
|
2332
|
+
element.closest('.adstage-slot'),
|
|
2333
|
+
element.closest('.adstage-banner'),
|
|
2334
|
+
element.closest('.adstage-text'),
|
|
2335
|
+
element.closest('.adstage-video'),
|
|
2336
|
+
element.closest('.adstage-native'),
|
|
2337
|
+
element.closest('.adstage-interstitial'),
|
|
2338
|
+
].filter(Boolean);
|
|
2339
|
+
// 3순위: 일반적인 광고 컨테이너 패턴들 (fallback)
|
|
2340
|
+
const generalContainers = [
|
|
2341
|
+
element.closest('[class*="ad"]'),
|
|
2342
|
+
element.closest('[class*="banner"]'),
|
|
2343
|
+
element.closest('[class*="container"]'),
|
|
2344
|
+
element.closest('div[style*="height"]'),
|
|
2345
|
+
element.closest('div[style*="min-height"]'),
|
|
2346
|
+
element.parentElement
|
|
2347
|
+
].filter(Boolean);
|
|
2348
|
+
// 우선순위에 따라 컨테이너 선택
|
|
2349
|
+
const possibleContainers = [
|
|
2350
|
+
...adstageContainers,
|
|
2351
|
+
...classBasedContainers,
|
|
2352
|
+
...generalContainers
|
|
2353
|
+
];
|
|
2354
|
+
// 가장 적절한 컨테이너 선택
|
|
2355
|
+
const targetContainer = possibleContainers[0];
|
|
2356
|
+
if (targetContainer) {
|
|
2357
|
+
// 컨테이너 타입 로깅
|
|
2358
|
+
let containerType = 'unknown';
|
|
2359
|
+
if (targetContainer.hasAttribute('data-adstage-container')) {
|
|
2360
|
+
containerType = 'adstage-official';
|
|
2361
|
+
}
|
|
2362
|
+
else if (targetContainer.classList.contains('adstage-slot')) {
|
|
2363
|
+
containerType = 'adstage-class';
|
|
2364
|
+
}
|
|
2365
|
+
else {
|
|
2366
|
+
containerType = 'generic';
|
|
2367
|
+
}
|
|
2368
|
+
targetContainer.style.cssText += `
|
|
2369
|
+
height: 0px !important;
|
|
2370
|
+
min-height: 0px !important;
|
|
2371
|
+
padding: 0px !important;
|
|
2372
|
+
margin: 0px !important;
|
|
2373
|
+
border: none !important;
|
|
2374
|
+
overflow: hidden !important;
|
|
2375
|
+
display: block !important;
|
|
2376
|
+
`;
|
|
2377
|
+
// 내부 모든 요소 제거
|
|
2378
|
+
targetContainer.innerHTML = '';
|
|
2379
|
+
// 빈 상태임을 표시하는 속성 추가
|
|
2380
|
+
targetContainer.setAttribute('data-adstage-empty', 'true');
|
|
2324
2381
|
if (this._config?.debug) {
|
|
2325
|
-
console.warn(`⚠️ Ad
|
|
2382
|
+
console.warn(`⚠️ Ad container collapsed (${containerType}): ${slot.id}`, targetContainer);
|
|
2326
2383
|
}
|
|
2327
2384
|
}
|
|
2385
|
+
else {
|
|
2386
|
+
// 컨테이너를 찾지 못한 경우 새로운 빈 컨테이너 생성
|
|
2387
|
+
this.createEmptyContainer(slot);
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
// 슬롯 상태 업데이트 (제거하지 않고 빈 상태로 마킹)
|
|
2391
|
+
slot.advertisement = undefined;
|
|
2392
|
+
slot.isEmpty = true;
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* 빈 컨테이너 생성 (컨테이너를 찾지 못한 경우)
|
|
2396
|
+
*/
|
|
2397
|
+
createEmptyContainer(slot) {
|
|
2398
|
+
const originalContainer = document.getElementById(slot.containerId);
|
|
2399
|
+
if (originalContainer) {
|
|
2400
|
+
// 기존 내용 제거
|
|
2401
|
+
originalContainer.innerHTML = '';
|
|
2402
|
+
// 빈 AdStage 컨테이너 생성
|
|
2403
|
+
const emptyElement = document.createElement('div');
|
|
2404
|
+
emptyElement.id = slot.id;
|
|
2405
|
+
emptyElement.className = 'adstage-slot adstage-empty';
|
|
2406
|
+
emptyElement.setAttribute('data-adstage-container', 'true');
|
|
2407
|
+
emptyElement.setAttribute('data-adstage-empty', 'true');
|
|
2408
|
+
emptyElement.setAttribute('data-adstage-slot', slot.id);
|
|
2409
|
+
emptyElement.style.cssText = `
|
|
2410
|
+
height: 0px !important;
|
|
2411
|
+
min-height: 0px !important;
|
|
2412
|
+
padding: 0px !important;
|
|
2413
|
+
margin: 0px !important;
|
|
2414
|
+
border: none !important;
|
|
2415
|
+
overflow: hidden !important;
|
|
2416
|
+
display: block !important;
|
|
2417
|
+
`;
|
|
2418
|
+
originalContainer.appendChild(emptyElement);
|
|
2419
|
+
if (this._config?.debug) {
|
|
2420
|
+
console.warn(`⚠️ Created empty AdStage container: ${slot.id}`);
|
|
2421
|
+
}
|
|
2328
2422
|
}
|
|
2329
|
-
// 슬롯 맵에서도 제거
|
|
2330
|
-
this.slots.delete(slot.id);
|
|
2331
2423
|
}
|
|
2332
2424
|
/**
|
|
2333
2425
|
* 광고 데이터 가져오기
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adstage/web-sdk",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "AdStage Web SDK - Production-ready marketing platform SDK with namespace architecture for ads, events, and config management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs.js",
|
|
@@ -279,6 +279,11 @@ export class AdsModule implements BaseModule {
|
|
|
279
279
|
const adElement = document.createElement('div');
|
|
280
280
|
adElement.id = slotId;
|
|
281
281
|
adElement.className = `adstage-slot adstage-${type.toLowerCase()}`;
|
|
282
|
+
// 확실한 컨테이너 식별을 위한 데이터 속성 추가
|
|
283
|
+
adElement.setAttribute('data-adstage-container', 'true');
|
|
284
|
+
adElement.setAttribute('data-adstage-type', type);
|
|
285
|
+
adElement.setAttribute('data-adstage-slot', slotId);
|
|
286
|
+
|
|
282
287
|
adElement.style.width = typeof options.width === 'number' ? `${options.width}px` : (options.width || '100%');
|
|
283
288
|
adElement.style.height = typeof options.height === 'number' ? `${options.height}px` : (options.height || '250px');
|
|
284
289
|
adElement.style.border = '1px dashed #ccc';
|
|
@@ -401,24 +406,122 @@ export class AdsModule implements BaseModule {
|
|
|
401
406
|
}
|
|
402
407
|
|
|
403
408
|
/**
|
|
404
|
-
* Fallback 광고 렌더링 -
|
|
409
|
+
* Fallback 광고 렌더링 - AdStage 확실한 컨테이너 우선 탐지
|
|
405
410
|
*/
|
|
406
411
|
private renderFallback(slot: AdSlot): void {
|
|
407
412
|
const element = document.getElementById(slot.id);
|
|
408
413
|
if (element) {
|
|
409
|
-
//
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
414
|
+
// 1순위: AdStage가 생성한 확실한 컨테이너들 (데이터 속성 기반)
|
|
415
|
+
const adstageContainers = [
|
|
416
|
+
element.querySelector('[data-adstage-container="true"]'), // 내부 AdStage 컨테이너
|
|
417
|
+
element.closest('[data-adstage-container="true"]'), // 상위 AdStage 컨테이너
|
|
418
|
+
element, // 자기 자신이 AdStage 컨테이너인 경우
|
|
419
|
+
].filter(el => el && el.hasAttribute('data-adstage-container'));
|
|
420
|
+
|
|
421
|
+
// 2순위: AdStage 클래스 기반 컨테이너들
|
|
422
|
+
const classBasedContainers = [
|
|
423
|
+
element.closest('.adstage-slot'),
|
|
424
|
+
element.closest('.adstage-banner'),
|
|
425
|
+
element.closest('.adstage-text'),
|
|
426
|
+
element.closest('.adstage-video'),
|
|
427
|
+
element.closest('.adstage-native'),
|
|
428
|
+
element.closest('.adstage-interstitial'),
|
|
429
|
+
].filter(Boolean);
|
|
430
|
+
|
|
431
|
+
// 3순위: 일반적인 광고 컨테이너 패턴들 (fallback)
|
|
432
|
+
const generalContainers = [
|
|
433
|
+
element.closest('[class*="ad"]'),
|
|
434
|
+
element.closest('[class*="banner"]'),
|
|
435
|
+
element.closest('[class*="container"]'),
|
|
436
|
+
element.closest('div[style*="height"]'),
|
|
437
|
+
element.closest('div[style*="min-height"]'),
|
|
438
|
+
element.parentElement
|
|
439
|
+
].filter(Boolean);
|
|
440
|
+
|
|
441
|
+
// 우선순위에 따라 컨테이너 선택
|
|
442
|
+
const possibleContainers = [
|
|
443
|
+
...adstageContainers,
|
|
444
|
+
...classBasedContainers,
|
|
445
|
+
...generalContainers
|
|
446
|
+
];
|
|
447
|
+
|
|
448
|
+
// 가장 적절한 컨테이너 선택
|
|
449
|
+
const targetContainer = possibleContainers[0] as HTMLElement;
|
|
450
|
+
|
|
451
|
+
if (targetContainer) {
|
|
452
|
+
// 컨테이너 타입 로깅
|
|
453
|
+
let containerType = 'unknown';
|
|
454
|
+
if (targetContainer.hasAttribute('data-adstage-container')) {
|
|
455
|
+
containerType = 'adstage-official';
|
|
456
|
+
} else if (targetContainer.classList.contains('adstage-slot')) {
|
|
457
|
+
containerType = 'adstage-class';
|
|
458
|
+
} else {
|
|
459
|
+
containerType = 'generic';
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
targetContainer.style.cssText += `
|
|
463
|
+
height: 0px !important;
|
|
464
|
+
min-height: 0px !important;
|
|
465
|
+
padding: 0px !important;
|
|
466
|
+
margin: 0px !important;
|
|
467
|
+
border: none !important;
|
|
468
|
+
overflow: hidden !important;
|
|
469
|
+
display: block !important;
|
|
470
|
+
`;
|
|
471
|
+
|
|
472
|
+
// 내부 모든 요소 제거
|
|
473
|
+
targetContainer.innerHTML = '';
|
|
474
|
+
|
|
475
|
+
// 빈 상태임을 표시하는 속성 추가
|
|
476
|
+
targetContainer.setAttribute('data-adstage-empty', 'true');
|
|
413
477
|
|
|
414
478
|
if (this._config?.debug) {
|
|
415
|
-
console.warn(`⚠️ Ad
|
|
479
|
+
console.warn(`⚠️ Ad container collapsed (${containerType}): ${slot.id}`, targetContainer);
|
|
416
480
|
}
|
|
481
|
+
} else {
|
|
482
|
+
// 컨테이너를 찾지 못한 경우 새로운 빈 컨테이너 생성
|
|
483
|
+
this.createEmptyContainer(slot);
|
|
417
484
|
}
|
|
418
485
|
}
|
|
419
486
|
|
|
420
|
-
// 슬롯
|
|
421
|
-
|
|
487
|
+
// 슬롯 상태 업데이트 (제거하지 않고 빈 상태로 마킹)
|
|
488
|
+
slot.advertisement = undefined;
|
|
489
|
+
(slot as any).isEmpty = true;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 빈 컨테이너 생성 (컨테이너를 찾지 못한 경우)
|
|
494
|
+
*/
|
|
495
|
+
private createEmptyContainer(slot: AdSlot): void {
|
|
496
|
+
const originalContainer = document.getElementById(slot.containerId);
|
|
497
|
+
if (originalContainer) {
|
|
498
|
+
// 기존 내용 제거
|
|
499
|
+
originalContainer.innerHTML = '';
|
|
500
|
+
|
|
501
|
+
// 빈 AdStage 컨테이너 생성
|
|
502
|
+
const emptyElement = document.createElement('div');
|
|
503
|
+
emptyElement.id = slot.id;
|
|
504
|
+
emptyElement.className = 'adstage-slot adstage-empty';
|
|
505
|
+
emptyElement.setAttribute('data-adstage-container', 'true');
|
|
506
|
+
emptyElement.setAttribute('data-adstage-empty', 'true');
|
|
507
|
+
emptyElement.setAttribute('data-adstage-slot', slot.id);
|
|
508
|
+
|
|
509
|
+
emptyElement.style.cssText = `
|
|
510
|
+
height: 0px !important;
|
|
511
|
+
min-height: 0px !important;
|
|
512
|
+
padding: 0px !important;
|
|
513
|
+
margin: 0px !important;
|
|
514
|
+
border: none !important;
|
|
515
|
+
overflow: hidden !important;
|
|
516
|
+
display: block !important;
|
|
517
|
+
`;
|
|
518
|
+
|
|
519
|
+
originalContainer.appendChild(emptyElement);
|
|
520
|
+
|
|
521
|
+
if (this._config?.debug) {
|
|
522
|
+
console.warn(`⚠️ Created empty AdStage container: ${slot.id}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
422
525
|
}
|
|
423
526
|
|
|
424
527
|
/**
|