661 lines
24 KiB
JavaScript
661 lines
24 KiB
JavaScript
/**
|
|
* PMPro Dynamic Pricing - Frontend JavaScript Optimizado v2.1
|
|
* Estructura de snippet con optimizaciones de rendimiento
|
|
*
|
|
* @version 2.1.0
|
|
*/
|
|
|
|
jQuery(document).ready(function($) {
|
|
'use strict';
|
|
|
|
// ====================================================================
|
|
// CONFIGURACIÓN Y VARIABLES GLOBALES
|
|
// ====================================================================
|
|
|
|
var PLUGIN_VERSION = '2.1.0';
|
|
var DEBUG_MODE = typeof console !== 'undefined' && (typeof nextcloud_pricing !== 'undefined' && nextcloud_pricing.debug);
|
|
var CACHE_EXPIRY = 60000; // 1 minuto
|
|
var TOOLTIP_DELAY = 300;
|
|
|
|
// Cache simple para optimización
|
|
var priceCache = {};
|
|
var originalTextsCache = {};
|
|
var activeTooltip = null;
|
|
var showTooltipTimer = null;
|
|
var hideTooltipTimer = null;
|
|
|
|
// ====================================================================
|
|
// SISTEMA DE LOGGING
|
|
// ====================================================================
|
|
|
|
function log(level, message, data) {
|
|
if (!DEBUG_MODE) return;
|
|
|
|
var prefix = '[PMPro Dynamic ' + level + ']';
|
|
if (data && typeof data === 'object') {
|
|
console.log(prefix, message, data);
|
|
} else {
|
|
console.log(prefix, message);
|
|
}
|
|
}
|
|
|
|
function logError(message, data) { log('ERROR', message, data); }
|
|
function logWarn(message, data) { log('WARN', message, data); }
|
|
function logInfo(message, data) { log('INFO', message, data); }
|
|
function logDebug(message, data) { log('DEBUG', message, data); }
|
|
|
|
// ====================================================================
|
|
// VALIDACIÓN DE DEPENDENCIAS
|
|
// ====================================================================
|
|
|
|
function validateDependencies() {
|
|
var checks = {
|
|
nextcloud_pricing: typeof nextcloud_pricing !== 'undefined',
|
|
jquery: typeof $ !== 'undefined',
|
|
required_elements: $('#storage_space, #office_suite, #payment_frequency').length >= 3
|
|
};
|
|
|
|
var missing = [];
|
|
for (var check in checks) {
|
|
if (!checks[check]) {
|
|
missing.push(check);
|
|
}
|
|
}
|
|
|
|
if (missing.length > 0) {
|
|
logError('Missing dependencies', { missing: missing });
|
|
return false;
|
|
}
|
|
|
|
logInfo('Dependencies validated successfully');
|
|
return true;
|
|
}
|
|
|
|
// ====================================================================
|
|
// CONFIGURACIÓN DINÁMICA
|
|
// ====================================================================
|
|
|
|
function getConfig() {
|
|
if (typeof nextcloud_pricing === 'undefined') {
|
|
logError('nextcloud_pricing configuration not available');
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
levelId: nextcloud_pricing.level_id || 1,
|
|
basePrice: parseInt(nextcloud_pricing.base_price) || 0,
|
|
currencySymbol: nextcloud_pricing.currency_symbol || 'R$',
|
|
currentStorage: nextcloud_pricing.current_storage || '1tb',
|
|
currentSuite: nextcloud_pricing.current_suite || '20users',
|
|
usedSpaceTb: parseFloat(nextcloud_pricing.used_space_tb) || 0,
|
|
pricePerTb: 120,
|
|
officeUserPrice: 25,
|
|
frequencyMultipliers: {
|
|
'monthly': 1.0,
|
|
'semiannual': 5.7,
|
|
'annual': 10.8,
|
|
'biennial': 20.4,
|
|
'triennial': 28.8,
|
|
'quadrennial': 36.0,
|
|
'quinquennial': 42.0
|
|
}
|
|
};
|
|
}
|
|
|
|
// ====================================================================
|
|
// SISTEMA DE CACHÉ
|
|
// ====================================================================
|
|
|
|
function getCachedPrice(key) {
|
|
var cached = priceCache[key];
|
|
if (cached && (Date.now() - cached.timestamp) < CACHE_EXPIRY) {
|
|
logDebug('Cache hit for price', { key: key });
|
|
return cached.value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function setCachedPrice(key, value) {
|
|
priceCache[key] = {
|
|
value: value,
|
|
timestamp: Date.now()
|
|
};
|
|
logDebug('Price cached', { key: key });
|
|
}
|
|
|
|
function clearPriceCache() {
|
|
priceCache = {};
|
|
logDebug('Price cache cleared');
|
|
}
|
|
|
|
// ====================================================================
|
|
// SISTEMA DE TOOLTIPS OPTIMIZADO
|
|
// ====================================================================
|
|
|
|
var tooltipContent = {
|
|
'office-suite-tooltip': '<p>Integração do Collabora Online com o Nextcloud.</p>' +
|
|
'<p><strong>Collabora Online Development Edition (CODE)</strong> suporta uma média de 20 usuários simultaneos.</p>' +
|
|
'<p>Para um número maior de usuários, e para evitar instabilidade ou perda de documentos, você deve selecionar uma licença:</p>' +
|
|
'<p><strong>• Collabora Online for Business</strong> (até 99 usuários)<br>' +
|
|
'<strong>• Collabora Online for Enterprise</strong> (≥ 100 usuários)</p>' +
|
|
'<p><strong>ATENÇÃO:</strong> O número de usuários suportados pelo Collabora Online não limita o número de usuários suportados pelo Nextcloud.</p>'
|
|
};
|
|
|
|
function createTooltip() {
|
|
if (activeTooltip && activeTooltip.length) {
|
|
activeTooltip.remove();
|
|
}
|
|
|
|
activeTooltip = $('<div class="pmpro-tooltip" role="tooltip"></div>').css({
|
|
position: 'absolute',
|
|
background: '#333',
|
|
color: 'white',
|
|
padding: '16px 20px',
|
|
borderRadius: '8px',
|
|
fontSize: '14px',
|
|
lineHeight: '1.6',
|
|
width: '420px',
|
|
maxWidth: '95vw',
|
|
zIndex: 10001,
|
|
opacity: 0,
|
|
visibility: 'hidden',
|
|
transition: 'opacity 0.3s ease, visibility 0.3s ease',
|
|
boxShadow: '0 8px 24px rgba(0, 0, 0, 0.2)',
|
|
wordWrap: 'break-word',
|
|
whiteSpace: 'normal',
|
|
textAlign: 'left',
|
|
boxSizing: 'border-box'
|
|
});
|
|
|
|
$('body').append(activeTooltip);
|
|
return activeTooltip;
|
|
}
|
|
|
|
function positionTooltip(tooltip, trigger) {
|
|
var triggerOffset = trigger.offset();
|
|
var triggerWidth = trigger.outerWidth();
|
|
var triggerHeight = trigger.outerHeight();
|
|
var windowWidth = $(window).width();
|
|
var windowHeight = $(window).height();
|
|
var scrollTop = $(window).scrollTop();
|
|
|
|
// Mostrar temporalmente para obtener dimensiones
|
|
tooltip.css({ visibility: 'visible', opacity: 0 });
|
|
|
|
var tooltipWidth = tooltip.outerWidth();
|
|
var tooltipHeight = tooltip.outerHeight();
|
|
|
|
// Calcular posición horizontal
|
|
var left = triggerOffset.left + (triggerWidth / 2) - (tooltipWidth / 2);
|
|
|
|
// Ajustar si se sale de la pantalla
|
|
if (left + tooltipWidth > windowWidth - 20) {
|
|
left = windowWidth - tooltipWidth - 20;
|
|
}
|
|
if (left < 20) {
|
|
left = 20;
|
|
}
|
|
|
|
// Calcular posición vertical
|
|
var top = triggerOffset.top - tooltipHeight - 12;
|
|
|
|
// Si no cabe arriba, mostrarlo abajo
|
|
if (top < scrollTop + 20) {
|
|
top = triggerOffset.top + triggerHeight + 12;
|
|
}
|
|
|
|
// Aplicar posición
|
|
tooltip.css({
|
|
left: left + 'px',
|
|
top: top + 'px',
|
|
visibility: 'visible',
|
|
opacity: 1
|
|
});
|
|
|
|
logDebug('Tooltip positioned', { left: left, top: top });
|
|
}
|
|
|
|
function showTooltip(trigger, contentKey) {
|
|
clearTimeout(hideTooltipTimer);
|
|
|
|
if (showTooltipTimer) {
|
|
clearTimeout(showTooltipTimer);
|
|
}
|
|
|
|
showTooltipTimer = setTimeout(function() {
|
|
var content = tooltipContent[contentKey];
|
|
if (!content) {
|
|
logWarn('No content found for tooltip', { contentKey: contentKey });
|
|
return;
|
|
}
|
|
|
|
var tooltip = createTooltip();
|
|
tooltip.html(content);
|
|
positionTooltip(tooltip, trigger);
|
|
|
|
logDebug('Tooltip shown', { contentKey: contentKey });
|
|
}, TOOLTIP_DELAY);
|
|
}
|
|
|
|
function hideTooltip() {
|
|
clearTimeout(showTooltipTimer);
|
|
|
|
if (hideTooltipTimer) {
|
|
clearTimeout(hideTooltipTimer);
|
|
}
|
|
|
|
hideTooltipTimer = setTimeout(function() {
|
|
if (activeTooltip && activeTooltip.length) {
|
|
activeTooltip.css({ opacity: 0, visibility: 'hidden' });
|
|
|
|
setTimeout(function() {
|
|
if (activeTooltip && activeTooltip.length) {
|
|
activeTooltip.remove();
|
|
activeTooltip = null;
|
|
}
|
|
}, 300);
|
|
}
|
|
|
|
logDebug('Tooltip hidden');
|
|
}, 200);
|
|
}
|
|
|
|
function initTooltips() {
|
|
logDebug('Initializing tooltip system');
|
|
|
|
// Limpiar eventos previos
|
|
$(document).off('mouseenter.tooltip mouseleave.tooltip keydown.tooltip');
|
|
$(window).off('resize.tooltip scroll.tooltip');
|
|
|
|
// Eventos de tooltip
|
|
$(document).on('mouseenter.tooltip', '.pmpro-tooltip-trigger', function(e) {
|
|
var $trigger = $(e.currentTarget);
|
|
var tooltipId = $trigger.data('tooltip-id');
|
|
|
|
if (tooltipId && tooltipContent[tooltipId]) {
|
|
showTooltip($trigger, tooltipId);
|
|
}
|
|
});
|
|
|
|
$(document).on('mouseleave.tooltip', '.pmpro-tooltip-trigger', function() {
|
|
hideTooltip();
|
|
});
|
|
|
|
// Cerrar con Escape
|
|
$(document).on('keydown.tooltip', function(e) {
|
|
if (e.key === 'Escape' || e.keyCode === 27) {
|
|
hideTooltip();
|
|
}
|
|
});
|
|
|
|
// Reposicionar en scroll/resize
|
|
$(window).on('resize.tooltip scroll.tooltip', function() {
|
|
if (activeTooltip && activeTooltip.css('opacity') == '1') {
|
|
hideTooltip();
|
|
}
|
|
});
|
|
|
|
var triggerCount = $('.pmpro-tooltip-trigger').length;
|
|
logInfo('Tooltip system initialized', { triggerCount: triggerCount });
|
|
}
|
|
|
|
// ====================================================================
|
|
// GESTIÓN DE PRECIOS
|
|
// ====================================================================
|
|
|
|
function getStoragePrices(config) {
|
|
var prices = {};
|
|
var options = ['1tb', '2tb', '3tb', '4tb', '5tb', '6tb', '7tb', '8tb', '9tb', '10tb',
|
|
'15tb', '20tb', '30tb', '40tb', '50tb', '60tb', '70tb', '80tb', '90tb', '100tb',
|
|
'200tb', '300tb', '400tb', '500tb'];
|
|
|
|
for (var i = 0; i < options.length; i++) {
|
|
var option = options[i];
|
|
var tb = parseInt(option.replace('tb', ''));
|
|
prices[option] = config.basePrice + (config.pricePerTb * Math.max(0, tb - 1));
|
|
}
|
|
|
|
return prices;
|
|
}
|
|
|
|
function getOfficePrices(config) {
|
|
return {
|
|
'20users': 0,
|
|
'30users': config.officeUserPrice * 30,
|
|
'50users': config.officeUserPrice * 50,
|
|
'80users': config.officeUserPrice * 80,
|
|
'100users': (config.officeUserPrice - 3.75) * 100,
|
|
'150users': (config.officeUserPrice - 3.75) * 150,
|
|
'200users': (config.officeUserPrice - 3.75) * 200,
|
|
'300users': (config.officeUserPrice - 3.75) * 300,
|
|
'400users': (config.officeUserPrice - 3.75) * 400,
|
|
'500users': (config.officeUserPrice - 3.75) * 500
|
|
};
|
|
}
|
|
|
|
function formatPrice(price, currencySymbol) {
|
|
var formatted = Math.ceil(price).toFixed(2)
|
|
.replace('.', ',')
|
|
.replace(/(\d)(?=(\d{3})+\,)/g, '$1.');
|
|
|
|
return currencySymbol + ' ' + formatted;
|
|
}
|
|
|
|
function getPeriodText(frequency) {
|
|
var periods = {
|
|
'monthly': ' (por mês)',
|
|
'semiannual': ' (por 6 meses)',
|
|
'annual': ' (por ano)',
|
|
'biennial': ' (por 2 anos)',
|
|
'triennial': ' (por 3 anos)',
|
|
'quadrennial': ' (por 4 anos)',
|
|
'quinquennial': ' (por 5 anos)'
|
|
};
|
|
|
|
return periods[frequency] || '';
|
|
}
|
|
|
|
function calculateTotalPrice(config) {
|
|
var storageValue = $('#storage_space').val() || config.currentStorage;
|
|
var officeValue = $('#office_suite').val() || config.currentSuite;
|
|
var frequencyValue = $('#payment_frequency').val() || 'monthly';
|
|
|
|
// Verificar caché
|
|
var cacheKey = storageValue + '_' + officeValue + '_' + frequencyValue + '_' + config.basePrice;
|
|
var cached = getCachedPrice(cacheKey);
|
|
if (cached !== null) {
|
|
return cached;
|
|
}
|
|
|
|
var storagePrices = getStoragePrices(config);
|
|
var officePrices = getOfficePrices(config);
|
|
|
|
var storagePrice = storagePrices[storageValue] || config.basePrice;
|
|
var officePrice = officePrices[officeValue] || 0;
|
|
var multiplier = config.frequencyMultipliers[frequencyValue] || 1.0;
|
|
|
|
var calculation = {
|
|
storageValue: storageValue,
|
|
officeValue: officeValue,
|
|
frequencyValue: frequencyValue,
|
|
storagePrice: storagePrice,
|
|
officePrice: officePrice,
|
|
multiplier: multiplier,
|
|
totalPrice: Math.ceil((storagePrice + officePrice) * multiplier)
|
|
};
|
|
|
|
setCachedPrice(cacheKey, calculation);
|
|
|
|
logDebug('Price calculated', calculation);
|
|
return calculation;
|
|
}
|
|
|
|
function updatePriceDisplay(config) {
|
|
try {
|
|
var calculation = calculateTotalPrice(config);
|
|
var formattedPrice = formatPrice(calculation.totalPrice, config.currencySymbol);
|
|
var periodText = getPeriodText(calculation.frequencyValue);
|
|
var displayText = formattedPrice + periodText;
|
|
|
|
var $display = $('#total_price_display');
|
|
if ($display.length) {
|
|
$display.val(displayText);
|
|
logDebug('Price display updated', { displayText: displayText });
|
|
}
|
|
|
|
// Trigger evento personalizado
|
|
$(document).trigger('pmpropricing:updated', [calculation]);
|
|
|
|
} catch (error) {
|
|
logError('Error updating price display', { error: error.message });
|
|
}
|
|
}
|
|
|
|
// ====================================================================
|
|
// GESTIÓN DE OPCIONES
|
|
// ====================================================================
|
|
|
|
function storeOriginalTexts() {
|
|
$('#office_suite option, #storage_space option, #payment_frequency option').each(function() {
|
|
var $option = $(this);
|
|
var selectId = $option.closest('select').attr('id');
|
|
var key = selectId + '_' + $option.val();
|
|
originalTextsCache[key] = $option.text();
|
|
});
|
|
|
|
logDebug('Original texts stored', { count: Object.keys(originalTextsCache).length });
|
|
}
|
|
|
|
function updateStorageOptions(config) {
|
|
var currentTb = parseInt(config.currentStorage.replace('tb', '')) || 1;
|
|
var $storageSelect = $('#storage_space');
|
|
|
|
if (!$storageSelect.length) return;
|
|
|
|
$storageSelect.find('option').each(function() {
|
|
var $option = $(this);
|
|
var optionTb = parseInt($option.val().replace('tb', ''));
|
|
var originalKey = 'storage_space_' + $option.val();
|
|
var originalText = originalTextsCache[originalKey] || $option.text();
|
|
|
|
// Limpiar texto previo
|
|
var cleanText = originalText.replace(/ \(.*\)$/, '');
|
|
|
|
if (optionTb < currentTb && optionTb < config.usedSpaceTb) {
|
|
$option.prop('disabled', true);
|
|
$option.text(cleanText + ' (Espaço insuficiente)');
|
|
} else if (optionTb < currentTb) {
|
|
$option.prop('disabled', true);
|
|
$option.text(cleanText + ' (Downgrade não permitido)');
|
|
} else {
|
|
$option.prop('disabled', false);
|
|
$option.text(cleanText);
|
|
}
|
|
});
|
|
|
|
// Ajustar selección si está deshabilitada
|
|
if ($storageSelect.find('option:selected').prop('disabled')) {
|
|
var $firstEnabled = $storageSelect.find('option:not(:disabled)').first();
|
|
if ($firstEnabled.length) {
|
|
$storageSelect.val($firstEnabled.val()).trigger('change');
|
|
}
|
|
}
|
|
|
|
// Mostrar alerta si es necesario
|
|
if (config.usedSpaceTb > currentTb) {
|
|
showStorageAlert(config);
|
|
}
|
|
|
|
logDebug('Storage options updated', { currentTb: currentTb, usedSpaceTb: config.usedSpaceTb });
|
|
}
|
|
|
|
function updateOfficeOptions(config) {
|
|
var currentUsers = parseInt(config.currentSuite.replace('users', '')) || 20;
|
|
var $officeSelect = $('#office_suite');
|
|
|
|
if (!$officeSelect.length) return;
|
|
|
|
$officeSelect.find('option').each(function() {
|
|
var $option = $(this);
|
|
var optionUsers = parseInt($option.val().replace('users', ''));
|
|
var originalKey = 'office_suite_' + $option.val();
|
|
var originalText = originalTextsCache[originalKey] || $option.text();
|
|
|
|
if (optionUsers < currentUsers && currentUsers > 20) {
|
|
if (originalText.indexOf('(Redução de licenças)') === -1) {
|
|
$option.text(originalText + ' - Redução de licenças');
|
|
}
|
|
} else {
|
|
$option.text(originalText);
|
|
}
|
|
|
|
$option.prop('disabled', false);
|
|
});
|
|
|
|
logDebug('Office options updated', { currentUsers: currentUsers });
|
|
}
|
|
|
|
function showStorageAlert(config) {
|
|
var alertId = 'storage_alert';
|
|
|
|
if ($('#' + alertId).length) return;
|
|
|
|
var alertHtml = '<div class="pmpro_message pmpro_error" id="' + alertId + '">' +
|
|
'<strong>Atenção:</strong> Você está usando ' + config.usedSpaceTb.toFixed(2) + ' TB de armazenamento. ' +
|
|
'Não é possível reduzir abaixo deste limite.' +
|
|
'</div>';
|
|
|
|
$('#storage_space').before(alertHtml);
|
|
logInfo('Storage alert shown', { usedSpace: config.usedSpaceTb });
|
|
}
|
|
|
|
// ====================================================================
|
|
// INICIALIZACIÓN PRINCIPAL
|
|
// ====================================================================
|
|
|
|
function initializePMProDynamic() {
|
|
logInfo('Starting PMPro Dynamic initialization', { version: PLUGIN_VERSION });
|
|
|
|
// Verificar dependencias
|
|
if (!validateDependencies()) {
|
|
logError('Dependencies validation failed');
|
|
return false;
|
|
}
|
|
|
|
// Obtener configuración
|
|
var config = getConfig();
|
|
if (!config) {
|
|
logError('Configuration not available');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// 1. Guardar textos originales
|
|
storeOriginalTexts();
|
|
|
|
// 2. Configurar valores iniciales
|
|
var $storage = $('#storage_space');
|
|
var $office = $('#office_suite');
|
|
var $frequency = $('#payment_frequency');
|
|
|
|
if ($storage.length && !$storage.val()) {
|
|
$storage.val(config.currentStorage);
|
|
}
|
|
|
|
if ($office.length && !$office.val()) {
|
|
$office.val(config.currentSuite);
|
|
}
|
|
|
|
if ($frequency.length && !$frequency.val()) {
|
|
$frequency.val('monthly');
|
|
}
|
|
|
|
// 3. Actualizar opciones
|
|
updateStorageOptions(config);
|
|
updateOfficeOptions(config);
|
|
|
|
// 4. Calcular precio inicial
|
|
updatePriceDisplay(config);
|
|
|
|
// 5. Inicializar tooltips
|
|
initTooltips();
|
|
|
|
// 6. Configurar event listeners
|
|
$('#storage_space, #office_suite, #payment_frequency')
|
|
.off('change.pmpro')
|
|
.on('change.pmpro', function() {
|
|
logDebug('Field changed', {
|
|
field: $(this).attr('id'),
|
|
value: $(this).val()
|
|
});
|
|
|
|
// Limpiar caché
|
|
clearPriceCache();
|
|
|
|
// Actualizar precio
|
|
updatePriceDisplay(config);
|
|
});
|
|
|
|
// 7. Mostrar sección de precio
|
|
$('.pmpro_checkout-field-price-display').show();
|
|
|
|
logInfo('PMPro Dynamic initialized successfully', {
|
|
fieldsFound: $('#storage_space, #office_suite, #payment_frequency').length,
|
|
tooltipsFound: $('.pmpro-tooltip-trigger').length,
|
|
basePrice: config.basePrice
|
|
});
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
logError('Exception during initialization', {
|
|
message: error.message,
|
|
stack: error.stack
|
|
});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ====================================================================
|
|
// ESTRATEGIA DE INICIALIZACIÓN MÚLTIPLE
|
|
// ====================================================================
|
|
|
|
var initializationAttempts = 0;
|
|
var maxAttempts = 5;
|
|
var initializationDelays = [100, 250, 500, 1000, 2000];
|
|
|
|
function attemptInitialization() {
|
|
if (initializationAttempts >= maxAttempts) {
|
|
logError('Maximum initialization attempts reached');
|
|
return;
|
|
}
|
|
|
|
var delay = initializationDelays[initializationAttempts] || 2000;
|
|
initializationAttempts++;
|
|
|
|
setTimeout(function() {
|
|
logDebug('Initialization attempt ' + initializationAttempts + '/' + maxAttempts);
|
|
|
|
if (initializePMProDynamic()) {
|
|
logInfo('Initialization successful');
|
|
return;
|
|
}
|
|
|
|
// Si falló, intentar de nuevo
|
|
if (initializationAttempts < maxAttempts) {
|
|
logWarn('Initialization failed, retrying in ' + initializationDelays[initializationAttempts] + 'ms');
|
|
attemptInitialization();
|
|
}
|
|
}, delay);
|
|
}
|
|
|
|
// Iniciar proceso
|
|
attemptInitialization();
|
|
|
|
// Backup: inicializar cuando la página esté cargada
|
|
$(window).on('load', function() {
|
|
if ($('.pmpro-tooltip-trigger').length === 0 || $('#total_price_display').val() === '') {
|
|
logInfo('Window load backup initialization');
|
|
setTimeout(initializePMProDynamic, 500);
|
|
}
|
|
});
|
|
|
|
// API para debugging (solo en modo debug)
|
|
if (DEBUG_MODE) {
|
|
window.PMProDynamic = {
|
|
version: PLUGIN_VERSION,
|
|
reinitialize: initializePMProDynamic,
|
|
clearCache: clearPriceCache,
|
|
getConfig: getConfig,
|
|
log: {
|
|
error: logError,
|
|
warn: logWarn,
|
|
info: logInfo,
|
|
debug: logDebug
|
|
}
|
|
};
|
|
|
|
logInfo('Debug mode enabled - API available in window.PMProDynamic');
|
|
}
|
|
});
|