/* global awbPerformance, AwbTypography, ajaxurl, awbTypoData */ window.awbWizard = { /** * Run actions on load. * * @since 7.4 * * @return {void} */ init: function() { this.$el = jQuery( '.avada-dashboard' ); this.activeStep = 1; this.$steps = this.$el.find( '.awb-wizard-steps' ); this.homeURL = awbPerformance.homeURL; this.apiKey = awbPerformance.apiKey; this.saveChange = awbPerformance.saveChange; this.accessible = this.checkSiteAccessible(); // Font variant notice. this.$vnote = this.$el.find( '.variant-analysis' ); this.$vcount = this.$el.find( '.variant-count' ); // Lighthouse data is turned on. this.lighthouse = { before: false, after: false }; this.runTests = 'none'; // Listeners for events. this.addListeners(); // Init typography fields, could be moved. this.fontsRendered = false; this.initFontOptions(); }, /** * Init font family/variant select fields. * * @since 7.4 * * @return {void} */ initFontOptions: function() { var self = this, $fontFamily = this.$el.find( '.fusion-builder-font-family' ); if ( _.isUndefined( window.awbTypographySelect ) || _.isUndefined( window.awbTypographySelect.webfonts ) ) { jQuery.when( window.awbTypographySelect.getWebFonts() ).done( function() { self.initAfterWebfontsLoaded( $fontFamily ); } ); } else { this.initAfterWebfontsLoaded( $fontFamily ); } this.maybeShowPreload(); }, /** * Handle dependency for preloading options. * * @since 7.4 * * @return {void} */ maybeShowPreload: function() { var preloadVal = this.$el.find( 'input[name="preload_fonts"]' ).val(); if ( 'all' === preloadVal || 'google_fonts' === preloadVal ) { this.$el.find( '[name="preload_fonts_variants"], [name="preload_fonts_subsets"]' ).closest( '.pyre_metabox_field' ).show(); } else { this.$el.find( '[name="preload_fonts_variants"], [name="preload_fonts_subsets"]' ).closest( '.pyre_metabox_field' ).hide(); } }, /** * Check if site is accessible. * * @since 7.4 * * @return {void} */ checkSiteAccessible: function() { if ( this.homeURL.includes( 'localhost' ) ) { return false; } if ( ! this.homeURL.includes( '//' ) ) { return false; } return true; }, /** * Change which step is active. * * @since 7.4 * * @return {void} */ changeStep: function( step ) { var $step = this.$el.find( '.awb-wizard-section[data-step="' + step + '"]' ); if ( $step.length ) { // If this is the final step. if ( 'finish' === $step.attr( 'data-id' ) ) { this.finishSteps(); this.maybeFinishGPS(); } $step.removeClass( 'hidden' ); this.$el.find( '.awb-wizard-section:not([data-step="' + step + '"])' ).addClass( 'hidden' ); this.activeStep = parseInt( step ); this.$steps.find( '.completed' ).removeClass( 'completed' ); this.$steps.find( 'li:not([data-id="' + step + '"])' ).removeClass( 'active' ); this.$steps.find( '[data-id="' + step + '"]' ).addClass( 'active' ).prevAll().addClass( 'completed' ); this.scrollTo(); } }, /** * Perform finishing steps, cache, homepage load and test if desired. * * @since 7.4 * * @return {void} */ finishSteps: function() { var self = this, $progress = this.$el.find( '.finish-progress' ), $heading = $progress.find( '.avada-db-card-notice-heading' ), $improvements = this.$el.find( '.awb-possible-improvements' ); $progress.addClass( 'fetching' ); // Clear cache and maybe run lighthouse. this.clearCache().done( function() { $heading.html( awbPerformance.loadingHome ); jQuery.ajax( { type: 'GET', url: self.homeURL } ) .done( function() { if ( ! self.maybeFinishGPS() ) { $progress.removeClass( 'fetching' ).addClass( 'success' ); $heading.html( awbPerformance.wizardComplete ); } else { $heading.html( awbPerformance.performLighthouse ); } } ) .fail( function() { $progress.removeClass( 'fetching' ); self.addTemporaryClass( $progress, 'error' ); $heading.html( awbPerformance.errorLoadingPage ); } ); } ).fail( function() { $progress.removeClass( 'fetching' ); self.addTemporaryClass( $progress, 'error' ); $heading.html( awbPerformance.errorClearingCache ); } ); // Check if there are any recommendations to highlight. if ( this.$el.find( '.pyre_metabox_field.value-bad' ).length ) { $improvements.html( '' ).closest( '.awb-recommendation-holder' ).addClass( 'show-recommendations' ); this.$el.find( '.pyre_metabox_field.value-bad' ).each( function() { var $element = jQuery( this ); $improvements.append( '
' + optionData.message + '
' ); } if ( dynamic && 'undefined' !== typeof optionData.value ) { $element.attr( 'data-recommendation', optionData.value ); } } } ); } // Loop inputs and change value/add coloring. $activeStep.find( '.pyre_metabox_field' ).each( function() { var $element = jQuery( this ), recommended = $element.attr( 'data-recommendation' ), $input = $element.find( 'input, select' ), value = $input.val(); if ( ! recommended ) { return; } if ( 'object' === typeof value && 'function' === typeof value.join ) { value = value.join( ',' ); } if ( ( -1 !== recommended.indexOf( ',' ) && -1 !== recommended.indexOf( value ) ) || recommended === value ) { $element.addClass( 'value-good' ).removeClass( 'value-bad' ); } else { $element.addClass( 'value-bad' ).removeClass( 'value-good' ); } } ); // Make apply all button visibile. $activeStep.addClass( 'show-apply-all' ); }, /** * Apply recommendations on current step. * * @since 7.4 * * @return {void} */ applyRecommendations: function() { var $activeStep = this.$el.find( '.awb-wizard-section[data-step="' + this.activeStep + '"]' ); $activeStep.find( '.pyre_metabox_field' ).each( function() { var $element = jQuery( this ), recommended = $element.attr( 'data-recommendation' ), $input = $element.find( 'input, select' ), value = $input.length ? $input.val() : null; // Allow empty recommended value for FA select field. if ( ! recommended && 'status_fontawesome' !== $input.attr( 'name' ) ) { return; } if ( $element.find( 'select[multiple]' ).length && 'string' === typeof recommended ) { recommended = recommended.split( ',' ); $element.find( 'select[multiple]' ).val( recommended ).trigger( 'change' ); return; } if ( null !== value && ( ( -1 !== recommended.indexOf( ',' ) && -1 !== recommended.indexOf( value ) ) || recommended === value ) ) { return; } $element.find( '.buttonset-item.ui-state-active' ).removeClass( 'ui-state-active' ); $element.find( '.buttonset-item[data-value="' + recommended + '"]' ).addClass( 'ui-state-active' ); $element.find( 'input, select' ).val( recommended ).trigger( 'change' ); } ); // Hide button, no longer needed. setTimeout( function() { $activeStep.removeClass( 'show-apply-all' ); }, 2000 ); }, /** * Update icon scan markup. * * @since 7.4 * * @return {void} */ updateIcons: function( data ) { if ( '' !== data ) { this.$el.find( '#fusion-used-icons-table' ).removeClass( 'hidden' ); this.$el.find( '#fusion-used-icons-table tbody' ).html( data ); } }, /** * Add a class, wait and then remove. * * @since 7.4 * * @return {void} */ addTemporaryClass: function( $element, classname ) { $element.addClass( classname ); setTimeout( function() { $element.removeClass( classname ); }, 2000 ); }, /** * Display an error message to user. * * @since 7.4 * * @return {void} */ displayError: function( message ) { window.alert( message ); // eslint-disable-line no-alert }, /** * Run GPS test. * * @since 7.4 * * @return {void} */ runPageSpeed: function( status ) { var self = this, api = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed', parameters = { url: encodeURIComponent( this.homeURL ), category: 'PERFORMANCE', strategy: this.runTests.toUpperCase() }, query = api; status = 'undefined' === typeof status ? 'before' : status; // Site is not accessible, don't try. if ( ! this.accessible || 'none' === this.runTests ) { self.$el.find( '.awb-wizard-score-holder' ).addClass( 'hidden' ); return; } console.log( 'Running Test ', this.runTests ); // Which type of analysis to run. query += '?url=' + parameters.url; query += '&category=' + parameters.category; query += '&strategy=' + parameters.strategy; if ( this.apiKey ) { query += '&key=' + this.apiKey; } // Fetch results. fetch( query ).then( ( response ) => response.json() ).then( ( json ) => { var lighthouse, lighthouseMetrics; // Hide message saying it is fetching scores. if ( 'after' === status ) { self.$el.find( '.finish-progress' ).removeClass( 'fetching' ).addClass( 'success' ).find( '.avada-db-card-notice-heading' ).html( awbPerformance.wizardComplete ); } // Results failed in some way, set it so no further tests run. if ( 'object' !== typeof json || 'undefined' === typeof json.lighthouseResult ) { console.log( 'Lighthouse failed' ); self.$el.find( '.awb-wizard-score-holder' ).addClass( 'hidden' ); self.accessible = false; return; } lighthouse = json.lighthouseResult; console.log( 'lighthouse' ); lighthouseMetrics = { score: lighthouse.categories.performance.score * 100, fcp: lighthouse.audits[ 'first-contentful-paint' ].score * 100, lcp: lighthouse.audits[ 'largest-contentful-paint' ].score * 100, cls: lighthouse.audits[ 'cumulative-layout-shift' ].score * 100, fid: lighthouse.audits[ 'max-potential-fid' ].score * 100 }; // Store data with status. self[ status ] = lighthouseMetrics; console.log( 'Lighthouse completed', lighthouseMetrics ); // Update actual markup jQuery.each( lighthouseMetrics, function( metricId, metricValue ) { var $score = self.$el.find( '.awb-score-' + status + '[data-type="' + metricId + '"]' ), scoreClass = 'good'; if ( $score.length ) { if ( 50 > metricValue ) { scoreClass = 'poor'; } else if ( 90 > metricValue ) { scoreClass = 'okay'; } $score.removeClass( 'score-good score-okay score-poor score-fetching' ).addClass( 'score-' + scoreClass ).attr( 'data-score', metricValue ); $score.find( '.lh-gauge__percentage' ).html( Math.round( metricValue ) ); $score.find( '.lh-gauge-arc' ).css( 'stroke-dasharray', ( 360 * metricValue / 100 ) + ', 360' ); } } ); } ); }, /** * Create the data for font family and render select field. * * @since 2.2 * @param {object} $fontFamily - The option jQuery elements. * @return {Void} */ initAfterWebfontsLoaded: function( $fontFamily ) { // eslint-disable-line no-unused-vars var self = this; if ( 'object' !== typeof this.typoSets ) { this.typoSets = {}; } this.$el.find( '.fusion-builder-font-family' ).each( function() { self.typoSets[ jQuery( this ).attr( 'data-id' ) ] = new AwbTypography( jQuery( this ), self ); } ); this.$el.on( 'change', '.input-variant', function() { self.updateVariantCount(); } ); setTimeout( function() { self.updateVariantCount(); }, 100 ); this.fontsRendered = true; }, /** * Count unique variants. * * @since 7.4 * @return {Void} */ updateVariantCount: function() { var variants = {}, variantLength = 0; this.$el.find( '.fusion-builder-font-family' ).each( function() { var $family = jQuery( this ).find( '.input-font_family' ), $variant = jQuery( this ).find( '.input-variant' ), family = $family.val(), variant = $variant.val(), search = ''; if ( null === family ) { family = $family.attr( 'data-default' ); } if ( null === variant ) { variant = $variant.attr( 'data-default' ); } // Get font name from global typo set to avoid count the same font twice. if ( 'string' === typeof family && family.startsWith( 'var(--awb-' ) ) { const typoSetKey = family.replace( 'var(--awb-', '' ).replace( ')', '' ).replace( /\s+/g, '' ).split( '-' )[ 0 ]; family = awbTypoData.data[ typoSetKey ][ 'font-family' ]; variant = awbTypoData.data[ typoSetKey ][ 'font-weight' ] + awbTypoData.data[ typoSetKey ][ 'font-style' ]; } search = family + variant; if ( 'undefined' !== typeof variants[ search ] ) { return; } variants[ search ] = true; } ); variantLength = Object.keys( variants ).length; this.$vnote.attr( 'data-count', variantLength ); this.$vcount.html( variantLength ); } }; ( function( jQuery ) { 'use strict'; jQuery( document ).ready( function() { window.awbWizard.init(); } ); }( jQuery ) );