mkfashion-sdk 2.3.0 → 2.3.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/index.html +66 -46
- package/package.json +1 -1
- package/src/mkfashion.js +72 -446
package/index.html
CHANGED
|
@@ -1,67 +1,87 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
2
|
+
<html lang="pt-BR">
|
|
4
3
|
<head>
|
|
5
4
|
<meta charset="UTF-8">
|
|
6
|
-
<
|
|
7
|
-
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Provador Virtual</title>
|
|
8
7
|
<script src="./src/mkfashion.js"></script>
|
|
9
|
-
<!-- Para produção, use o CDN: -->
|
|
10
|
-
<!-- <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script> -->
|
|
11
|
-
<style>
|
|
12
|
-
.btn-provar {
|
|
13
|
-
background: #000;
|
|
14
|
-
color: #fff;
|
|
15
|
-
padding: 12px 24px;
|
|
16
|
-
border: none;
|
|
17
|
-
border-radius: 8px;
|
|
18
|
-
cursor: pointer;
|
|
19
|
-
font-size: 16px;
|
|
20
|
-
display: none;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.btn-provar:hover {
|
|
24
|
-
background: #333;
|
|
25
|
-
}
|
|
26
|
-
</style>
|
|
27
8
|
</head>
|
|
28
|
-
|
|
29
9
|
<body>
|
|
30
10
|
|
|
31
|
-
<
|
|
32
|
-
<p>SKU: 165230</p>
|
|
33
|
-
|
|
34
|
-
<button class="btn-provar" id="btn-provar">
|
|
35
|
-
Provador Virtual
|
|
36
|
-
</button>
|
|
11
|
+
<button id="btn-provar" style="display: none;">Provar Virtualmente</button>
|
|
37
12
|
|
|
38
13
|
<script>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
14
|
+
(function() {
|
|
15
|
+
var projectid = '698c7cc61d3129430f15dddc';
|
|
16
|
+
var identifier = '16255';
|
|
17
|
+
|
|
18
|
+
function initMkFashion() {
|
|
19
|
+
mkfashion.addToCart(function(payload) {
|
|
20
|
+
console.log('Adicionando ao carrinho:', payload);
|
|
21
|
+
|
|
22
|
+
var variantSku = payload.selectedIdentifier;
|
|
42
23
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
24
|
+
fetch('/cart/add.js', {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
items: [{
|
|
31
|
+
quantity: 1,
|
|
32
|
+
id: variantSku
|
|
33
|
+
}]
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
.then(function(response) {
|
|
37
|
+
return response.json();
|
|
38
|
+
})
|
|
39
|
+
.then(function(data) {
|
|
40
|
+
console.log('Produto adicionado:', data);
|
|
41
|
+
// document.dispatchEvent(new CustomEvent('cart:updated'));
|
|
42
|
+
})
|
|
43
|
+
.catch(function(error) {
|
|
44
|
+
console.error('Erro carrinho:', error);
|
|
45
|
+
});
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
+
mkfashion.isAvailable(projectid, identifier)
|
|
49
|
+
.then(function(disponivel) {
|
|
50
|
+
if (disponivel) {
|
|
51
|
+
var button = document.getElementById('btn-provar');
|
|
48
52
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
btn.style.display = 'inline-block';
|
|
53
|
+
if (button) {
|
|
54
|
+
button.style.display = 'inline-block';
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
button.onclick = function() {
|
|
57
|
+
mkfashion.open({
|
|
58
|
+
projectid: projectid,
|
|
59
|
+
identifier: identifier
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
.catch(function(error) {
|
|
66
|
+
console.error('Erro disponibilidade MK Fashion:', error);
|
|
57
67
|
});
|
|
58
|
-
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function waitForMkFashion() {
|
|
71
|
+
if (typeof mkfashion !== 'undefined') {
|
|
72
|
+
initMkFashion();
|
|
73
|
+
} else {
|
|
74
|
+
setTimeout(waitForMkFashion, 100);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (document.readyState === "loading") {
|
|
79
|
+
document.addEventListener("DOMContentLoaded", waitForMkFashion);
|
|
59
80
|
} else {
|
|
60
|
-
|
|
81
|
+
waitForMkFashion();
|
|
61
82
|
}
|
|
62
|
-
});
|
|
83
|
+
})();
|
|
63
84
|
</script>
|
|
64
85
|
|
|
65
86
|
</body>
|
|
66
|
-
|
|
67
87
|
</html>
|
package/package.json
CHANGED
package/src/mkfashion.js
CHANGED
|
@@ -1,36 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* SDK para integrar o provador virtual mKFashion em qualquer site.
|
|
4
|
-
* Fornece métodos para abrir o provador virtual, verificar disponibilidade
|
|
5
|
-
* de produtos e gerenciar interações com o carrinho.
|
|
6
|
-
*
|
|
2
|
+
* mKFashion SDK - Integração de Provador Virtual
|
|
7
3
|
* @version 1.0.0
|
|
8
4
|
* @author metaKosmos
|
|
9
5
|
*
|
|
10
6
|
* @example
|
|
11
|
-
* // Instalação via unpkg
|
|
12
7
|
* <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script>
|
|
13
8
|
*
|
|
14
|
-
*
|
|
15
|
-
* // Uso básico - Abrir provador virtual
|
|
16
|
-
* mkfashion.open({
|
|
17
|
-
* projectId: 'gregory', // aliases: projectid, store
|
|
18
|
-
* identifier: '308088' // alias: sku
|
|
19
|
-
* });
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* // Verificar disponibilidade antes de mostrar botão
|
|
23
|
-
* const disponivel = await mkfashion.isAvailable('gregory', '165230');
|
|
24
|
-
* if (disponivel) {
|
|
25
|
-
* // Mostrar botão de prova virtual
|
|
26
|
-
* }
|
|
9
|
+
* mkfashion.open({ projectId: 'gregory', identifier: '308088' });
|
|
27
10
|
*
|
|
28
|
-
* @example
|
|
29
|
-
* // Tratar adicionar ao carrinho
|
|
30
11
|
* mkfashion.addToCart((payload) => {
|
|
31
|
-
* console.log(
|
|
32
|
-
* console.log('Tamanho:', payload.size);
|
|
33
|
-
* // Adicionar ao seu carrinho e-commerce
|
|
12
|
+
* console.log(payload.name, payload.selectedSize, payload.selectedIdentifier);
|
|
34
13
|
* });
|
|
35
14
|
*/
|
|
36
15
|
|
|
@@ -38,81 +17,25 @@ const mkfashion = {
|
|
|
38
17
|
|
|
39
18
|
// ============ CONFIGURACAO ============
|
|
40
19
|
|
|
41
|
-
/**
|
|
42
|
-
* URL base da aplicação visualizador
|
|
43
|
-
* @type {string}
|
|
44
|
-
* @default 'https://mkfashion.mk3dlabs.com/visualizer'
|
|
45
|
-
*/
|
|
46
20
|
appUrl: 'https://mkfashion.mk3dlabs.com/visualizer',
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* URL base da API mKFashion
|
|
50
|
-
* @type {string}
|
|
51
|
-
* @default 'https://mkfashion-new-api.mk3dlabs.com'
|
|
52
|
-
*/
|
|
53
21
|
apiUrl: 'https://mkfashion-new-api.mk3dlabs.com',
|
|
22
|
+
debug: false,
|
|
54
23
|
|
|
55
24
|
// DEV - Descomentar para desenvolvimento local
|
|
56
25
|
// appUrl: 'http://localhost:5174',
|
|
57
26
|
// apiUrl: 'http://localhost:3007',
|
|
58
27
|
|
|
59
|
-
/**
|
|
60
|
-
* Habilita logs de debug no console
|
|
61
|
-
* @type {boolean}
|
|
62
|
-
* @default false
|
|
63
|
-
*/
|
|
64
|
-
debug: false,
|
|
65
|
-
|
|
66
28
|
// ============ ESTADO INTERNO ============
|
|
67
29
|
|
|
68
|
-
/**
|
|
69
|
-
* Elemento iframe do visualizador
|
|
70
|
-
* @private
|
|
71
|
-
* @type {?HTMLIFrameElement}
|
|
72
|
-
*/
|
|
73
30
|
_iframe: null,
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Elemento div do modal overlay
|
|
77
|
-
* @private
|
|
78
|
-
* @type {?HTMLDivElement}
|
|
79
|
-
*/
|
|
80
31
|
_modal: null,
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Indica se o modal está aberto
|
|
84
|
-
* @private
|
|
85
|
-
* @type {boolean}
|
|
86
|
-
*/
|
|
87
32
|
_isOpen: false,
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Configuração atual da sessão
|
|
91
|
-
* @private
|
|
92
|
-
* @type {?{projectId: string, identifier: string, width: number|string, height: number|string}}
|
|
93
|
-
*/
|
|
94
33
|
_config: null,
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Cache dos dados do último callback add_to_cart
|
|
98
|
-
* Usado por getProduct() para evitar chamadas API desnecessárias
|
|
99
|
-
* @private
|
|
100
|
-
* @type {?Object}
|
|
101
|
-
*/
|
|
102
34
|
_lastCartData: null,
|
|
35
|
+
_lastCartProductData: null, // cache completo do produto (para getProduct)
|
|
36
|
+
_escHandler: null,
|
|
37
|
+
_messageHandler: null,
|
|
103
38
|
|
|
104
|
-
/**
|
|
105
|
-
* Callbacks de eventos registrados
|
|
106
|
-
* @private
|
|
107
|
-
* @type {{
|
|
108
|
-
* onReady: ?Function,
|
|
109
|
-
* onClose: ?Function,
|
|
110
|
-
* onAddToCart: ?Function,
|
|
111
|
-
* onGenerationComplete: ?Function,
|
|
112
|
-
* onProductLoaded: ?Function,
|
|
113
|
-
* onError: ?Function
|
|
114
|
-
* }}
|
|
115
|
-
*/
|
|
116
39
|
_callbacks: {
|
|
117
40
|
onReady: null,
|
|
118
41
|
onClose: null,
|
|
@@ -122,51 +45,17 @@ const mkfashion = {
|
|
|
122
45
|
onError: null
|
|
123
46
|
},
|
|
124
47
|
|
|
125
|
-
/**
|
|
126
|
-
* Handler de evento ESC para fechar modal
|
|
127
|
-
* @private
|
|
128
|
-
* @type {?Function}
|
|
129
|
-
*/
|
|
130
|
-
_escHandler: null,
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Handler de evento postMessage para comunicação com iframe
|
|
134
|
-
* @private
|
|
135
|
-
* @type {?Function}
|
|
136
|
-
*/
|
|
137
|
-
_messageHandler: null,
|
|
138
|
-
|
|
139
48
|
// ============ METODOS PUBLICOS ============
|
|
140
49
|
|
|
141
50
|
/**
|
|
142
|
-
* Abre o modal do provador virtual
|
|
51
|
+
* Abre o modal do provador virtual.
|
|
52
|
+
* Valida disponibilidade antes de abrir.
|
|
143
53
|
*
|
|
144
|
-
*
|
|
145
|
-
* disponível para prova virtual, exibe um alerta e cancela a operação.
|
|
146
|
-
*
|
|
147
|
-
* @async
|
|
148
|
-
* @param {Object} options - Opções de configuração
|
|
54
|
+
* @param {Object} options
|
|
149
55
|
* @param {string} options.projectId - ID do projeto (aliases: projectid, store)
|
|
150
56
|
* @param {string} options.identifier - Identificador do produto (alias: sku)
|
|
151
|
-
* @param {number|string} [options.width=430]
|
|
152
|
-
* @param {number|string} [options.height=800]
|
|
153
|
-
* @returns {Promise<void>} Resolve quando o modal é aberto, ou rejeita em caso de erro
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* // Abrir com alias de loja
|
|
157
|
-
* await mkfashion.open({
|
|
158
|
-
* projectId: 'gregory',
|
|
159
|
-
* identifier: '308088'
|
|
160
|
-
* });
|
|
161
|
-
*
|
|
162
|
-
* @example
|
|
163
|
-
* // Abrir com dimensões customizadas
|
|
164
|
-
* await mkfashion.open({
|
|
165
|
-
* store: 'gregory', // alias para projectId
|
|
166
|
-
* sku: '308088', // alias para identifier
|
|
167
|
-
* width: 500,
|
|
168
|
-
* height: '90vh'
|
|
169
|
-
* });
|
|
57
|
+
* @param {number|string} [options.width=430]
|
|
58
|
+
* @param {number|string} [options.height=800]
|
|
170
59
|
*/
|
|
171
60
|
async open(options = {}) {
|
|
172
61
|
if (this._isOpen) {
|
|
@@ -174,12 +63,10 @@ const mkfashion = {
|
|
|
174
63
|
return
|
|
175
64
|
}
|
|
176
65
|
|
|
177
|
-
// Normaliza opções (compatibilidade com nomes alternativos)
|
|
178
66
|
const raw = options.projectId || options.projectid || options.store
|
|
179
67
|
const projectId = this._resolveProjectId(raw)
|
|
180
68
|
const identifier = options.identifier || options.sku
|
|
181
69
|
|
|
182
|
-
// Valida opções obrigatórias
|
|
183
70
|
if (!projectId) {
|
|
184
71
|
console.error('[mKFashion] projectId e obrigatorio')
|
|
185
72
|
return
|
|
@@ -189,7 +76,6 @@ const mkfashion = {
|
|
|
189
76
|
return
|
|
190
77
|
}
|
|
191
78
|
|
|
192
|
-
// Verifica disponibilidade antes de abrir
|
|
193
79
|
try {
|
|
194
80
|
const availability = await this.getAvailability(projectId, identifier)
|
|
195
81
|
if (!availability.available) {
|
|
@@ -203,7 +89,6 @@ const mkfashion = {
|
|
|
203
89
|
return
|
|
204
90
|
}
|
|
205
91
|
|
|
206
|
-
// Salva configuração
|
|
207
92
|
this._config = {
|
|
208
93
|
projectId: projectId,
|
|
209
94
|
identifier: identifier,
|
|
@@ -218,15 +103,7 @@ const mkfashion = {
|
|
|
218
103
|
this._log('Aberto', this._config)
|
|
219
104
|
},
|
|
220
105
|
|
|
221
|
-
/**
|
|
222
|
-
* Fecha o modal do provador virtual
|
|
223
|
-
*
|
|
224
|
-
* Remove o modal do DOM e limpa os event listeners.
|
|
225
|
-
* Dispara o callback onClose se registrado.
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* mkfashion.close();
|
|
229
|
-
*/
|
|
106
|
+
/** Fecha o modal do provador virtual */
|
|
230
107
|
close() {
|
|
231
108
|
if (!this._isOpen) {
|
|
232
109
|
this._log('Ja esta fechado')
|
|
@@ -241,41 +118,12 @@ const mkfashion = {
|
|
|
241
118
|
},
|
|
242
119
|
|
|
243
120
|
/**
|
|
244
|
-
* Registra
|
|
245
|
-
*
|
|
246
|
-
* Chamado quando o usuário seleciona um tamanho e adiciona o produto ao carrinho
|
|
247
|
-
* do visualizador. O payload inclui todos os dados do produto, tamanho selecionado
|
|
248
|
-
* e múltiplos aliases de identificador para compatibilidade.
|
|
249
|
-
*
|
|
250
|
-
* @param {Function} callback - Função a ser chamada no add-to-cart
|
|
251
|
-
* @param {Object} callback.payload - Dados do carrinho
|
|
252
|
-
* @param {string} callback.payload.projectId - ID do projeto
|
|
253
|
-
* @param {string} callback.payload.identifier - Identificador do produto
|
|
254
|
-
* @param {string} [callback.payload.sku] - Alias do identifier (apenas projetos Gregory)
|
|
255
|
-
* @param {Object} callback.payload.size - Objeto do tamanho selecionado
|
|
256
|
-
* @param {string} callback.payload.size.label - Label do tamanho (ex: "M", "42")
|
|
257
|
-
* @param {number} callback.payload.size.produtoVarianteId - ID da variante para analytics
|
|
258
|
-
* @param {Object} callback.payload.product - Dados completos do produto
|
|
259
|
-
*
|
|
260
|
-
* @example
|
|
261
|
-
* mkfashion.addToCart((payload) => {
|
|
262
|
-
* const { size, product } = payload;
|
|
121
|
+
* Registra callback de adicionar ao carrinho.
|
|
263
122
|
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* productId: payload.identifier,
|
|
267
|
-
* variantId: size.produtoVarianteId,
|
|
268
|
-
* quantidade: 1
|
|
269
|
-
* });
|
|
123
|
+
* Payload simplificado (não-Gregory):
|
|
124
|
+
* { mainIdentifier, selectedIdentifier, name, price, sizePrice, selectedSize, productUrl, tryonImageUrl }
|
|
270
125
|
*
|
|
271
|
-
*
|
|
272
|
-
* gtag('event', 'add_to_cart', {
|
|
273
|
-
* items: [{
|
|
274
|
-
* item_id: payload.identifier,
|
|
275
|
-
* item_variant: size.label
|
|
276
|
-
* }]
|
|
277
|
-
* });
|
|
278
|
-
* });
|
|
126
|
+
* Projetos Gregory mantêm estrutura legada completa.
|
|
279
127
|
*/
|
|
280
128
|
addToCart(callback) {
|
|
281
129
|
if (typeof callback === 'function') {
|
|
@@ -286,17 +134,6 @@ const mkfashion = {
|
|
|
286
134
|
}
|
|
287
135
|
},
|
|
288
136
|
|
|
289
|
-
/**
|
|
290
|
-
* Registra um callback para executar quando o visualizador estiver pronto
|
|
291
|
-
*
|
|
292
|
-
* @param {Function} callback - Função a ser chamada quando pronto
|
|
293
|
-
* @param {Object} callback.data - Dados do evento ready do visualizador
|
|
294
|
-
*
|
|
295
|
-
* @example
|
|
296
|
-
* mkfashion.onReady((data) => {
|
|
297
|
-
* console.log('Visualizador pronto:', data);
|
|
298
|
-
* });
|
|
299
|
-
*/
|
|
300
137
|
onReady(callback) {
|
|
301
138
|
if (typeof callback === 'function') {
|
|
302
139
|
this._callbacks.onReady = callback
|
|
@@ -304,17 +141,6 @@ const mkfashion = {
|
|
|
304
141
|
}
|
|
305
142
|
},
|
|
306
143
|
|
|
307
|
-
/**
|
|
308
|
-
* Registra um callback para executar quando o modal fechar
|
|
309
|
-
*
|
|
310
|
-
* @param {Function} callback - Função a ser chamada ao fechar
|
|
311
|
-
*
|
|
312
|
-
* @example
|
|
313
|
-
* mkfashion.onClose(() => {
|
|
314
|
-
* console.log('Modal fechado');
|
|
315
|
-
* // Limpeza ou analytics
|
|
316
|
-
* });
|
|
317
|
-
*/
|
|
318
144
|
onClose(callback) {
|
|
319
145
|
if (typeof callback === 'function') {
|
|
320
146
|
this._callbacks.onClose = callback
|
|
@@ -322,17 +148,6 @@ const mkfashion = {
|
|
|
322
148
|
}
|
|
323
149
|
},
|
|
324
150
|
|
|
325
|
-
/**
|
|
326
|
-
* Registra um callback para executar quando a geração de imagem for concluída
|
|
327
|
-
*
|
|
328
|
-
* @param {Function} callback - Função a ser chamada quando a geração completar
|
|
329
|
-
* @param {Object} callback.data - Dados da geração concluída
|
|
330
|
-
*
|
|
331
|
-
* @example
|
|
332
|
-
* mkfashion.onGenerationComplete((data) => {
|
|
333
|
-
* console.log('Geração concluída:', data);
|
|
334
|
-
* });
|
|
335
|
-
*/
|
|
336
151
|
onGenerationComplete(callback) {
|
|
337
152
|
if (typeof callback === 'function') {
|
|
338
153
|
this._callbacks.onGenerationComplete = callback
|
|
@@ -340,17 +155,6 @@ const mkfashion = {
|
|
|
340
155
|
}
|
|
341
156
|
},
|
|
342
157
|
|
|
343
|
-
/**
|
|
344
|
-
* Registra um callback para tratar erros do visualizador
|
|
345
|
-
*
|
|
346
|
-
* @param {Function} callback - Função a ser chamada em caso de erro
|
|
347
|
-
* @param {Object} callback.data - Dados do erro
|
|
348
|
-
*
|
|
349
|
-
* @example
|
|
350
|
-
* mkfashion.onError((data) => {
|
|
351
|
-
* console.error('Erro no visualizador:', data);
|
|
352
|
-
* });
|
|
353
|
-
*/
|
|
354
158
|
onError(callback) {
|
|
355
159
|
if (typeof callback === 'function') {
|
|
356
160
|
this._callbacks.onError = callback
|
|
@@ -358,17 +162,6 @@ const mkfashion = {
|
|
|
358
162
|
}
|
|
359
163
|
},
|
|
360
164
|
|
|
361
|
-
/**
|
|
362
|
-
* Registra um callback para executar quando o produto for carregado
|
|
363
|
-
*
|
|
364
|
-
* @param {Function} callback - Função a ser chamada quando produto carregar
|
|
365
|
-
* @param {Object} callback.data - Dados do produto carregado
|
|
366
|
-
*
|
|
367
|
-
* @example
|
|
368
|
-
* mkfashion.onProductLoaded((data) => {
|
|
369
|
-
* console.log('Produto carregado:', data);
|
|
370
|
-
* });
|
|
371
|
-
*/
|
|
372
165
|
onProductLoaded(callback) {
|
|
373
166
|
if (typeof callback === 'function') {
|
|
374
167
|
this._callbacks.onProductLoaded = callback
|
|
@@ -376,14 +169,7 @@ const mkfashion = {
|
|
|
376
169
|
}
|
|
377
170
|
},
|
|
378
171
|
|
|
379
|
-
/**
|
|
380
|
-
* Reinicia a experiência do provador virtual
|
|
381
|
-
*
|
|
382
|
-
* Recarrega o iframe com a mesma configuração, reiniciando a sessão.
|
|
383
|
-
*
|
|
384
|
-
* @example
|
|
385
|
-
* mkfashion.restart();
|
|
386
|
-
*/
|
|
172
|
+
/** Recarrega o iframe com a mesma configuração */
|
|
387
173
|
restart() {
|
|
388
174
|
if (!this._iframe || !this._config) {
|
|
389
175
|
this._log('Nenhum iframe ativo')
|
|
@@ -394,21 +180,14 @@ const mkfashion = {
|
|
|
394
180
|
this._log('Reiniciado')
|
|
395
181
|
},
|
|
396
182
|
|
|
397
|
-
/**
|
|
398
|
-
* Destrói completamente a instância do SDK
|
|
399
|
-
*
|
|
400
|
-
* Fecha o modal, remove todos os event listeners, limpa cache e reseta callbacks.
|
|
401
|
-
* Use quando não for mais utilizar o SDK na página.
|
|
402
|
-
*
|
|
403
|
-
* @example
|
|
404
|
-
* mkfashion.destroy();
|
|
405
|
-
*/
|
|
183
|
+
/** Fecha modal, remove listeners, limpa cache e reseta callbacks */
|
|
406
184
|
destroy() {
|
|
407
185
|
this.close()
|
|
408
186
|
this._iframe = null
|
|
409
187
|
this._modal = null
|
|
410
188
|
this._config = null
|
|
411
189
|
this._lastCartData = null
|
|
190
|
+
this._lastCartProductData = null
|
|
412
191
|
this._callbacks = {
|
|
413
192
|
onReady: null,
|
|
414
193
|
onClose: null,
|
|
@@ -420,16 +199,6 @@ const mkfashion = {
|
|
|
420
199
|
this._log('Destruído')
|
|
421
200
|
},
|
|
422
201
|
|
|
423
|
-
/**
|
|
424
|
-
* Retorna o estado atual do SDK
|
|
425
|
-
*
|
|
426
|
-
* @returns {{isOpen: boolean, config: ?Object}} Estado atual com isOpen e config
|
|
427
|
-
*
|
|
428
|
-
* @example
|
|
429
|
-
* const status = mkfashion.getStatus();
|
|
430
|
-
* console.log('Está aberto?', status.isOpen);
|
|
431
|
-
* console.log('Configuração:', status.config);
|
|
432
|
-
*/
|
|
433
202
|
getStatus() {
|
|
434
203
|
return {
|
|
435
204
|
isOpen: this._isOpen,
|
|
@@ -438,29 +207,10 @@ const mkfashion = {
|
|
|
438
207
|
},
|
|
439
208
|
|
|
440
209
|
/**
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
* Retorna apenas true/false ao invés dos dados completos.
|
|
444
|
-
* Se apenas um parâmetro for passado, assume que é o identifier e usa projeto padrão.
|
|
445
|
-
*
|
|
446
|
-
* @async
|
|
447
|
-
* @param {string} projectId - ID do projeto (ex: 'gregory') ou identifier se único parâmetro
|
|
448
|
-
* @param {string} [identifier] - Identificador do produto
|
|
449
|
-
* @returns {Promise<boolean>} true se disponível, false caso contrário
|
|
450
|
-
*
|
|
451
|
-
* @example
|
|
452
|
-
* // Com projectId e identifier
|
|
453
|
-
* const disponivel = await mkfashion.isAvailable('gregory', '308088');
|
|
454
|
-
* if (disponivel) {
|
|
455
|
-
* // Mostrar botão
|
|
456
|
-
* }
|
|
457
|
-
*
|
|
458
|
-
* @example
|
|
459
|
-
* // Apenas identifier (usa projeto padrão)
|
|
460
|
-
* const disponivel = await mkfashion.isAvailable('308088');
|
|
210
|
+
* Retorna true/false se produto está disponível para try-on.
|
|
211
|
+
* Se apenas 1 parâmetro, assume que é o identifier (usa projeto padrão).
|
|
461
212
|
*/
|
|
462
213
|
async isAvailable(projectId, identifier) {
|
|
463
|
-
// Se apenas 1 parâmetro, assume que é o identifier
|
|
464
214
|
if (!identifier) {
|
|
465
215
|
identifier = projectId
|
|
466
216
|
projectId = '698c7e791d3129430f15dddd'
|
|
@@ -473,29 +223,7 @@ const mkfashion = {
|
|
|
473
223
|
}
|
|
474
224
|
},
|
|
475
225
|
|
|
476
|
-
/**
|
|
477
|
-
* Verifica disponibilidade do produto via API (retorna dados completos)
|
|
478
|
-
*
|
|
479
|
-
* @async
|
|
480
|
-
* @param {string} projectId - ID do projeto (ex: 'gregory' ou UUID)
|
|
481
|
-
* @param {string} identifier - Identificador do produto
|
|
482
|
-
* @returns {Promise<Object>} Dados de disponibilidade da API com:
|
|
483
|
-
* - available: boolean - Se produto está disponível
|
|
484
|
-
* - message: string - Mensagem descritiva
|
|
485
|
-
* - (outros campos conforme API)
|
|
486
|
-
* @throws {Error} Se projectId ou identifier estiver faltando
|
|
487
|
-
* @throws {Error} Se a requisição da API falhar
|
|
488
|
-
*
|
|
489
|
-
* @example
|
|
490
|
-
* try {
|
|
491
|
-
* const dados = await mkfashion.getAvailability('gregory', '308088');
|
|
492
|
-
* if (dados.available) {
|
|
493
|
-
* console.log('Disponível!', dados.message);
|
|
494
|
-
* }
|
|
495
|
-
* } catch (erro) {
|
|
496
|
-
* console.error('Erro ao verificar:', erro);
|
|
497
|
-
* }
|
|
498
|
-
*/
|
|
226
|
+
/** Verifica disponibilidade via API (retorna dados completos) */
|
|
499
227
|
async getAvailability(projectId, identifier) {
|
|
500
228
|
if (!projectId) {
|
|
501
229
|
return Promise.reject(new Error('projectId e obrigatorio'))
|
|
@@ -526,17 +254,6 @@ const mkfashion = {
|
|
|
526
254
|
}
|
|
527
255
|
},
|
|
528
256
|
|
|
529
|
-
/**
|
|
530
|
-
* Lista todos os produtos disponíveis para try-on
|
|
531
|
-
*
|
|
532
|
-
* @async
|
|
533
|
-
* @returns {Promise<Array>} Lista de produtos disponíveis
|
|
534
|
-
* @throws {Error} Se a requisição da API falhar
|
|
535
|
-
*
|
|
536
|
-
* @example
|
|
537
|
-
* const produtos = await mkfashion.getAvailableProducts();
|
|
538
|
-
* console.log(`${produtos.length} produtos disponíveis`);
|
|
539
|
-
*/
|
|
540
257
|
async getAvailableProducts() {
|
|
541
258
|
this._log('Buscando produtos disponíveis')
|
|
542
259
|
|
|
@@ -558,19 +275,6 @@ const mkfashion = {
|
|
|
558
275
|
}
|
|
559
276
|
},
|
|
560
277
|
|
|
561
|
-
/**
|
|
562
|
-
* Busca feedbacks enviados pelos usuários (para testes e analytics)
|
|
563
|
-
*
|
|
564
|
-
* @async
|
|
565
|
-
* @param {number} [page=1] - Página a buscar
|
|
566
|
-
* @param {number} [limit=20] - Itens por página
|
|
567
|
-
* @returns {Promise<Object>} Lista paginada de feedbacks
|
|
568
|
-
* @throws {Error} Se a requisição da API falhar
|
|
569
|
-
*
|
|
570
|
-
* @example
|
|
571
|
-
* const feedbacks = await mkfashion.getFeedback(1, 10);
|
|
572
|
-
* console.log('Feedbacks:', feedbacks);
|
|
573
|
-
*/
|
|
574
278
|
async getFeedback(page = 1, limit = 20) {
|
|
575
279
|
this._log('Buscando feedbacks', { page, limit })
|
|
576
280
|
|
|
@@ -592,33 +296,8 @@ const mkfashion = {
|
|
|
592
296
|
},
|
|
593
297
|
|
|
594
298
|
/**
|
|
595
|
-
* Busca dados
|
|
596
|
-
*
|
|
597
|
-
* Este método implementa cache inteligente e lógica de fallback:
|
|
598
|
-
* 1. Retorna dados cacheados se disponíveis do callback add_to_cart anterior
|
|
599
|
-
* 2. Faz chamada API para /products/{projectId}/{identifier}
|
|
600
|
-
* 3. Se retornar 404 e identifier parecer uma variante, tenta novamente com productId do config
|
|
601
|
-
*
|
|
602
|
-
* @async
|
|
603
|
-
* @param {string} projectId - ID do projeto (ex: 'gregory' ou UUID)
|
|
604
|
-
* @param {string} identifier - Identificador do produto (pode ser productId ou variantSku)
|
|
605
|
-
* @returns {Promise<Object>} Dados do produto com estrutura:
|
|
606
|
-
* - success: boolean
|
|
607
|
-
* - data: Objeto do produto (compatibilidade com bundle Gregory)
|
|
608
|
-
* - product: Objeto do produto (compatibilidade com código legado)
|
|
609
|
-
* @throws {Error} Se projectId ou identifier estiver faltando
|
|
610
|
-
* @throws {Error} Se a requisição da API falhar
|
|
611
|
-
*
|
|
612
|
-
* @example
|
|
613
|
-
* // Buscar dados do produto
|
|
614
|
-
* const resultado = await mkfashion.getProduct('gregory', '308088');
|
|
615
|
-
* console.log(resultado.data.sizes); // Para bundle Gregory
|
|
616
|
-
* console.log(resultado.product.price); // Para código legado
|
|
617
|
-
*
|
|
618
|
-
* @example
|
|
619
|
-
* // Funciona com SKU de variante (usa fallback)
|
|
620
|
-
* const resultado = await mkfashion.getProduct('gregory', '302509');
|
|
621
|
-
* // Se 302509 for uma variante, tenta novamente com productId principal
|
|
299
|
+
* Busca dados do produto via API.
|
|
300
|
+
* Usa cache do add_to_cart se disponível. Fallback automático se identifier for variantSku.
|
|
622
301
|
*/
|
|
623
302
|
async getProduct(projectId, identifier) {
|
|
624
303
|
if (!projectId) {
|
|
@@ -628,12 +307,10 @@ const mkfashion = {
|
|
|
628
307
|
return Promise.reject(new Error('identifier e obrigatorio'))
|
|
629
308
|
}
|
|
630
309
|
|
|
631
|
-
//
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
const cached = this._lastCartData
|
|
310
|
+
// Retorna do cache se disponível (evita chamada API após add_to_cart)
|
|
311
|
+
if (this._lastCartProductData?.product) {
|
|
312
|
+
const cached = this._lastCartProductData
|
|
635
313
|
const product = cached.product
|
|
636
|
-
// Verifica se o identifier bate com algum campo do produto cacheado
|
|
637
314
|
const isMatch = identifier === cached.identifier ||
|
|
638
315
|
identifier === product.identifier ||
|
|
639
316
|
identifier === product.variantSku ||
|
|
@@ -641,8 +318,6 @@ const mkfashion = {
|
|
|
641
318
|
String(identifier) === String(product.produtoVarianteId)
|
|
642
319
|
if (isMatch) {
|
|
643
320
|
this._log('Produto retornado do cache (add_to_cart)', { identifier })
|
|
644
|
-
// Retorna com ambas as chaves (data + product) para compatibilidade
|
|
645
|
-
// Bundle Gregory usa t.data.produtoVarianteId
|
|
646
321
|
return { success: true, data: product, product: product }
|
|
647
322
|
}
|
|
648
323
|
}
|
|
@@ -655,8 +330,7 @@ const mkfashion = {
|
|
|
655
330
|
const response = await fetch(url)
|
|
656
331
|
|
|
657
332
|
if (!response.ok) {
|
|
658
|
-
// Fallback:
|
|
659
|
-
// tenta com ele (caller pode ter passado variantSku ao invés de productId)
|
|
333
|
+
// Fallback: tenta com productId do config caso caller tenha passado variantSku
|
|
660
334
|
if (response.status === 404 && this._config?.identifier && this._config.identifier !== identifier) {
|
|
661
335
|
this._log(`Identifier ${identifier} não encontrado, tentando com productId: ${this._config.identifier}`)
|
|
662
336
|
const fallbackUrl = `${this.apiUrl}/products/${resolved}/${this._config.identifier}`
|
|
@@ -683,12 +357,6 @@ const mkfashion = {
|
|
|
683
357
|
|
|
684
358
|
// ============ METODOS PRIVADOS ============
|
|
685
359
|
|
|
686
|
-
/**
|
|
687
|
-
* Registra mensagens de debug se o modo debug estiver habilitado
|
|
688
|
-
* @private
|
|
689
|
-
* @param {string} message - Mensagem para registrar
|
|
690
|
-
* @param {*} [data] - Dados opcionais para registrar
|
|
691
|
-
*/
|
|
692
360
|
_log(message, data = null) {
|
|
693
361
|
if (this.debug) {
|
|
694
362
|
if (data) {
|
|
@@ -699,45 +367,21 @@ const mkfashion = {
|
|
|
699
367
|
}
|
|
700
368
|
},
|
|
701
369
|
|
|
702
|
-
/**
|
|
703
|
-
* Mapeamento de aliases de ID de projeto
|
|
704
|
-
* Mapeia nomes amigáveis de loja para UUIDs internos de projeto
|
|
705
|
-
* @private
|
|
706
|
-
* @type {Object.<string, string>}
|
|
707
|
-
*/
|
|
708
370
|
_storeAliases: {
|
|
709
371
|
'gregory': '698c7e791d3129430f15dddd'
|
|
710
372
|
},
|
|
711
373
|
|
|
712
|
-
/**
|
|
713
|
-
* Resolve ID de projeto a partir de alias ou UUID
|
|
714
|
-
* @private
|
|
715
|
-
* @param {string} projectId - ID do projeto ou alias (ex: 'gregory')
|
|
716
|
-
* @returns {string} UUID do projeto resolvido
|
|
717
|
-
*/
|
|
718
374
|
_resolveProjectId(projectId) {
|
|
719
375
|
if (!projectId) return '698c7e791d3129430f15dddd'
|
|
720
376
|
const key = String(projectId).toLowerCase()
|
|
721
377
|
return this._storeAliases[key] || projectId
|
|
722
378
|
},
|
|
723
379
|
|
|
724
|
-
/**
|
|
725
|
-
* Verifica se o projeto é Gregory (requer aliases legados)
|
|
726
|
-
* @private
|
|
727
|
-
* @param {string} projectId - UUID do projeto já resolvido
|
|
728
|
-
* @returns {boolean}
|
|
729
|
-
*/
|
|
730
380
|
_isGregoryProject(projectId) {
|
|
731
381
|
return projectId === '698c7e791d3129430f15dddd' ||
|
|
732
382
|
String(projectId).toLowerCase() === 'gregory'
|
|
733
383
|
},
|
|
734
384
|
|
|
735
|
-
/**
|
|
736
|
-
* Dispara um callback registrado se ele existir
|
|
737
|
-
* @private
|
|
738
|
-
* @param {string} name - Nome do callback (ex: 'onReady')
|
|
739
|
-
* @param {*} [data] - Dados para passar ao callback
|
|
740
|
-
*/
|
|
741
385
|
_triggerCallback(name, data = null) {
|
|
742
386
|
if (this._callbacks && typeof this._callbacks[name] === 'function') {
|
|
743
387
|
try {
|
|
@@ -749,20 +393,10 @@ const mkfashion = {
|
|
|
749
393
|
}
|
|
750
394
|
},
|
|
751
395
|
|
|
752
|
-
/**
|
|
753
|
-
* Constrói a URL do iframe para o visualizador
|
|
754
|
-
* @private
|
|
755
|
-
* @returns {string} URL completa com projectId e identifier
|
|
756
|
-
*/
|
|
757
396
|
_buildUrl() {
|
|
758
397
|
return `${this.appUrl}/${this._config.projectId}/${this._config.identifier}`
|
|
759
398
|
},
|
|
760
399
|
|
|
761
|
-
/**
|
|
762
|
-
* Cria e exibe o overlay modal com iframe
|
|
763
|
-
* Gerencia estado de loading, animações e event listeners
|
|
764
|
-
* @private
|
|
765
|
-
*/
|
|
766
400
|
_openModal() {
|
|
767
401
|
this._modal = document.createElement('div')
|
|
768
402
|
this._modal.style.cssText = `
|
|
@@ -781,7 +415,6 @@ const mkfashion = {
|
|
|
781
415
|
transition: opacity 0.3s ease;
|
|
782
416
|
`
|
|
783
417
|
|
|
784
|
-
// Container para loading + iframe
|
|
785
418
|
const container = document.createElement('div')
|
|
786
419
|
const { width, height } = this._config
|
|
787
420
|
container.style.cssText = `
|
|
@@ -798,7 +431,6 @@ const mkfashion = {
|
|
|
798
431
|
transition: transform 0.3s ease;
|
|
799
432
|
`
|
|
800
433
|
|
|
801
|
-
// Loading indicator (mostra imediatamente)
|
|
802
434
|
const loader = document.createElement('div')
|
|
803
435
|
loader.className = 'mkfashion-loader'
|
|
804
436
|
loader.innerHTML = `
|
|
@@ -840,7 +472,6 @@ const mkfashion = {
|
|
|
840
472
|
`
|
|
841
473
|
container.appendChild(loader)
|
|
842
474
|
|
|
843
|
-
// Iframe (carrega em background)
|
|
844
475
|
this._iframe = this._createIframe()
|
|
845
476
|
this._iframe.style.cssText = `
|
|
846
477
|
position: absolute;
|
|
@@ -853,7 +484,6 @@ const mkfashion = {
|
|
|
853
484
|
transition: opacity 0.3s ease;
|
|
854
485
|
`
|
|
855
486
|
|
|
856
|
-
// Quando iframe carregar, esconde o loading
|
|
857
487
|
this._iframe.onload = () => {
|
|
858
488
|
loader.style.opacity = '0'
|
|
859
489
|
this._iframe.style.opacity = '1'
|
|
@@ -864,7 +494,6 @@ const mkfashion = {
|
|
|
864
494
|
this._modal.appendChild(container)
|
|
865
495
|
document.body.appendChild(this._modal)
|
|
866
496
|
|
|
867
|
-
// Guarda referencia do container
|
|
868
497
|
this._container = container
|
|
869
498
|
|
|
870
499
|
requestAnimationFrame(() => {
|
|
@@ -886,11 +515,6 @@ const mkfashion = {
|
|
|
886
515
|
document.addEventListener('keydown', this._escHandler)
|
|
887
516
|
},
|
|
888
517
|
|
|
889
|
-
/**
|
|
890
|
-
* Fecha e remove o modal do DOM
|
|
891
|
-
* Inclui animação de fade-out
|
|
892
|
-
* @private
|
|
893
|
-
*/
|
|
894
518
|
_closeModal() {
|
|
895
519
|
if (!this._modal) return
|
|
896
520
|
|
|
@@ -910,11 +534,6 @@ const mkfashion = {
|
|
|
910
534
|
}
|
|
911
535
|
},
|
|
912
536
|
|
|
913
|
-
/**
|
|
914
|
-
* Cria o elemento iframe configurado
|
|
915
|
-
* @private
|
|
916
|
-
* @returns {HTMLIFrameElement} Elemento iframe configurado
|
|
917
|
-
*/
|
|
918
537
|
_createIframe() {
|
|
919
538
|
const { width, height } = this._config
|
|
920
539
|
const iframe = document.createElement('iframe')
|
|
@@ -927,11 +546,6 @@ const mkfashion = {
|
|
|
927
546
|
return iframe
|
|
928
547
|
},
|
|
929
548
|
|
|
930
|
-
/**
|
|
931
|
-
* Configura listener postMessage para comunicação com iframe
|
|
932
|
-
* Trata eventos: close_request, ready, add_to_cart, generation_complete, etc.
|
|
933
|
-
* @private
|
|
934
|
-
*/
|
|
935
549
|
_setupMessageListener() {
|
|
936
550
|
this._messageHandler = (event) => {
|
|
937
551
|
if (!event.data || event.data.source !== 'mkfashion-app') {
|
|
@@ -963,40 +577,57 @@ const mkfashion = {
|
|
|
963
577
|
case 'add_to_cart':
|
|
964
578
|
this._log('Adicionar ao carrinho', data)
|
|
965
579
|
|
|
966
|
-
// Prioriza valores do frontend (data), usa _config como fallback
|
|
967
580
|
const identifierValue = data.identifier || this._config.identifier
|
|
968
581
|
const projectIdValue = data.projectId || this._config.projectId
|
|
969
582
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
product: data?.product || null
|
|
974
|
-
// Prioriza data (frontend), usa _config como fallback
|
|
975
|
-
projectId: projectIdValue,
|
|
976
|
-
identifier: identifierValue
|
|
583
|
+
// Cache interno completo (para getProduct)
|
|
584
|
+
this._lastCartProductData = {
|
|
585
|
+
identifier: identifierValue,
|
|
586
|
+
product: data?.product || null
|
|
977
587
|
}
|
|
978
588
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
589
|
+
let callbackPayload
|
|
590
|
+
|
|
591
|
+
if (this._isGregoryProject(projectIdValue)) {
|
|
592
|
+
// Fluxo Gregory - payload legado completo
|
|
593
|
+
callbackPayload = {
|
|
594
|
+
...data,
|
|
595
|
+
size: data?.size || null,
|
|
596
|
+
product: data?.product || null,
|
|
597
|
+
projectId: projectIdValue,
|
|
598
|
+
identifier: identifierValue
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (callbackPayload.product) {
|
|
602
|
+
callbackPayload.sku = identifierValue
|
|
603
|
+
|
|
604
|
+
const p = callbackPayload.product
|
|
605
|
+
p.productID = identifierValue
|
|
606
|
+
p.Identifier = identifierValue
|
|
607
|
+
p.nome = p.name
|
|
608
|
+
p.cor = p.color
|
|
609
|
+
p.preco = { de: p.compareAtPrice, por: p.price }
|
|
610
|
+
p.sizeSku = p.variantSku || p.produtoVarianteId || identifierValue
|
|
611
|
+
p.productVariantId = p.produtoVarianteId || p.variantSku
|
|
612
|
+
p.imagem = p.originalImageUrl
|
|
613
|
+
p.url = p.productUrl
|
|
614
|
+
}
|
|
615
|
+
} else {
|
|
616
|
+
// Fluxo simplificado
|
|
617
|
+
const product = data?.product || {}
|
|
618
|
+
callbackPayload = {
|
|
619
|
+
mainIdentifier: identifierValue,
|
|
620
|
+
selectedIdentifier: product.variantSku || null,
|
|
621
|
+
name: product.name || null,
|
|
622
|
+
price: product.price || null,
|
|
623
|
+
sizePrice: product.sizePrice || null,
|
|
624
|
+
selectedSize: data?.size || null,
|
|
625
|
+
productUrl: product.productUrl || null,
|
|
626
|
+
tryonImageUrl: product.tryonImageUrl || null
|
|
627
|
+
}
|
|
995
628
|
}
|
|
996
629
|
|
|
997
|
-
// Cache dos dados para getProduct (evita chamada API desnecessária)
|
|
998
630
|
this._lastCartData = callbackPayload
|
|
999
|
-
|
|
1000
631
|
this._triggerCallback('onAddToCart', callbackPayload)
|
|
1001
632
|
break
|
|
1002
633
|
|
|
@@ -1019,10 +650,6 @@ const mkfashion = {
|
|
|
1019
650
|
this._log('Listener de mensagens ativado')
|
|
1020
651
|
},
|
|
1021
652
|
|
|
1022
|
-
/**
|
|
1023
|
-
* Remove listener postMessage
|
|
1024
|
-
* @private
|
|
1025
|
-
*/
|
|
1026
653
|
_removeMessageListener() {
|
|
1027
654
|
if (this._messageHandler) {
|
|
1028
655
|
window.removeEventListener('message', this._messageHandler)
|
|
@@ -1032,7 +659,6 @@ const mkfashion = {
|
|
|
1032
659
|
}
|
|
1033
660
|
}
|
|
1034
661
|
|
|
1035
|
-
// Disponibiliza globalmente
|
|
1036
662
|
if (typeof window !== 'undefined') {
|
|
1037
663
|
window.mkfashion = mkfashion
|
|
1038
664
|
}
|