' + imagifyPricingModal.labels.errorPriceAPI + '
');
// Show the modal content.
imagifyModal.$modal.find('.imagify-modal-loader').fadeOut(300);
return;
}
// Autofill coupon code & Show banner if discount is active.
w.imagify_discount_datas = promo_datas;
if (promo_datas.is_active) {
$banners = $('.imagify-modal-promotion');
date_end = promo_datas.date_end.split('T')[0];
promo = promo_datas.coupon_value;
discount = 'percentage' === promo_datas.coupon_type ? promo + '%' : '$' + promo;
// Fill coupon code.
$('#imagify-coupon-code').val(promo_datas.label).attr('readonly', true);
// Show banners.
$banners.addClass('active').attr('aria-hidden', 'false');
// Populate banners.
$banners.find('.imagify-promotion-number').text(discount);
$banners.find('.imagify-promotion-date').text(date_end);
// Auto validate coupon.
imagifyModal.checkCoupon();
}
/**
* Find which plan(s) should be pre-selected.
*/
suggested = imagifyModal.getSuggestedOffers(offers, consumption, freeQuota);
/**
* Below lines will build Plan and Onetime offers lists.
* It will also pre-select a Plan and/or Onetime in both of views: pre-checkout and pricing tables.
*/
if (0 === offers.mo.length) {
$('.imagify-pre-checkout-offers .imagify-offer-monthly').remove();
$('.imagify-tabs').remove();
$('.imagify-pricing-tab-monthly').remove();
} else {
// Now, do the MONTHLIES Markup.
$.each(offers.mo, function (index, value) {
var $tpl, $offer,
classes = '';
// If offer is too big (far) than estimated needs, don't show the offer.
if ((index - suggested.mo.index) > 2) {
return true;
}
if (index === suggested.mo.index) {
// It's the one to display.
$offer = $('.imagify-pre-checkout-offers .imagify-offer-monthly');
if (suggested.mo.selected) {
classes = ' imagify-offer-selected';
// Add this offer as pre-selected item in pre-checkout view.
$offer.addClass('imagify-offer-selected').find('.imagify-checkbox').prop('checked', true);
}
// Populate the Pre-checkout view depending on user_cons.
imagifyModal.populateOffer($offer, value, 'monthly');
}
// Populate each offer.
$tpl = $(mo_clone).clone();
$tpl = imagifyModal.populateOffer($tpl, value, 'monthly', classes);
// Complete Monthlies HTML.
mo_html += $tpl[0].outerHTML;
});
}
if (0 === offers.ot.length) {
$('.imagify-pre-checkout-offers .imagify-offer-onetime').remove();
$('.imagify-tabs').remove();
$('.imagify-pricing-tab-onetime').remove();
} else {
// Do the ONETIMES Markup.
$.each(offers.ot, function (index, value) {
var $tpl, $offer,
classes = '';
// Parent classes.
if (index === suggested.ot.index) {
$offer = $('.imagify-pre-checkout-offers .imagify-offer-onetime');
if (suggested.ot.selected) {
classes = ' imagify-offer-selected';
// Add this offer as pre-selected item in pre-checkout view.
$offer.addClass('imagify-offer-selected').find('.imagify-checkbox').prop('checked', true);
}
// Populate the Pre-checkout view depending on user_cons.
imagifyModal.populateOffer($offer, value, 'onetime');
}
// Populate each offer.
$tpl = $(ot_clone).clone();
$tpl = imagifyModal.populateOffer($tpl, value, 'onetime', classes);
// complete Onetimes HTML
ot_html += $tpl[0].outerHTML;
});
}
// Fill pricing tables.
if ($mo_tpl.parent().find('.imagify-offer-line')) {
$mo_tpl.parent().find('.imagify-offer-line').remove();
}
$mo_tpl.before(mo_html);
if ($ot_tpl.parent().find('.imagify-offer-line')) {
$ot_tpl.parent().find('.imagify-offer-line').remove();
}
$ot_tpl.before(ot_html);
// Show the content.
imagifyModal.$modal.find('.imagify-modal-loader').fadeOut(300);
}); // Third AJAX request to get discount information.
}); // Second AJAX request for image estimation sizes.
// Populate Pay button.
imagifyModal.populatePayBtn();
}); // End $.post.
},
/**
* Tell which offer(s) should be pre-selected.
*
* @param object offers {
* An object build like this:
*
* @type array mo Monthly offers. The most important data being 'quota' (MBytes).
* @type array ot One-Time offers. The most important data being 'quota' (MBytes).
* }
* @param object consumption {
* An object build like this:
*
* @type array month Average image size uploaded each month on the site (MBytes).
* @type array total Total image size in the library (MBytes).
* }
* @param int freeQuota Quota of the free monthly offer (MBytes). Currently 25.
* @return object {
* An object build like this:
*
* @type object mo An object containing the index of the suggested monthly offer, and if it should be selected.
* @type object ot An object containing the index of the suggested one-time offer, and if it should be selected.
* }
*/
getSuggestedOffers: function (offers, consumption, freeQuota) {
var tmpMB = consumption.total + consumption.month,
plan,
biggestPlan = {
quota: 0
},
unlimitedPlan,
suggested = {
mo: false,
ot: false
};
/**
* Paid monthly plan.
*/
$.each(offers.mo, function (index, value) {
// if this is the unlimited plan, save it; we may need to come back to it.
if (0 > value.quota) {
unlimitedPlan = {
index: index,
selected: 1
};
}
// This is the biggest plan we've seen so far. Save it in case we need it later.
if (value.quota > biggestPlan.quota) {
biggestPlan = {
index: index,
selected: 1,
quota: value.quota
};
}
// Skip the free plan.
if ((0 === value.monthly_cost) && (0 === value.annual_cost)) {
return true;
}
// For all except unlimited plan: Rule out this plan if quota is less than either library size or monthly usage.
if ((0 >= value.quota) && (consumption.month > value.quota) || (consumption.total > value.quota)) {
return true;
}
// For all except unlimited plan: Consider this plan if its quota meets consumption needs.
if ((0 <= value.quota) && (consumption.month < value.quota) && (consumption.total < value.quota)) {
// Select this one when (1) we haven't yet selected a plan, or (2) when this plan is less quota than the current one.
if (('undefined' === typeof plan) || (plan.quota > value.quota)) {
plan = value;
suggested.mo = {
index: index,
selected: (freeQuota > consumption.month) && (freeQuota > consumption.total) ? 0 : 1
};
}
return true;
}
return true;
});
// If we don't have a plan selected by the time we get here, we need the infinite plan, or the biggest if infinite isn't available.
if (false === suggested.mo) {
if ('undefined' !== typeof unlimitedPlan) {
suggested.mo = unlimitedPlan;
} else {
suggested.mo = biggestPlan;
}
}
// Remaining MB.
tmpMB -= offers.mo[suggested.mo.index].quota;
// If we don't have active onetime plans, we're done.
if (0 === offers.ot.length) {
return suggested;
}
if (tmpMB <= 0) {
/**
* The monthly plan is big enough to optimize all the images that already are in the library.
* We'll display a One-Time plan that is able to optimize the whole library, in case the user doesn't want a monthly plan, but it won't be pre-selected.
*/
$.each(offers.ot, function (index, value) {
if (value.quota < consumption.total) {
// This plan is not big enough for the user needs.
return true;
}
// Suggested monthly plan.
suggested.ot = {
index: index,
selected: 0
};
return false;
});
if (false === suggested.ot) {
suggested.ot = {
index: offers.ot.length - 1,
selected: 0
};
}
return suggested;
}
/**
* The monthly plan is not big enough to optimize all the images that already are in the library.
* We need to select a One-Time plan.
*/
$.each(offers.ot, function (index, value) {
if (value.quota < tmpMB) {
// This plan is not big enough for the user needs.
return true;
}
// Suggested one-time plan.
suggested.ot = {
index: index,
selected: 1
};
return false;
});
if (false !== suggested.ot) {
// OK, we have all we need.
return suggested;
}
/**
* If nothing is selected, that means no OT plan is big enough for the user.
* In that case we fallback to the biggest available, and we need to increase the monthly plan.
*/
suggested.ot = {
index: offers.ot.length - 1,
selected: 1
};
// Reset monthly plan.
suggested.mo = false;
// Reset the remaining MB and subtract the OT plan quota.
tmpMB = consumption.total + consumption.month - offers.ot[suggested.ot.index].quota;
// Search for a new monthly plan.
$.each(offers.mo, function (index, value) {
if (value.quota < tmpMB) {
// This plan is not big enough for the user needs.
return true;
}
// Suggested monthly plan.
suggested.mo = {
index: index,
selected: 1
};
return false;
});
if (false === suggested.mo) {
/**
* If nothing is selected, that means no monthly plan is big enough for the user's monthly consumption.
* In that case we fallback to the biggest available.
*/
suggested.mo = {
index: offers.mo.length - 1,
selected: 1
};
}
return suggested;
},
/**
* @uses imagifyModal.populatePayBtn()
*/
checkCheckbox: function ($checkbox) {
var sel_class = 'imagify-offer-selected';
$checkbox.each(function () {
var $this = $(this);
if ($this.is(':checked')) {
$this.closest('.imagify-offer-line').addClass(sel_class);
} else {
$this.closest('.imagify-offer-line').removeClass(sel_class);
}
});
// Update pay button.
imagifyModal.populatePayBtn();
},
/**
* @uses imagifyModal.populatePayBtn()
*/
checkRadio: function ($radio) {
var year_class = 'imagify-year-selected',
month_class = 'imagify-month-selected';
$radio.each(function () {
// To handle modal pricing & modal suggestion.
var $_this = $(this),
$parent, $to_switch;
if ($_this.parent('.imagify-cart-list-switcher').length) {
$parent = $_this.closest('.imagify-cart');
} else if ($_this.parent('.imagify-small-options').length) {
$parent = $_this.parent('.imagify-small-options').next('.imagify-pricing-table');
} else {
$parent = $_this.closest('.imagify-offer-line');
}
$to_switch = $parent.find('.imagify-switch-my');
if ($_this.val() === 'yearly') {
$parent.addClass(year_class).removeClass(month_class);
$to_switch.find('.imagify-monthly').attr('aria-hidden', 'true');
$to_switch.find('.imagify-yearly').attr('aria-hidden', 'false');
} else {
$parent.addClass(month_class).removeClass(year_class);
$to_switch.find('.imagify-monthly').attr('aria-hidden', 'false');
$to_switch.find('.imagify-yearly').attr('aria-hidden', 'true');
}
});
// Update Pay button information.
imagifyModal.populatePayBtn();
return $radio;
},
/**
* Currently not used.
* @uses imagifyModal.populatePayBtn()
*/
populateBtnPrice: setInterval(function () {
imagifyModal.populatePayBtn();
}, 1000),
/**
* 1) Modal Payment change/select plan
* 2) Checkout selection(s)
* 3) Payment process
*/
getPeriod: function () {
return $('.imagify-offer-monthly').hasClass('imagify-month-selected') ? 'monthly' : 'yearly';
},
getApiKey: function () {
return $('#imagify-payment-iframe').data('imagify-api');
},
switchToView: function ($view, data) {
var viewId = $view.attr('id'),
$modalContent = imagifyModal.$modal.children('.imagify-modal-content');
$view.siblings('.imagify-modal-views').hide().attr('aria-hidden', 'true');
// Plans view has tabs: display the right one.
if (data && data.tab) {
$view.find('a[href="#' + data.tab + '"]').trigger('click.imagify');
}
// Payment view: it's an iframe.
if ('imagify-payment-process-view' === viewId) {
$modalContent.addClass('imagify-iframe-viewing');
} else {
$modalContent.removeClass('imagify-iframe-viewing');
}
// Success view: some tweaks.
if ('imagify-success-view' === viewId) {
$modalContent.addClass('imagify-success-viewing');
imagifyModal.$modal.attr('aria-labelledby', 'imagify-success-view');
} else {
$modalContent.removeClass('imagify-success-viewing');
imagifyModal.$modal.removeAttr('aria-labelledby');
}
$view.fadeIn(imagifyModal.speedFadeIn).attr('aria-hidden', 'false');
},
/**
* @uses imagifyModal.getApiKey()
*/
iframeSetSrc: function (params) {
/**
* params = {
* 'monthly': {
* 'lite': {
* name: 'something',
* id: ''
* }
* },
* 'onetime': {
* 'recommended': {
* name: 'Recommend',
* id: ''
* }
* },
* 'period': 'monthly'|'yearly'
* }
*/
var $iframe = $('#imagify-payment-iframe'),
iframe_src = $iframe.attr('src'),
pay_src = $iframe.data('src'),
monthly_id = 0,
onetime_id = 0,
// Stop it ESLint, you're drunk.
key, amount, // eslint-disable-line no-unused-vars
rt_onetime, rt_yearly, rt_monthly, coupon, rt_coupon, $iframeClone, tofind;
// If we only change monthly/yearly payment mode.
if (typeof params === 'string' && '' !== iframe_src) {
tofind = 'monthly' === params ? 'yearly' : 'monthly';
iframe_src = iframe_src.replace(tofind, params);
$iframe.attr('src', iframe_src);
return;
}
// If we get new informations about products.
if (typeof params !== 'object') {
return;
}
if (params.monthly) {
monthly_id = params.monthly[Object.keys(params.monthly)[0]].id;
}
if (params.onetime) {
onetime_id = params.onetime[Object.keys(params.onetime)[0]].id;
// If onetime ID === 999 it's a custom plan, send datas instead.
onetime_id = (onetime_id + '' === '999' ? params.onetime[Object.keys(params.onetime)[0]].data : onetime_id);
}
if (! params.period) {
w.imagify.info('No period defined');
return;
}
key = imagifyModal.getApiKey();
rt_onetime = onetime_id;
rt_yearly = 'yearly' === params.period ? monthly_id : 0;
rt_monthly = 'monthly' === params.period ? monthly_id : 0;
coupon = $('#imagify-coupon-code').val();
rt_coupon = '' === coupon ? 'none' : coupon;
// Not used but...
amount = parseFloat($('.imagify-global-amount').text()).toFixed(2);
// Compose route.
// pay_src + :ontimeplan(0)/:monthlyplan(0)/:yearlyplan(0)/:coupon(none)/
pay_src = pay_src + rt_onetime + '/' + rt_monthly + '/' + rt_yearly + '/' + rt_coupon + '/';
// iFrame sort of cache fix.
$iframeClone = $iframe.remove().attr('src', pay_src);
imagifyModal.$paymentView.html($iframeClone);
},
/**
* Public function triggered by payement iframe.
*/
paymentClose: function () {
$('.imagify-iframe-viewing .close-btn').trigger('click.imagify');
$('.imagify-iframe-viewing').removeClass('imagify-iframe-viewing');
},
/**
* @uses imagifyModal.switchToView()
*/
paymentBack: function () {
imagifyModal.switchToView(imagifyModal.$preView);
},
/**
* @uses imagifyModal.switchToView()
*/
paymentSuccess: function () {
imagifyModal.switchToView(imagifyModal.$successView);
},
/**
* @uses imagifyModal.paymentClose()
* @uses imagifyModal.paymentBack()
* @uses imagifyModal.paymentSuccess()
*/
checkPluginMessage: function (e) {
var origin = e.origin || e.originalEvent.origin; // eslint-disable-line no-shadow
if ('https://app.imagify.io' !== origin && 'http://dapp.imagify.io' !== origin) {
return;
}
switch (e.data) {
case 'cancel':
imagifyModal.paymentClose();
break;
case 'back':
imagifyModal.paymentBack();
break;
case 'success':
imagifyModal.paymentSuccess();
break;
}
}
};
/**
* INIT.
*/
// Check all boxes on load.
imagifyModal.checkCheckbox(imagifyModal.$checkboxes);
imagifyModal.checkRadio(imagifyModal.$radios.filter(':checked'));
// Check coupon onload.
imagifyModal.checkCoupon();
// Check the changed box.
imagifyModal.$checkboxes.on('change.imagify', function () {
imagifyModal.checkCheckbox($(this));
});
// Check the radio box.
imagifyModal.$radios.on('change.imagify', function () {
imagifyModal.checkRadio($(this));
});
/**
* Get pricings on modal opening.
* Build the pricing tables inside modal.
*/
$('#imagify-get-pricing-modal').on('click.imagify-ajax', function () {
imagifyModal.getPricing($(this));
});
/**
* Reset the modal on close.
*/
$(d).on('modalClosed.imagify', '.imagify-payment-modal', function () {
// Reset viewing class & aria-labelledby.
$(this).find('.imagify-modal-content').removeClass('imagify-success-viewing imagify-iframe-viewing');
// Reset first view after fadeout ~= 300 ms.
setTimeout(function () {
$('.imagify-modal-views').hide();
$('#imagify-pre-checkout-view').show();
}, 300);
});
/**
* Get validation for Coupon Code
* - On blur
* - On Enter or Spacebar press
* - On click OK button
*
* @since 1.6.3 Only if field hasn't readonly attribute (discount auto-applied).
*/
$('#imagify-coupon-code').on('blur.imagify', function () {
if (! $(this).attr('readonly')) {
imagifyModal.checkCoupon();
}
}).on('keydown.imagify', function (e) {
var $this = $(this);
if ($this.attr('readonly')) {
return;
}
if (13 === e.keyCode || 32 === e.keyCode) {
imagifyModal.checkCoupon();
return false;
}
if ($this.val().length >= 3) {
$this.closest('.imagify-coupon-input').addClass('imagify-canbe-validate');
} else {
$this.closest('.imagify-coupon-input').removeClass('imagify-canbe-validate');
}
});
$('#imagify-coupon-validate').on('click.imagify', function () {
imagifyModal.checkCoupon();
$(this).closest('.imagify-canbe-validate').removeClass('imagify-canbe-validate');
});
/**
* View game, step by step.
*/
// 1) when you decide to choose another plan.
/**
* 1.a) on click, display choices.
*
* @uses imagifyModal.switchToView()
*/
imagifyModal.$anotherBtn.on('click.imagify', function (e) {
var type = $(this).data('imagify-choose'),
tab = 'imagify-pricing-tab-' + ('plan' === type ? 'monthly' : 'onetime');
e.preventDefault();
imagifyModal.switchToView(imagifyModal.$plansView, { tab: tab });
});
/**
* 1.b) on click in a choice, return to pre-checkout step.
*
* @uses imagifyModal.getHtmlPrice()
* @uses imagifyModal.switchToView()
* @uses imagifyModal.populatePayBtn()
*/
imagifyModal.$modal.on('click.imagify', '.imagify-payment-btn-select-plan', function (e) {
var $_this = $(this),
$offer_line = $_this.closest('.imagify-offer-line'),
datas = $_this.data('offer'),
datas_str = $_this.attr('data-offer'),
is_onetime = $_this.closest('.imagify-tab-content').attr('id') !== 'imagify-pricing-tab-monthly',
$target_line = is_onetime ? imagifyModal.$preView.find('.imagify-offer-onetime') : imagifyModal.$preView.find('.imagify-offer-monthly'),
period = is_onetime ? null : ($_this.closest('.imagify-pricing-table').hasClass('imagify-month-selected') ? 'monthly' : 'yearly'),
price = is_onetime ? imagifyModal.getHtmlPrice(datas[Object.keys(datas)[0]].price) : imagifyModal.getHtmlPrice(datas[Object.keys(datas)[0]].prices, period),
monthly_txt = is_onetime ? '' : '