' + 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.
*/
// 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;
} );
// 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,
suggested = {
mo: false,
ot: false
};
if ( consumption.month <= freeQuota ) {
/**
* The free plan is enough (but we still may need a One-Time plan).
*/
suggested.mo = {
index: 0,
selected: 0
};
tmpMB -= freeQuota;
} else {
/**
* Paid monthly plan.
*/
$.each( offers.mo, function( index, value ) {
if ( value.quota < consumption.month ) {
// 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 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
};
}
// Remaining MB.
tmpMB -= offers.mo[ suggested.mo.index ].quota;
}
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 substract 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;
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 ? '' : '