yoastseo-dep
Version:
Yoast clientside page analysis
960 lines (833 loc) • 29.6 kB
JavaScript
import { setLocaleData } from "@wordpress/i18n";
import { debounce, defaultsDeep, forEach, isArray, isEmpty, isFunction, isObject, isString, isUndefined, merge, noop, throttle } from "lodash-es";
import MissingArgument from "./errors/missingArgument";
import { measureTextWidth } from "./helpers/createMeasurementElement.js";
import removeHtmlBlocks from "./languageProcessing/helpers/html/htmlParser.js";
import Pluggable from "./pluggable.js";
import ContentAssessor from "./scoring/contentAssessor.js";
import CornerstoneContentAssessor from "./scoring/cornerstone/contentAssessor.js";
import CornerstoneSEOAssessor from "./scoring/cornerstone/seoAssessor.js";
import AssessorPresenter from "./scoring/renderers/AssessorPresenter.js";
import SEOAssessor from "./scoring/seoAssessor.js";
import SnippetPreview from "./snippetPreview/snippetPreview.js";
import Paper from "./values/Paper.js";
var inputDebounceDelay = 800;
/**
* Default config for YoastSEO.js
*
* @type {Object}
*/
var defaults = {
callbacks: {
bindElementEvents: noop,
updateSnippetValues: noop,
saveScores: noop,
saveContentScore: noop,
updatedContentResults: noop,
updatedKeywordsResults: noop,
},
sampleText: {
baseUrl: "example.org/",
snippetCite: "example-post/",
title: "",
keyword: "Choose a focus keyword",
meta: "",
text: "Start writing your text!",
},
queue: [ "wordCount",
"keywordDensity",
"subHeadings",
"stopwords",
"fleschReading",
"linkCount",
"imageCount",
"slugKeyword",
"urlLength",
"metaDescription",
"pageTitleKeyword",
"pageTitleWidth",
"firstParagraph",
"'keywordDoubles" ],
typeDelay: 3000,
typeDelayStep: 1500,
maxTypeDelay: 5000,
dynamicDelay: true,
locale: "en_US",
translations: {
domain: "wordpress-seo",
// eslint-disable-next-line camelcase
locale_data: {
"wordpress-seo": {
"": {},
},
},
},
replaceTarget: [],
resetTarget: [],
elementTarget: [],
marker: noop,
keywordAnalysisActive: true,
contentAnalysisActive: true,
hasSnippetPreview: true,
debounceRefresh: true,
};
/**
* Creates a default snippet preview, this can be used if no snippet preview has been passed.
*
* @private
* @this App
*
* @returns {SnippetPreview} The SnippetPreview object.
*/
function createDefaultSnippetPreview() {
var targetElement = document.getElementById( this.config.targets.snippet );
return new SnippetPreview( {
analyzerApp: this,
targetElement: targetElement,
callbacks: {
saveSnippetData: this.config.callbacks.saveSnippetData,
},
} );
}
/**
* Returns whether or not the given argument is a valid SnippetPreview object.
*
* @param {*} snippetPreview The 'object' to check against.
* @returns {boolean} Whether or not it's a valid SnippetPreview object.
*/
function isValidSnippetPreview( snippetPreview ) {
return ! isUndefined( snippetPreview ) && SnippetPreview.prototype.isPrototypeOf( snippetPreview );
}
/**
* Check arguments passed to the App to check if all necessary arguments are set.
*
* @private
* @param {Object} args The arguments object passed to the App.
* @returns {void}
*/
function verifyArguments( args ) {
if ( ! isObject( args.callbacks.getData ) ) {
throw new MissingArgument( "The app requires an object with a getdata callback." );
}
if ( ! isObject( args.targets ) ) {
throw new MissingArgument( "`targets` is a required App argument, `targets` is not an object." );
}
// The args.targets.snippet argument is only required if not SnippetPreview object has been passed.
if (
args.hasSnippetPreview &&
! isValidSnippetPreview( args.snippetPreview ) &&
! isString( args.targets.snippet ) ) {
throw new MissingArgument( "A snippet preview is required. When no SnippetPreview object isn't passed to " +
"the App, the `targets.snippet` is a required App argument. `targets.snippet` is not a string." );
}
}
/**
* This should return an object with the given properties
*
* @callback YoastSEO.App~getData
* @returns {Object} data
* @returns {String} data.keyword The keyword that should be used
* @returns {String} data.meta
* @returns {String} data.text The text to analyze
* @returns {String} data.metaTitle The text in the HTML title tag
* @returns {String} data.title The title to analyze
* @returns {String} data.url The URL for the given page
* @returns {String} data.excerpt Excerpt for the pages
*/
/**
* @callback YoastSEO.App~getAnalyzerInput
*
* @returns {Array} An array containing the analyzer queue
*/
/**
* @callback YoastSEO.App~bindElementEvents
*
* @param {YoastSEO.App} app A reference to the YoastSEO.App from where this is called.
*/
/**
* @callback YoastSEO.App~updateSnippetValues
*
* @param {Object} ev The event emitted from the DOM
*/
/**
* @callback YoastSEO.App~saveScores
*
* @param {int} score The overall keyword score as determined by the assessor.
* @param {AssessorPresenter} assessorPresenter The assessor presenter that will be used to render the keyword score.
*/
/**
* @callback YoastSEO.App~saveContentScore
*
* @param {int} score The overall content score as determined by the assessor.
* @param {AssessorPresenter} assessorPresenter The assessor presenter that will be used to render the content score.
*/
/**
* @callback YoastSEO.App~updatedContentResults
*
* @param {Object[]} result The updated content analysis results.
* @param {number} result[].score The SEO score.
* @param {string} result[].rating String representation of the SEO score.
* @param {string} result[].text Textual explanation of the score.
* @param {number} overallContentScore The overall content SEO score.
*/
/**
* @callback YoastSEO.App~updatedKeywordsResults
*
* @param {Object[]} result The updated keywords analysis results.
* @param {number} result[].score The SEO score.
* @param {string} result[].rating String representation of the SEO score.
* @param {string} result[].text Textual explanation of the score.
* @param {number} overallContentScore The overall keywords SEO score.
*/
/**
* Loader for the analyzer, loads the eventbinder and the elementdefiner
*
* @param {Object} args The arguments passed to the loader.
* @param {Object} args.translations Jed compatible translations.
* @param {Object} args.targets Targets to retrieve or set on.
* @param {String} args.targets.snippet ID for the snippet preview element.
* @param {String} args.targets.output ID for the element to put the output of the analyzer in.
* @param {int} args.typeDelay Number of milliseconds to wait between typing to refresh the analyzer output.
* @param {boolean} args.dynamicDelay Whether to enable dynamic delay, will ignore type delay if the analyzer takes a long time.
* Applicable on slow devices.
* @param {int} args.maxTypeDelay The maximum amount of type delay even if dynamic delay is on.
* @param {int} args.typeDelayStep The amount with which to increase the typeDelay on each step when dynamic delay is enabled.
* @param {Object} args.callbacks The callbacks that the app requires.
* @param {Object} args.assessor The Assessor to use instead of the default assessor.
* @param {YoastSEO.App~getData} args.callbacks.getData Called to retrieve input data
* @param {YoastSEO.App~getAnalyzerInput} args.callbacks.getAnalyzerInput Called to retrieve input for the analyzer.
* @param {YoastSEO.App~bindElementEvents} args.callbacks.bindElementEvents Called to bind events to the DOM elements.
* @param {YoastSEO.App~updateSnippetValues} args.callbacks.updateSnippetValues Called when the snippet values need to be updated.
* @param {YoastSEO.App~saveScores} args.callbacks.saveScores Called when the score has been determined by the analyzer.
* @param {YoastSEO.App~saveContentScore} args.callback.saveContentScore Called when the content score has been
* determined by the assessor.
* @param {YoastSEO.App~updatedContentResults} args.callbacks.updatedContentResults Called when the score has been determined
* by the analyzer.
* @param {YoastSEO.App~updatedKeywordsResults} args.callback.updatedKeywordsResults Called when the content score has been
* determined by the assessor.
* @param {Function} args.callbacks.saveSnippetData Function called when the snippet data is changed.
* @param {Function} args.marker The marker to use to apply the list of marks retrieved from an assessment.
*
* @param {SnippetPreview} args.snippetPreview The SnippetPreview object to be used.
* @param {boolean} [args.debouncedRefresh] Whether or not to debounce the
* refresh function. Defaults to true.
* @param {Researcher} args.researcher The Researcher object to be used.
*
* @constructor
*/
var App = function( args ) {
if ( ! isObject( args ) ) {
args = {};
}
defaultsDeep( args, defaults );
verifyArguments( args );
this.config = args;
if ( args.debouncedRefresh === true ) {
this.refresh = debounce( this.refresh.bind( this ), inputDebounceDelay );
}
this._pureRefresh = throttle( this._pureRefresh.bind( this ), this.config.typeDelay );
this.callbacks = this.config.callbacks;
setLocaleData( this.config.translations.locale_data[ "wordpress-seo" ], "wordpress-seo" );
this.initializeAssessors( args );
this.pluggable = new Pluggable( this );
this.getData();
this.defaultOutputElement = this.getDefaultOutputElement( args );
if ( this.defaultOutputElement !== "" ) {
this.showLoadingDialog();
}
if ( isValidSnippetPreview( args.snippetPreview ) ) {
this.snippetPreview = args.snippetPreview;
/* Hack to make sure the snippet preview always has a reference to this App. This way we solve the circular
dependency issue. In the future this should be solved by the snippet preview not having a reference to the
app.*/
if ( this.snippetPreview.refObj !== this ) {
this.snippetPreview.refObj = this;
}
} else if ( args.hasSnippetPreview ) {
this.snippetPreview = createDefaultSnippetPreview.call( this );
}
this._assessorOptions = {
useCornerStone: false,
};
this.initSnippetPreview();
this.initAssessorPresenters();
};
/**
* Returns the default output element based on which analyses are active.
*
* @param {Object} args The arguments passed to the App.
* @returns {string} The ID of the target that is active.
*/
App.prototype.getDefaultOutputElement = function( args ) {
if ( args.keywordAnalysisActive ) {
return args.targets.output;
}
if ( args.contentAnalysisActive ) {
return args.targets.contentOutput;
}
return "";
};
/**
* Sets the assessors based on the assessor options and refreshes them.
*
* @param {Object} assessorOptions The specific options.
* @returns {void}
*/
App.prototype.changeAssessorOptions = function( assessorOptions ) {
this._assessorOptions = merge( this._assessorOptions, assessorOptions );
// Set the assessors based on the new assessor options.
this.seoAssessor = this.getSeoAssessor();
this.contentAssessor = this.getContentAssessor();
// Refresh everything so the user sees the changes.
this.initAssessorPresenters();
this.refresh();
};
/**
* Returns an instance of the seo assessor to use.
*
* @returns {Assessor} The assessor instance.
*/
App.prototype.getSeoAssessor = function() {
const { useCornerStone } = this._assessorOptions;
const assessor = useCornerStone ? this.cornerStoneSeoAssessor : this.defaultSeoAssessor;
return assessor;
};
/**
* Returns an instance of the content assessor to use.
*
* @returns {Assessor} The assessor instance.
*/
App.prototype.getContentAssessor = function() {
const { useCornerStone } = this._assessorOptions;
return useCornerStone ? this.cornerStoneContentAssessor : this.defaultContentAssessor;
};
/**
* Initializes assessors based on if the respective analysis is active.
*
* @param {Object} args The arguments passed to the App.
* @returns {void}
*/
App.prototype.initializeAssessors = function( args ) {
this.initializeSEOAssessor( args );
this.initializeContentAssessor( args );
};
/**
* Initializes the SEO assessor.
*
* @param {Object} args The arguments passed to the App.
* @returns {void}
*/
App.prototype.initializeSEOAssessor = function( args ) {
if ( ! args.keywordAnalysisActive ) {
return;
}
this.defaultSeoAssessor = new SEOAssessor( { marker: this.config.marker } );
this.cornerStoneSeoAssessor = new CornerstoneSEOAssessor( { marker: this.config.marker } );
// Set the assessor
if ( isUndefined( args.seoAssessor ) ) {
this.seoAssessor = this.defaultSeoAssessor;
} else {
this.seoAssessor = args.seoAssessor;
}
};
/**
* Initializes the content assessor.
*
* @param {Object} args The arguments passed to the App.
* @returns {void}
*/
App.prototype.initializeContentAssessor = function( args ) {
if ( ! args.contentAnalysisActive ) {
return;
}
this.defaultContentAssessor = new ContentAssessor( { marker: this.config.marker, locale: this.config.locale } );
this.cornerStoneContentAssessor = new CornerstoneContentAssessor( { marker: this.config.marker, locale: this.config.locale } );
// Set the content assessor
if ( isUndefined( args._contentAssessor ) ) {
this.contentAssessor = this.defaultContentAssessor;
} else {
this.contentAssessor = args._contentAssessor;
}
};
/**
* Extend the config with defaults.
*
* @param {Object} args The arguments to be extended.
* @returns {Object} args The extended arguments.
*/
App.prototype.extendConfig = function( args ) {
args.sampleText = this.extendSampleText( args.sampleText );
args.locale = args.locale || "en_US";
return args;
};
/**
* Extend sample text config with defaults.
*
* @param {Object} sampleText The sample text to be extended.
* @returns {Object} sampleText The extended sample text.
*/
App.prototype.extendSampleText = function( sampleText ) {
var defaultSampleText = defaults.sampleText;
if ( isUndefined( sampleText ) ) {
return defaultSampleText;
}
for ( var key in sampleText ) {
if ( isUndefined( sampleText[ key ] ) ) {
sampleText[ key ] = defaultSampleText[ key ];
}
}
return sampleText;
};
/**
* Registers a custom data callback.
*
* @param {Function} callback The callback to register.
*
* @returns {void}
*/
App.prototype.registerCustomDataCallback = function( callback ) {
if ( ! this.callbacks.custom ) {
this.callbacks.custom = [];
}
if ( isFunction( callback ) ) {
this.callbacks.custom.push( callback );
}
};
/**
* Retrieves data from the callbacks.getData and applies modification to store these in this.rawData.
*
* @returns {void}
*/
App.prototype.getData = function() {
this.rawData = this.callbacks.getData();
// Add the custom data to the raw data.
if ( isArray( this.callbacks.custom ) ) {
this.callbacks.custom.forEach( ( customCallback ) => {
const customData = customCallback();
this.rawData = merge( this.rawData, customData );
} );
}
if ( this.hasSnippetPreview() ) {
// Gets the data FOR the analyzer
var data = this.snippetPreview.getAnalyzerData();
this.rawData.metaTitle = data.title;
this.rawData.url = data.url;
this.rawData.meta = data.metaDesc;
}
if ( this.pluggable.loaded ) {
this.rawData.metaTitle = this.pluggable._applyModifications( "data_page_title", this.rawData.metaTitle );
this.rawData.meta = this.pluggable._applyModifications( "data_meta_desc", this.rawData.meta );
}
this.rawData.titleWidth = measureTextWidth( this.rawData.metaTitle );
this.rawData.locale = this.config.locale;
};
/**
* Refreshes the analyzer and output of the analyzer, is debounced for a better experience.
*
* @returns {void}
*/
App.prototype.refresh = function() {
// Until all plugins are loaded, do not trigger a refresh.
if ( ! this.pluggable.loaded ) {
return;
}
this._pureRefresh();
};
/**
* Refreshes the analyzer and output of the analyzer, is throttled to prevent performance issues.
*
* @returns {void}
*
* @private
*/
App.prototype._pureRefresh = function() {
this.getData();
this.runAnalyzer();
};
/**
* Determines whether or not this app has a snippet preview.
*
* @returns {boolean} Whether or not this app has a snippet preview.
*/
App.prototype.hasSnippetPreview = function() {
return this.snippetPreview !== null && ! isUndefined( this.snippetPreview );
};
/**
* Initializes the snippet preview for this App.
*
* @returns {void}
*/
App.prototype.initSnippetPreview = function() {
if ( this.hasSnippetPreview() ) {
this.snippetPreview.renderTemplate();
this.snippetPreview.callRegisteredEventBinder();
this.snippetPreview.bindEvents();
this.snippetPreview.init();
}
};
/**
* Initializes the assessor presenters for content and SEO.
*
* @returns {void}
*/
App.prototype.initAssessorPresenters = function() {
// Pass the assessor result through to the formatter
if ( ! isUndefined( this.config.targets.output ) ) {
this.seoAssessorPresenter = new AssessorPresenter( {
targets: {
output: this.config.targets.output,
},
assessor: this.seoAssessor,
} );
}
if ( ! isUndefined( this.config.targets.contentOutput ) ) {
// Pass the assessor result through to the formatter
this.contentAssessorPresenter = new AssessorPresenter( {
targets: {
output: this.config.targets.contentOutput,
},
assessor: this.contentAssessor,
} );
}
};
/**
* Binds the refresh function to the input of the targetElement on the page.
*
* @returns {void}
*/
App.prototype.bindInputEvent = function() {
for ( var i = 0; i < this.config.elementTarget.length; i++ ) {
var elem = document.getElementById( this.config.elementTarget[ i ] );
elem.addEventListener( "input", this.refresh.bind( this ) );
}
};
/**
* Runs the rerender function of the snippetPreview if that object is defined.
*
* @returns {void}
*/
App.prototype.reloadSnippetText = function() {
if ( this.hasSnippetPreview() ) {
this.snippetPreview.reRender();
}
};
/**
* Sets the startTime timestamp.
*
* @returns {void}
*/
App.prototype.startTime = function() {
this.startTimestamp = new Date().getTime();
};
/**
* Sets the endTime timestamp and compares with startTime to determine typeDelayincrease.
*
* @returns {void}
*/
App.prototype.endTime = function() {
this.endTimestamp = new Date().getTime();
if ( this.endTimestamp - this.startTimestamp > this.config.typeDelay ) {
if ( this.config.typeDelay < ( this.config.maxTypeDelay - this.config.typeDelayStep ) ) {
this.config.typeDelay += this.config.typeDelayStep;
}
}
};
/**
* Inits a new pageAnalyzer with the inputs from the getInput function and calls the scoreFormatter
* to format outputs.
*
* @returns {void}
*/
App.prototype.runAnalyzer = function() {
if ( this.pluggable.loaded === false ) {
return;
}
if ( this.config.dynamicDelay ) {
this.startTime();
}
this.analyzerData = this.modifyData( this.rawData );
if ( this.hasSnippetPreview() ) {
this.snippetPreview.refresh();
}
let text = this.analyzerData.text;
// Insert HTML stripping code
text = removeHtmlBlocks( text );
let titleWidth = this.analyzerData.titleWidth;
if ( this.hasSnippetPreview() ) {
titleWidth = this.snippetPreview.getTitleWidth();
}
// Create a paper object for the Researcher
this.paper = new Paper( text, {
keyword: this.analyzerData.keyword,
synonyms: this.analyzerData.synonyms,
description: this.analyzerData.meta,
slug: this.analyzerData.slug,
title: this.analyzerData.metaTitle,
titleWidth: titleWidth,
locale: this.config.locale,
permalink: this.analyzerData.permalink,
} );
this.config.researcher.setPaper( this.paper );
this.runKeywordAnalysis();
this.runContentAnalysis();
this._renderAnalysisResults();
if ( this.config.dynamicDelay ) {
this.endTime();
}
if ( this.hasSnippetPreview() ) {
this.snippetPreview.reRender();
}
};
/**
* Runs the keyword analysis and calls the appropriate callbacks.
*
* @returns {void}
*/
App.prototype.runKeywordAnalysis = function() {
if ( this.config.keywordAnalysisActive ) {
this.seoAssessor.assess( this.paper );
const overallSeoScore = this.seoAssessor.calculateOverallScore();
if ( ! isUndefined( this.callbacks.updatedKeywordsResults ) ) {
this.callbacks.updatedKeywordsResults( this.seoAssessor.results, overallSeoScore );
}
if ( ! isUndefined( this.callbacks.saveScores ) ) {
this.callbacks.saveScores( overallSeoScore, this.seoAssessorPresenter );
}
}
};
/**
* Runs the content analysis and calls the appropriate callbacks.
*
* @returns {void}
*/
App.prototype.runContentAnalysis = function() {
if ( this.config.contentAnalysisActive ) {
this.contentAssessor.assess( this.paper );
const overallContentScore = this.contentAssessor.calculateOverallScore();
if ( ! isUndefined( this.callbacks.updatedContentResults ) ) {
this.callbacks.updatedContentResults( this.contentAssessor.results, overallContentScore );
}
if ( ! isUndefined( this.callbacks.saveContentScore ) ) {
this.callbacks.saveContentScore( overallContentScore, this.contentAssessorPresenter );
}
}
};
/**
* Modifies the data with plugins before it is sent to the analyzer.
*
* @param {Object} data The data to be modified.
* @returns {Object} The data with the applied modifications.
*/
App.prototype.modifyData = function( data ) {
// Copy rawdata to lose object reference.
data = JSON.parse( JSON.stringify( data ) );
data.text = this.pluggable._applyModifications( "content", data.text );
data.metaTitle = this.pluggable._applyModifications( "title", data.metaTitle );
return data;
};
/**
* Function to fire the analyzer when all plugins are loaded, removes the loading dialog.
*
* @returns {void}
*/
App.prototype.pluginsLoaded = function() {
this.removeLoadingDialog();
this.refresh();
};
/**
* Shows the loading dialog which shows the loading of the plugins.
*
* @returns {void}
*/
App.prototype.showLoadingDialog = function() {
var outputElement = document.getElementById( this.defaultOutputElement );
if ( this.defaultOutputElement !== "" && ! isEmpty( outputElement ) ) {
var dialogDiv = document.createElement( "div" );
dialogDiv.className = "YoastSEO_msg";
dialogDiv.id = "YoastSEO-plugin-loading";
document.getElementById( this.defaultOutputElement ).appendChild( dialogDiv );
}
};
/**
* Updates the loading plugins. Uses the plugins as arguments to show which plugins are loading.
*
* @param {Object} plugins The plugins to be parsed into the dialog.
* @returns {void}
*/
App.prototype.updateLoadingDialog = function( plugins ) {
var outputElement = document.getElementById( this.defaultOutputElement );
if ( this.defaultOutputElement === "" || isEmpty( outputElement ) ) {
return;
}
var dialog = document.getElementById( "YoastSEO-plugin-loading" );
dialog.textContent = "";
forEach( plugins, function( plugin, pluginName ) {
dialog.innerHTML += "<span class=left>" + pluginName + "</span><span class=right " +
plugin.status + ">" + plugin.status + "</span><br />";
} );
dialog.innerHTML += "<span class=bufferbar></span>";
};
/**
* Removes the pluging load dialog.
*
* @returns {void}
*/
App.prototype.removeLoadingDialog = function() {
var outputElement = document.getElementById( this.defaultOutputElement );
var loadingDialog = document.getElementById( "YoastSEO-plugin-loading" );
if ( ( this.defaultOutputElement !== "" && ! isEmpty( outputElement ) ) && ! isEmpty( loadingDialog ) ) {
document.getElementById( this.defaultOutputElement ).removeChild( document.getElementById( "YoastSEO-plugin-loading" ) );
}
};
// ***** PLUGGABLE PUBLIC DSL ***** //
/**
* Delegates to `YoastSEO.app.pluggable.registerPlugin`
*
* @param {string} pluginName The name of the plugin to be registered.
* @param {object} options The options object.
* @param {string} options.status The status of the plugin being registered. Can either be "loading" or "ready".
* @returns {boolean} Whether or not it was successfully registered.
*/
App.prototype.registerPlugin = function( pluginName, options ) {
return this.pluggable._registerPlugin( pluginName, options );
};
/**
* Delegates to `YoastSEO.app.pluggable.ready`
*
* @param {string} pluginName The name of the plugin to check.
* @returns {boolean} Whether or not the plugin is ready.
*/
App.prototype.pluginReady = function( pluginName ) {
return this.pluggable._ready( pluginName );
};
/**
* Delegates to `YoastSEO.app.pluggable.reloaded`
*
* @param {string} pluginName The name of the plugin to reload
* @returns {boolean} Whether or not the plugin was reloaded.
*/
App.prototype.pluginReloaded = function( pluginName ) {
return this.pluggable._reloaded( pluginName );
};
/**
* Delegates to `YoastSEO.app.pluggable.registerModification`.
*
* @param {string} modification The name of the filter
* @param {function} callable The callable function
* @param {string} pluginName The plugin that is registering the modification.
* @param {number} [priority] Used to specify the order in which the callables associated with a particular filter are called.
* Lower numbers correspond with earlier execution.
*
* @returns {boolean} Whether or not the modification was successfully registered.
*/
App.prototype.registerModification = function( modification, callable, pluginName, priority ) {
return this.pluggable._registerModification( modification, callable, pluginName, priority );
};
/**
* Registers a custom assessment for use in the analyzer, this will result in a new line in the analyzer results.
* The function needs to use the assessmentresult to return an result based on the contents of the page/posts.
*
* Score 0 results in a grey circle if it is not explicitly set by using setscore
* Scores 0, 1, 2, 3 and 4 result in a red circle
* Scores 6 and 7 result in a yellow circle
* Scores 8, 9 and 10 result in a green circle
*
* @param {string} name Name of the test.
* @param {function} assessment The assessment to run
* @param {string} pluginName The plugin that is registering the test.
* @returns {boolean} Whether or not the test was successfully registered.
*/
App.prototype.registerAssessment = function( name, assessment, pluginName ) {
if ( ! isUndefined( this.seoAssessor ) ) {
return this.pluggable._registerAssessment( this.defaultSeoAssessor, name, assessment, pluginName ) &&
this.pluggable._registerAssessment( this.cornerStoneSeoAssessor, name, assessment, pluginName );
}
};
/**
* Disables markers visually in the UI.
*
* @returns {void}
*/
App.prototype.disableMarkers = function() {
if ( ! isUndefined( this.seoAssessorPresenter ) ) {
this.seoAssessorPresenter.disableMarker();
}
if ( ! isUndefined( this.contentAssessorPresenter ) ) {
this.contentAssessorPresenter.disableMarker();
}
};
/**
* Renders the content and keyword analysis results.
*
* @returns {void}
*/
App.prototype._renderAnalysisResults = function() {
if ( this.config.contentAnalysisActive && ! isUndefined( this.contentAssessorPresenter ) ) {
this.contentAssessorPresenter.renderIndividualRatings();
}
if ( this.config.keywordAnalysisActive && ! isUndefined( this.seoAssessorPresenter ) ) {
this.seoAssessorPresenter.setKeyword( this.paper.getKeyword() );
this.seoAssessorPresenter.render();
}
};
// Deprecated functions
/**
* The analyzeTimer calls the checkInputs function with a delay, so the function won't be executed
* at every keystroke checks the reference object, so this function can be called from anywhere,
* without problems with different scopes.
*
* @deprecated: 1.3 - Use this.refresh() instead.
*
* @returns {void}
*/
App.prototype.analyzeTimer = function() {
this.refresh();
};
/**
* Registers a custom test for use in the analyzer, this will result in a new line in the analyzer results. The function
* has to return a result based on the contents of the page/posts.
*
* The scoring object is a special object with definitions about how to translate a result from your analysis function
* to a SEO score.
*
* Negative scores result in a red circle
* Scores 1, 2, 3, 4 and 5 result in a orange circle
* Scores 6 and 7 result in a yellow circle
* Scores 8, 9 and 10 result in a red circle
*
* @returns {void}
*
* @deprecated since version 1.2
*/
App.prototype.registerTest = function() {
console.error( "This function is deprecated, please use registerAssessment" );
};
/**
* Creates the elements for the snippetPreview
*
* @deprecated Don't create a snippet preview using this method, create it directly using the prototype and pass it as
* an argument instead.
*
* @returns {void}
*/
App.prototype.createSnippetPreview = function() {
this.snippetPreview = createDefaultSnippetPreview.call( this );
this.initSnippetPreview();
};
/**
* Switches between the cornerstone and default assessors.
*
* @deprecated 1.35.0 - Use changeAssessorOption instead.
*
* @param {boolean} useCornerStone True when cornerstone should be used.
*
* @returns {void}
*/
App.prototype.switchAssessors = function( useCornerStone ) {
// eslint-disable-next-line no-console
console.warn( "Switch assessor is deprecated since YoastSEO.js version 1.35.0" );
this.changeAssessorOptions( {
useCornerStone,
} );
};
export default App;