Skip to content
This repository was archived by the owner on Oct 4, 2022. It is now read-only.

Commit f373906

Browse files
Merge branch 'release-yoast-seo/9.8' of github.com:Yoast/javascript into release-yoast-seo/9.8
2 parents ab03b9e + 43c1d3f commit f373906

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1013
-42
lines changed

packages/yoast-components/App.js

+50-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import SvgIconsWrapper from "./app/SvgIconsWrapper";
1515
import UIControlsWrapper from "./app/UIControlsWrapper";
1616
import Wizard from "./app/WizardWrapper";
1717
import Loader from "./composites/basic/Loader";
18+
import FacebookPreview from "./composites/Plugin/SocialPreviews/Facebook/components/FacebookPreview";
1819

1920
const components = [
2021
{
@@ -82,24 +83,39 @@ const components = [
8283
name: "Components",
8384
component: <ComponentsExample />,
8485
},
86+
{
87+
id: "facebookpreview-example",
88+
name: "FacebookPreview",
89+
component: <FacebookPreview siteName="SiteName.com" />,
90+
},
8591
];
8692

8793
const LanguageDirectionContainer = styled.div`
8894
text-align: center;
8995
`;
9096

97+
/**
98+
* Represents the React Example App.
99+
*/
91100
class App extends React.Component {
101+
/**
102+
* Constructs the App container.
103+
*/
92104
constructor() {
93105
super();
94106

95107
this.state = {
96108
activeComponent: "snippet-preview",
97109
isRtl: false,
98110
};
99-
100111
this.changeLanguageDirection = this.changeLanguageDirection.bind( this );
101112
}
102113

114+
/**
115+
* Get the active component.
116+
*
117+
* @returns {string} The active component.
118+
*/
103119
getContent() {
104120
const activeComponent = this.state.activeComponent;
105121
for ( var i = 0; i < components.length; i++ ) {
@@ -109,12 +125,27 @@ class App extends React.Component {
109125
}
110126
}
111127

128+
/**
129+
* Sets the activeComponent in the state.
130+
*
131+
* @param {string} activeComponent The active component id.
132+
*
133+
* @returns {void}
134+
*/
112135
navigate( activeComponent ) {
113136
this.setState( {
114137
activeComponent: activeComponent,
115138
} );
116139
}
117140

141+
/**
142+
* Renders the button for each component section.
143+
*
144+
* @param {string} id The component id.
145+
* @param {string} title The component name.
146+
*
147+
* @returns {ReactElement} The button.
148+
*/
118149
renderButton( id, title ) {
119150
const isActive = this.state.activeComponent === id;
120151
const style = {};
@@ -132,6 +163,11 @@ class App extends React.Component {
132163
);
133164
}
134165

166+
/**
167+
* Renders the menu.
168+
*
169+
* @returns {ReactElement} The navigation menu.
170+
*/
135171
getMenu() {
136172
return (
137173
<nav style={ { textAlign: "center" } }>
@@ -148,7 +184,6 @@ class App extends React.Component {
148184
);
149185
}
150186

151-
152187
/**
153188
* Renders a switch language directionality button.
154189
*
@@ -173,13 +208,26 @@ class App extends React.Component {
173208
} );
174209
}
175210

211+
/**
212+
* Sets the language direction based on what direction is in the current state after the component did update.
213+
*
214+
* @param {Object} prevProps The old props.
215+
* @param {Object} prevState The old state.
216+
*
217+
* @returns {void}
218+
*/
176219
componentDidUpdate( prevProps, prevState ) {
177220
// Set and update the <html> element dir attribute based on the current language direction.
178221
if ( prevState.isRtl !== this.state.isRtl ) {
179222
document.documentElement.setAttribute( "dir", this.state.isRtl ? "rtl" : "ltr" );
180223
}
181224
}
182225

226+
/**
227+
* Renders the example app.
228+
*
229+
* @returns {ReactElement} The rendered App.
230+
*/
183231
render() {
184232
return (
185233
<IntlProvider locale="en">

packages/yoast-components/app/AppWrapper.js

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ import configureStore from "./configureStore";
88

99
const store = configureStore();
1010

11+
/**
12+
* The AppWrapper container component.
13+
*
14+
* @param {object} children The component's children.
15+
*
16+
* @returns {ReactElement} The AppContainer component.
17+
*/
1118
const AppWrapper = ( { children } ) => (
1219
<AppContainer>
1320
<Provider store={ store }>

packages/yoast-components/app/KeywordExample.js

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const Container = styled.div`
2020
width: 248px;
2121
`;
2222

23+
/**
24+
* The keyword example class.
25+
*/
2326
export default class KeywordExample extends Component {
2427
/**
2528
* Constructs a keywordInput example.

packages/yoast-components/app/KeywordSuggestionWrapper.js

+12
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@ import React from "react";
33
import ExamplesContainer from "./ExamplesContainer";
44
import KeywordSuggestions from "../composites/KeywordSuggestions/KeywordSuggestions";
55

6+
/**
7+
* Sets the relevant word.
8+
*
9+
* @param {string} word The relevant word to set.
10+
*
11+
* @returns {void}
12+
*/
613
const RelevantWord = function( word ) {
714
this._word = word;
815
};
916

17+
/**
18+
* Returns the currently set relevant word.
19+
*
20+
* @returns {string} word The set relevant word.
21+
*/
1022
RelevantWord.prototype.getCombination = function() {
1123
return this._word;
1224
};

packages/yoast-components/app/SnippetEditorExample.js

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ const recommendedReplacementVariables = [
4040
replacementVariables[ 1 ].name,
4141
];
4242

43+
/**
44+
* The SnippetEditorExample class.
45+
*/
4346
export default class SnippetEditorExample extends Component {
4447
/**
4548
* Constructs a snippet preview example
@@ -75,6 +78,14 @@ export default class SnippetEditorExample extends Component {
7578
keyword: "merci",
7679
date: "Jan 8, 2018",
7780
locale: "fr",
81+
82+
/**
83+
* Logs the click event and its type.
84+
*
85+
* @param {object} type The click type.
86+
*
87+
* @returns {void}
88+
*/
7889
onClick( type ) {
7990
// eslint-disable-next-line no-console
8091
console.log( "clicked:", type );

packages/yoast-components/app/SvgIconsWrapper.js

+5
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ const SingleSvgContainer = styled.span`
4242
* @returns {ReactElement} The HelpCenterWrapper component.
4343
*/
4444
export default function SvgIconsWrapper() {
45+
/**
46+
* Returns the icons.
47+
*
48+
* @returns {array} result An array of SingleSvgContainer components.
49+
*/
4550
const getIcons = () => {
4651
return transform( icons, ( result, value, key ) => {
4752
const color = key === "seo-score-ok" ? colors.$color_ok : colors.$color_black;

packages/yoast-components/app/WizardWrapper.js

+12
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,22 @@ import Wizard from "../composites/OnboardingWizard/OnboardingWizard";
44
import Config from "../composites/OnboardingWizard/config/production-config";
55
import apiConfig from "../composites/OnboardingWizard/config/api-config";
66

7+
/**
8+
* Returns a deep clone of an object.
9+
*
10+
* @param {object} object The object to clone.
11+
*
12+
* @returns {object} The cloned object.
13+
*/
714
function cloneDeep( object ) {
815
return JSON.parse( JSON.stringify( object ) );
916
}
1017

18+
/**
19+
* The wizard component.
20+
*
21+
* @returns {React.component} A wizard.
22+
*/
1123
const WizardWrapper = () => {
1224
const config = cloneDeep( Config );
1325

packages/yoast-components/composites/AlgoliaSearch/AlgoliaSearcher.js

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ const VIEW = {
2323
DETAIL: "DETAIL",
2424
};
2525

26+
/**
27+
* The AlgoliaSearcher component.
28+
*/
2629
class AlgoliaSearcher extends React.Component {
2730
/**
2831
* AlgoliaSearcher constructor.

packages/yoast-components/composites/AlgoliaSearch/ArticleContent.js

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ const ArticleContentFullWidth = styled( IFrame )`
1717
* @constructor
1818
*/
1919

20+
/**
21+
* The ArticleContent component.
22+
*/
2023
class ArticleContent extends React.Component {
2124
/**
2225
* Constructs the article content.

packages/yoast-components/composites/OnboardingWizard/OnboardingWizard.js

+86-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import interpolateComponents from "interpolate-components";
1313
import ArrowForwardIcon from "material-ui/svg-icons/navigation/arrow-forward";
1414
import ArrowBackwardIcon from "material-ui/svg-icons/navigation/arrow-back";
1515
import CloseIcon from "material-ui/svg-icons/navigation/close";
16-
16+
import isUndefined from "lodash/isUndefined";
1717

1818
/**
1919
* The OnboardingWizard class.
@@ -36,8 +36,22 @@ class OnboardingWizard extends React.Component {
3636
errorMessage: "",
3737
};
3838

39+
this.postStep = this.postStep.bind( this );
3940
this.setNextStep = this.setNextStep.bind( this );
4041
this.setPreviousStep = this.setPreviousStep.bind( this );
42+
this.listenToHashChange = this.listenToHashChange.bind( this );
43+
window.addEventListener( "hashchange", this.listenToHashChange, false );
44+
}
45+
46+
/**
47+
* Remove the prepended hashtag from the passed string.
48+
*
49+
* @param {string} stringWithHashtag The string to remove the prepended hashtag from.
50+
*
51+
* @returns {string} The string without prepended hashtag.
52+
*/
53+
removePrependedHashtag( stringWithHashtag ) {
54+
return stringWithHashtag.substring( 1 );
4155
}
4256

4357
/**
@@ -131,6 +145,13 @@ class OnboardingWizard extends React.Component {
131145
* @returns {Object} The first step object
132146
*/
133147
getFirstStep( steps ) {
148+
// Use the hash from the url without the hashtag.
149+
const firstStep = this.removePrependedHashtag( window.location.hash );
150+
151+
if ( firstStep !== "" ) {
152+
return firstStep;
153+
}
154+
// When window.location doesn't have a hash, use the first step of the wizard as default.
134155
return Object.getOwnPropertyNames( steps )[ 0 ];
135156
}
136157

@@ -204,7 +225,16 @@ class OnboardingWizard extends React.Component {
204225
* @returns {Object} The current step.
205226
*/
206227
getCurrentStep() {
207-
return this.state.steps[ this.state.currentStepId ];
228+
const steps = this.state.steps;
229+
const currentStep = steps[ this.state.currentStepId ];
230+
231+
// If the currentStep is undefined because the stepId is invalid, return the first step of the Wizard.
232+
if ( isUndefined( currentStep ) ) {
233+
const firstStepId = Object.keys( steps )[ 0 ];
234+
this.setState( { currentStepId: firstStepId } );
235+
return steps[ firstStepId ];
236+
}
237+
return currentStep;
208238
}
209239

210240
/**
@@ -259,6 +289,59 @@ class OnboardingWizard extends React.Component {
259289
return ( hideButton ) ? "" : <RaisedButton className={ className } { ...attributes } />;
260290
}
261291

292+
/**
293+
* Updates the currentStepId in the state when the hash in the URL changes.
294+
*
295+
* @returns {void}
296+
*/
297+
listenToHashChange() {
298+
// Because the hash starts with a hashtag, we need to do remove the hastag before using it.
299+
this.setState( { currentStepId: this.removePrependedHashtag( window.location.hash ) } );
300+
}
301+
302+
/**
303+
* When the currentStepId in the state changes, return a snapshot with the new currentStepId.
304+
*
305+
* @param {Object} prevProps The previous props.
306+
* @param {Object} prevState The previous state.
307+
*
308+
* @returns {string|null} The currentStepId from after the update.
309+
*/
310+
getSnapshotBeforeUpdate( prevProps, prevState ) {
311+
const currentStepIdAfterUpdate = this.state.currentStepId;
312+
// If there is no change in the currentStepId in the state, do nothing.
313+
if ( prevState.currentStepId === currentStepIdAfterUpdate ) {
314+
return null;
315+
}
316+
317+
// If the new currentStepId is the same as the current location hash, do nothing.
318+
if ( this.removePrependedHashtag( window.location.hash ) === currentStepIdAfterUpdate ) {
319+
return null;
320+
}
321+
322+
return currentStepIdAfterUpdate;
323+
}
324+
325+
/**
326+
* Push the new hash to the history.
327+
*
328+
* Only do this when the new hash differs from the current hash. If we wouldn't check against
329+
* the current hash, it would lead to double hashes when using the browser's previous and next
330+
* buttons.
331+
*
332+
* @param {Object} prevProps The previous props.
333+
* @param {Object} prevState The previous state.
334+
* @param {string} snapshot The currentStepId from after the update.
335+
*
336+
* @returns {void}
337+
*/
338+
componentDidUpdate( prevProps, prevState, snapshot ) {
339+
if ( snapshot !== null ) {
340+
window.history.pushState( null, null, "#" + snapshot );
341+
}
342+
}
343+
344+
262345
/**
263346
* Renders the wizard.
264347
*
@@ -302,7 +385,7 @@ class OnboardingWizard extends React.Component {
302385
<Header headerTitle={ headerTitle } icon={ this.props.headerIcon } />
303386
<StepIndicator
304387
steps={ this.props.steps } stepIndex={ this.getCurrentStepNumber() - 1 }
305-
onClick={ ( stepNumber, evt ) => this.postStep( stepNumber, evt ) }
388+
onClick={ this.postStep }
306389
/>
307390
<main className="yoast-wizard-container">
308391
<div className="yoast-wizard">

packages/yoast-components/composites/OnboardingWizard/components/Choice.js

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ const Choice = ( props ) => {
2525
}
2626
const wrapperClass = "yoast-wizard-input-" + type;
2727

28+
/**
29+
* Returns a select or radio fieldset component.
30+
*
31+
* @returns {ReactElement} The fieldset component.
32+
*/
2833
const fieldSet = () => {
2934
if ( type === "select" ) {
3035
/*

0 commit comments

Comments
 (0)