: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
/* global wpforms_challenge_admin */
* WPForms Challenge function.
* @since 1.6.2 Challenge v2
var WPFormsChallenge = window.WPFormsChallenge || {};
WPFormsChallenge.core = window.WPFormsChallenge.core || ( function( document, window, $ ) {
* Public functions and properties.
* Timer functions and properties.
* Number of minutes to complete the challenge.
initialSecondsLeft: WPFormsChallenge.admin.l10n.minutes_left * 60,
* @returns {string} ID from setInterval().
return localStorage.getItem( 'wpformsChallengeTimerId' );
* @param {number|string} id setInterval() ID to save.
localStorage.setItem( 'wpformsChallengeTimerId', id );
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
* @returns {string|void} ID from setInterval().
run: function( secondsLeft ) {
if ( 5 === app.loadStep() ) {
var timerId = setInterval( function() {
app.updateTimerUI( secondsLeft );
timer.saveSecondsLeft( 0 );
clearInterval( timerId );
var secondsLeft = timer.getSecondsLeft();
if ( 0 === secondsLeft || 5 === app.loadStep() ) {
timerId = timer.loadId();
clearInterval( timerId );
elSeconds = $( '#wpforms-challenge-timer' ).data( 'seconds-left' );
timer.saveSecondsLeft( elSeconds );
var secondsLeft = timer.getSecondsLeft();
if ( 0 === secondsLeft || 5 === app.loadStep() ) {
timerId = timer.loadId();
clearInterval( timerId );
timer.run( secondsLeft );
* Clear all frontend saved timer data.
localStorage.removeItem( 'wpformsChallengeSecondsLeft' );
localStorage.removeItem( 'wpformsChallengeTimerId' );
localStorage.removeItem( 'wpformsChallengeTimerStatus' );
$( '#wpforms-challenge-timer' ).removeData( 'seconds-left' );
* Get number of seconds left to complete the Challenge.
* @returns {number} Number of seconds left to complete the Challenge.
getSecondsLeft: function() {
var secondsLeft = localStorage.getItem( 'wpformsChallengeSecondsLeft' );
secondsLeft = parseInt( secondsLeft, 10 ) || 0;
* Get number of seconds spent completing the Challenge.
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
* @returns {number} Number of seconds spent completing the Challenge.
getSecondsSpent: function( secondsLeft ) {
secondsLeft = secondsLeft || timer.getSecondsLeft();
return timer.initialSecondsLeft - secondsLeft;
* Save number of seconds left to complete the Challenge.
* @param {number|string} secondsLeft Number of seconds left to complete the Challenge.
saveSecondsLeft: function( secondsLeft ) {
localStorage.setItem( 'wpformsChallengeSecondsLeft', secondsLeft );
* Get 'minutes' part of timer display.
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
* @returns {number} 'Minutes' part of timer display.
getMinutesFormatted: function( secondsLeft ) {
secondsLeft = secondsLeft || timer.getSecondsLeft();
return Math.floor( secondsLeft / 60 );
* Get 'seconds' part of timer display.
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
* @returns {number} 'Seconds' part of timer display.
getSecondsFormatted: function( secondsLeft ) {
secondsLeft = secondsLeft || timer.getSecondsLeft();
* Get formatted timer for display.
* @param {number} secondsLeft Number of seconds left to complete the Challenge.
* @returns {string} Formatted timer for display.
getFormatted: function( secondsLeft ) {
secondsLeft = secondsLeft || timer.getSecondsLeft();
var timerMinutes = timer.getMinutesFormatted( secondsLeft );
var timerSeconds = timer.getSecondsFormatted( secondsLeft );
return timerMinutes + ( 9 < timerSeconds ? ':' : ':0' ) + timerSeconds;
* Public functions and properties.
* Public timer functions and properties.
$( window ).on( 'load', function() {
// in case of jQuery 3.+ we need to wait for an `ready` event first.
if ( typeof $.ready.then === 'function' ) {
$.ready.then( app.load );
if ( wpforms_challenge_admin.option.status === 'started' ) {
app.timer.run( app.timer.getSecondsLeft() );
var timerId = app.timer.loadId();
clearInterval( timerId );
secondsLeft = app.timer.getSecondsLeft();
if ( ! timerId || 0 === app.loadStep() || wpforms_challenge_admin.option.status === 'inited' ) {
secondsLeft = app.timer.initialSecondsLeft;
app.initListUI( null, true );
app.updateTimerUI( secondsLeft );
$( [ window, document ] )
.on( 'blur', app.pauseChallenge )
.on( 'focus', app.resumeChallenge )
.on( 'click', '.wpforms-challenge-done-btn', app.resumeChallenge );
el.$btnPause.on( 'click', app.pauseChallenge );
el.$btnResume.on( 'click', app.resumeChallenge );
el.$listSteps.on( 'click', '.wpforms-challenge-item-current', app.refreshPage );
initElements: function() {
$challenge: $( '.wpforms-challenge' ),
$btnPause: $( '.wpforms-challenge-pause' ),
$btnResume: $( '.wpforms-challenge-resume' ),
$listSteps: $( '.wpforms-challenge-list' ),
$listBlock: $( '.wpforms-challenge-list-block' ),
$listBtnToggle: $( '.wpforms-challenge-list-block .toggle-list' ),
$progressBar: $( '.wpforms-challenge-bar' ),
$tooltipBtnDone: function() {
return $( '.wpforms-challenge-tooltip .wpforms-challenge-done-btn' );
* @returns {number} Last saved step.
var step = localStorage.getItem( 'wpformsChallengeStep' );
step = parseInt( step, 10 ) || 0;
* @param {number|string} step Step to save.
* @returns {object} jqXHR object from saveChallengeOption().
saveStep: function( step ) {
localStorage.setItem( 'wpformsChallengeStep', step );
return WPFormsChallenge.admin.saveChallengeOption( { step: step } );
* Update a step with backend data.
refreshStep: function() {
var savedStep = el.$challenge.data( 'wpforms-challenge-saved-step' );
savedStep = parseInt( savedStep, 10 ) || 0;
// Step saved on a backend has a priority.
if ( app.loadStep() !== savedStep ) {
app.saveStep( savedStep );
* Complete Challenge step.
* @param {number|string} step Step to complete.
* @returns {object} jqXHR object from saveStep().
stepCompleted: function( step ) {
app.updateListUI( step );
app.updateTooltipUI( step );
return app.saveStep( step );
* Initialize Challenge tooltips.
* @param {number|string} step Last saved step.
* @param {string} anchor Element selector to bind tooltip to.
* @param {object} args Tooltipster arguments.
initTooltips: function( step, anchor, args ) {
if ( typeof $.fn.tooltipster === 'undefined' ) {
var $dot = $( '<span class="wpforms-challenge-dot wpforms-challenge-dot-step' + step + '" data-wpforms-challenge-step="' + step + '"> </span>' );
content : $( '#tooltip-content' + step ),
theme : [ 'tooltipster-default', 'wpforms-challenge-tooltip' ],
functionReady : function( instance, helper ) {
$( helper.tooltip ).addClass( 'wpforms-challenge-tooltip-step' + step );
if ( step === 4 || step === 3 ) {
instance.option( 'side', 'right' );
} else if ( step === 1 ) {
instance.option( 'side', 'left' );
// Reposition is needed to render max-width CSS correctly.
if ( typeof args === 'object' && args !== null ) {
$.extend( tooltipsterArgs, args );
$dot.insertAfter( anchor ).tooltipster( tooltipsterArgs );
* Update tooltips appearance.