From 2afa263f28dd376c61b8fc3f1537aac4737fec5e Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Wed, 9 Nov 2022 16:32:14 +0100 Subject: [PATCH 01/19] only mark the anchor text --- .../helpers/word/markWordsInSentences.js | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 0d10a8f5af6..663284abbba 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -1,8 +1,10 @@ +import getAnchorsFromText from "../link/getAnchorsFromText"; import matchWords from "../match/matchTextWithArray"; import arrayToRegex from "../regex/createRegexFromArray"; import addMark from "../../../markers/addMarkSingleWord"; import Mark from "../../../values/Mark"; import { escapeRegExp } from "lodash-es"; +import { stripFullTags } from "../sanitize/stripHTMLTags"; /** * Adds marks to a sentence and merges marks if those are only separated by a space @@ -19,10 +21,30 @@ export const collectMarkingsInSentence = function( sentence, topicFoundInSentenc topicFoundInSentence = topicFoundInSentence.map( word => escapeRegExp( word ) ); // If a language has a custom helper to match words, we disable the word boundary when creating the regex. const topicRegex = matchWordCustomHelper ? arrayToRegex( topicFoundInSentence, true ) : arrayToRegex( topicFoundInSentence ); - const markup = sentence.replace( topicRegex, function( x ) { + + // Retrieve the anchors. + const anchors = getAnchorsFromText( sentence ); + // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor + const markedAnchors = anchors.map( anchor => { + // Get the anchor text + const anchorText = stripFullTags( anchor ); + // Apply the marking to the anchor text + const markedAnchorText = anchorText.replace( topicRegex, ( x ) => addMark( x ) ); + // Replace the original anchor text with the marked anchor text + return anchor.replace( anchorText, markedAnchorText ); + } ); + + let markup = sentence.replace( topicRegex, function( x ) { return addMark( x ); } ); + if ( anchors.length > 0 ) { + const markupAnchors = getAnchorsFromText( markup ); + for ( let i = 0; i < markupAnchors.length; i++ ) { + markup = markup.replace( markupAnchors[ i ], markedAnchors[ i ] ); + } + } + return ( markup.replace( new RegExp( " ", "ig" ), " " ) ); }; From f0644b2ab66d4add49c20a50cb0438ef681a6094 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Wed, 9 Nov 2022 16:37:19 +0100 Subject: [PATCH 02/19] add unit tests --- .../helpers/word/markWordsInSentenceSpec.js | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js index caf3ae18664..b655d7fb7dc 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js @@ -3,6 +3,46 @@ import Mark from "../../../../src/values/Mark"; import matchWordCustomHelper from "../../../../src/languageProcessing/languages/ja/helpers/matchTextWithWord"; describe( "Adds Yoast marks to specific words in a sentence", function() { + it( "should add Yoast marks to all instances of specified words in a sentence, except when there is an anchor," + + " the marking should not be applied to the anchor tag attribute", function() { + expect( markWordsInSentences( + [ "picket", "tile" ], + [ "Introducing Palisades Ceramic Picket Tile — the latest trend in ceramic tile!" ], + "en_EN" + ) ).toEqual( [ + new Mark( { + marked: "Introducing Palisades Ceramic Picket Tile — the latest trend in " + + "ceramic " + + "tile!", + original: "Introducing Palisades Ceramic Picket Tile — the latest trend in " + + "ceramic tile!" } ), + ] + ); + } ); + it( "should add Yoast marks to all instances of specified words in a sentence, except when there are multiple anchors," + + " the marking should not be applied to the anchor tag attribute", function() { + expect( markWordsInSentences( + [ "picket", "tile" ], + [ "Introducing Palisades Ceramic Picket Tile — " + + "the latest trend in ceramic tile!" ], + "en_EN" + ) ).toEqual( [ + new Mark( { + marked: "Introducing Palisades Ceramic " + + "Picket Tile — the latest trend in " + + "ceramic " + + "tile!", + original: "Introducing Palisades Ceramic Picket Tile — " + + "the latest trend in ceramic tile!" } ), + ] + ); + } ); it( "should add Yoast marks to all instances of specified words in a sentence", function() { expect( markWordsInSentences( [ "turtle", "hamster" ], @@ -73,7 +113,7 @@ describe( "Adds Yoast marks to specific words in a sentence for languages with c new Mark( { marked: "小さい花の刺繍しかし、それは在庫切れでしたマキシドレス。", original: "小さい花の刺繍しかし、それは在庫切れでしたマキシドレス。" } ), - ] + ] ); } ); From daa14cf7e5541776c523d8b826b28f2c7dcded43 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Wed, 9 Nov 2022 16:57:51 +0100 Subject: [PATCH 03/19] fix highlight in classic editor --- packages/js/src/decorator/tinyMCE.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/js/src/decorator/tinyMCE.js b/packages/js/src/decorator/tinyMCE.js index d785100f933..4e695deed88 100644 --- a/packages/js/src/decorator/tinyMCE.js +++ b/packages/js/src/decorator/tinyMCE.js @@ -21,6 +21,12 @@ function removeInvalidMarks( editor ) { editor.setContent( html ); } +function replaceSingleQuotesInTags( str ) { + const element = document.createElement( "body" ); + element.innerHTML = str; + return element.innerHTML; +} + /** * Puts a list of marks into the given tinyMCE editor * @@ -37,6 +43,9 @@ function markTinyMCE( editor, paper, marks ) { // Generate marked HTML. forEach( marks, function( mark ) { + mark._properties.marked = replaceSingleQuotesInTags( mark._properties.marked ); + mark._properties.original = replaceSingleQuotesInTags( mark._properties.original ); + html = mark.applyWithReplace( html ); } ); From dfbdc4b1d8655f4317764324b74ee8c6b5a34be2 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Thu, 10 Nov 2022 12:14:58 +0100 Subject: [PATCH 04/19] Create a helper to replace single quotes to double quotes and add unit tests --- .../helpers/html/replaceQuotesSpec.js | 35 +++++++++++++++++++ .../helpers/html/replaceQuotes.js | 14 ++++++++ .../yoastseo/src/languageProcessing/index.js | 2 ++ 3 files changed, 51 insertions(+) create mode 100644 packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js create mode 100644 packages/yoastseo/src/languageProcessing/helpers/html/replaceQuotes.js diff --git a/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js new file mode 100644 index 00000000000..c0899a9545d --- /dev/null +++ b/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js @@ -0,0 +1,35 @@ +import replaceSingleQuotesInTags from "../../../../src/languageProcessing/helpers/html/replaceQuotes"; + +describe( "replace-quotes", function() { + describe( "replaceSingleQuotesInTags", function() { + it( "should return the same string when no single quotes are present", function() { + expect( replaceSingleQuotesInTags( "This is a test" ) ) + .toEqual( "This is a test" ); + } ); + + it( "should return the same string when only double quotes in HTML attribute values are present", function() { + expect( replaceSingleQuotesInTags( "This is a test" ) ) + .toEqual( "This is a test" ); + } ); + + it( "should not replace single quotes outside HTML tags", function() { + expect( replaceSingleQuotesInTags( "This is a test, let's go!" ) ) + .toEqual( "This is a test, let's go!" ); + } ); + + it( "should replace the outer single quotes in HTML attribute values with double quotes", function() { + expect( replaceSingleQuotesInTags( "This is a test" ) ) + .toEqual( "This is a test" ); + } ); + + it( "should not replace any inner single quotes in HTML attribute values", function() { + expect( replaceSingleQuotesInTags( "This is a test" ) ) + .toEqual( "This is a test" ); + } ); + + it( "should replace the outer single quotes in multiple HTML attribute values with double quotes", function() { + expect( replaceSingleQuotesInTags( "This is a test" ) ) + .toEqual( "This is a test" ); + } ); + } ); +} ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/html/replaceQuotes.js b/packages/yoastseo/src/languageProcessing/helpers/html/replaceQuotes.js new file mode 100644 index 00000000000..dffe809f48d --- /dev/null +++ b/packages/yoastseo/src/languageProcessing/helpers/html/replaceQuotes.js @@ -0,0 +1,14 @@ +/** + * Replaces single quotes around HTML attribute values with double quotes. + * Double quotes are the standard, but we convert these to single quotes when parsing the HTML in `yoastseo` package. + * Here, we change them back to double quotes so by parsing the HTML and then outputting it again. + * + * @param {string} str The input string. + * + * @returns {string} The string with single quotes around HTML attributes replaced with double quotes. + */ +export default function( str ) { + const element = document.createElement( "body" ); + element.innerHTML = str; + return element.innerHTML; +} diff --git a/packages/yoastseo/src/languageProcessing/index.js b/packages/yoastseo/src/languageProcessing/index.js index f262eb21313..f14d4763d4c 100644 --- a/packages/yoastseo/src/languageProcessing/index.js +++ b/packages/yoastseo/src/languageProcessing/index.js @@ -26,6 +26,7 @@ import { stripFullTags as stripHTMLTags } from "./helpers/sanitize/stripHTMLTags import sanitizeString from "./helpers/sanitize/sanitizeString"; import { unifyAllSpaces } from "./helpers/sanitize/unifyWhitespace"; import removePunctuation from "./helpers/sanitize/removePunctuation"; +import replaceSingleQuotesInTags from "./helpers/html/replaceQuotes"; import countMetaDescriptionLength from "./helpers/word/countMetaDescriptionLength"; import getLanguage from "./helpers/language/getLanguage"; import getSentences from "./helpers/sentence/getSentences"; @@ -63,4 +64,5 @@ export { getLanguage, getSentences, unifyAllSpaces, + replaceSingleQuotesInTags, }; From 9913b6279cea2bc06620539050af6b74646d4e1f Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Thu, 10 Nov 2022 12:15:22 +0100 Subject: [PATCH 05/19] convert single quotes to double quotes in Classic editor --- packages/js/src/decorator/tinyMCE.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/js/src/decorator/tinyMCE.js b/packages/js/src/decorator/tinyMCE.js index 4e695deed88..1f6a9fb9116 100644 --- a/packages/js/src/decorator/tinyMCE.js +++ b/packages/js/src/decorator/tinyMCE.js @@ -1,4 +1,4 @@ -import { markers } from "yoastseo"; +import { markers, languageProcessing } from "yoastseo"; import { forEach } from "lodash-es"; var MARK_TAG = "yoastmark"; @@ -21,12 +21,6 @@ function removeInvalidMarks( editor ) { editor.setContent( html ); } -function replaceSingleQuotesInTags( str ) { - const element = document.createElement( "body" ); - element.innerHTML = str; - return element.innerHTML; -} - /** * Puts a list of marks into the given tinyMCE editor * @@ -43,8 +37,8 @@ function markTinyMCE( editor, paper, marks ) { // Generate marked HTML. forEach( marks, function( mark ) { - mark._properties.marked = replaceSingleQuotesInTags( mark._properties.marked ); - mark._properties.original = replaceSingleQuotesInTags( mark._properties.original ); + mark._properties.marked = languageProcessing.replaceSingleQuotesInTags( mark._properties.marked ); + mark._properties.original = languageProcessing.replaceSingleQuotesInTags( mark._properties.original ); html = mark.applyWithReplace( html ); } ); From e39d58b71782bd5af3c0fc6702766f0f7eab5194 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Thu, 10 Nov 2022 13:54:11 +0100 Subject: [PATCH 06/19] Make a separate helper to get the anchors and the marked anchors --- .../helpers/word/markWordsInSentences.js | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 663284abbba..b140f8bcbdb 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -6,6 +6,29 @@ import Mark from "../../../values/Mark"; import { escapeRegExp } from "lodash-es"; import { stripFullTags } from "../sanitize/stripHTMLTags"; +/** + * Gets the anchors and mark the anchors' text if the topic is found in the anchors' text. + * + * @param {string} sentence The sentence to retrieve the anchors from. + * @param {RegExp} topicRegex The regex of the topic. + * + * @returns {Object} The anchors and the marked anchors. + */ +const getMarkedAnchors = function( sentence, topicRegex ) { + // Retrieve the anchors. + const anchors = getAnchorsFromText( sentence ); + // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor + const markedAnchors = anchors.map( anchor => { + // Get the anchor text + const anchorText = stripFullTags( anchor ); + // Apply the marking to the anchor text + const markedAnchorText = anchorText.replace( topicRegex, ( x ) => addMark( x ) ); + // Replace the original anchor text with the marked anchor text + return anchor.replace( anchorText, markedAnchorText ); + } ); + return { anchors, markedAnchors }; +}; + /** * Adds marks to a sentence and merges marks if those are only separated by a space * (e.g., if highlighting words "ballet" and "shoes" in a sentence "I have a lot of ballet shoes and other paraphernalia." @@ -22,22 +45,19 @@ export const collectMarkingsInSentence = function( sentence, topicFoundInSentenc // If a language has a custom helper to match words, we disable the word boundary when creating the regex. const topicRegex = matchWordCustomHelper ? arrayToRegex( topicFoundInSentence, true ) : arrayToRegex( topicFoundInSentence ); - // Retrieve the anchors. - const anchors = getAnchorsFromText( sentence ); - // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor - const markedAnchors = anchors.map( anchor => { - // Get the anchor text - const anchorText = stripFullTags( anchor ); - // Apply the marking to the anchor text - const markedAnchorText = anchorText.replace( topicRegex, ( x ) => addMark( x ) ); - // Replace the original anchor text with the marked anchor text - return anchor.replace( anchorText, markedAnchorText ); - } ); + // Retrieve the anchors and mark the anchors' text if the topic is found in the anchors' text. + const { anchors, markedAnchors } = getMarkedAnchors( sentence, topicRegex ); let markup = sentence.replace( topicRegex, function( x ) { return addMark( x ); } ); + /** + * In 'markup', we apply the markings also inside the anchor's attribute if there is a match, on top of + * marking the anchor's text. + * The step below is to replace the incorrectly marked anchors with the marked anchors that we want: + * where the markings are only applied in the anchor's text. + */ if ( anchors.length > 0 ) { const markupAnchors = getAnchorsFromText( markup ); for ( let i = 0; i < markupAnchors.length; i++ ) { From a80d44f8658aa90ad7aaefa11c7af7639a12e8fb Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 14 Nov 2022 10:57:17 +0100 Subject: [PATCH 07/19] Adjust documentation --- .../helpers/word/markWordsInSentences.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index b140f8bcbdb..eee11a2b747 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -17,13 +17,13 @@ import { stripFullTags } from "../sanitize/stripHTMLTags"; const getMarkedAnchors = function( sentence, topicRegex ) { // Retrieve the anchors. const anchors = getAnchorsFromText( sentence ); - // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor + // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor. const markedAnchors = anchors.map( anchor => { - // Get the anchor text + // Get the anchor text. const anchorText = stripFullTags( anchor ); - // Apply the marking to the anchor text + // Apply the marking to the anchor text. const markedAnchorText = anchorText.replace( topicRegex, ( x ) => addMark( x ) ); - // Replace the original anchor text with the marked anchor text + // Replace the original anchor text with the marked anchor text. return anchor.replace( anchorText, markedAnchorText ); } ); return { anchors, markedAnchors }; From 4ad41d67b65c2f000fe4b1a71776b1f2a92ad586 Mon Sep 17 00:00:00 2001 From: Agnieszka Szuba Date: Wed, 16 Nov 2022 16:37:33 +0100 Subject: [PATCH 08/19] Add comment --- .../languageProcessing/helpers/word/markWordsInSentences.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index eee11a2b747..8f491fcd39a 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -65,6 +65,10 @@ export const collectMarkingsInSentence = function( sentence, topicFoundInSentenc } } + /* + * If two marks are separated by only a space, remove the closing tag of the first mark and the opening tag of the + * second mark so that the two marks can be combined into one. + */ return ( markup.replace( new RegExp( " ", "ig" ), " " ) ); }; From 899572c0320d1142dd79be83a83e404a0f8f99b9 Mon Sep 17 00:00:00 2001 From: Agnieszka Szuba Date: Wed, 16 Nov 2022 17:03:47 +0100 Subject: [PATCH 09/19] Rename 'topic' to 'words' 'topic' is an umbrella term for keyphrase and synonyms that we use in the code. But the functionality in this file is also used to mark words in the word complexity assessment, so the using the word 'topic' is no longer accurate here --- .../helpers/word/markWordsInSentences.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 8f491fcd39a..17b660d79cd 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -7,14 +7,14 @@ import { escapeRegExp } from "lodash-es"; import { stripFullTags } from "../sanitize/stripHTMLTags"; /** - * Gets the anchors and mark the anchors' text if the topic is found in the anchors' text. + * Gets the anchors and marks the anchors' text if the words are found in it. * * @param {string} sentence The sentence to retrieve the anchors from. - * @param {RegExp} topicRegex The regex of the topic. + * @param {RegExp} wordsRegex The regex of the words. * * @returns {Object} The anchors and the marked anchors. */ -const getMarkedAnchors = function( sentence, topicRegex ) { +const getMarkedAnchors = function( sentence, wordsRegex ) { // Retrieve the anchors. const anchors = getAnchorsFromText( sentence ); // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor. @@ -22,7 +22,7 @@ const getMarkedAnchors = function( sentence, topicRegex ) { // Get the anchor text. const anchorText = stripFullTags( anchor ); // Apply the marking to the anchor text. - const markedAnchorText = anchorText.replace( topicRegex, ( x ) => addMark( x ) ); + const markedAnchorText = anchorText.replace( wordsRegex, ( x ) => addMark( x ) ); // Replace the original anchor text with the marked anchor text. return anchor.replace( anchorText, markedAnchorText ); } ); @@ -35,20 +35,20 @@ const getMarkedAnchors = function( sentence, topicRegex ) { * the marks will be put around "ballet shoes" together, not "`ballet` `shoes`".) * * @param {string} sentence The sentence to mark words in. - * @param {[string]} topicFoundInSentence The words to mark in the sentence. + * @param {[string]} wordsFoundInSentence The words to mark in the sentence. * @param {function} matchWordCustomHelper The language-specific helper function to match word in text. * * @returns {string} The sentence with marks. */ -export const collectMarkingsInSentence = function( sentence, topicFoundInSentence, matchWordCustomHelper ) { - topicFoundInSentence = topicFoundInSentence.map( word => escapeRegExp( word ) ); +export const collectMarkingsInSentence = function( sentence, wordsFoundInSentence, matchWordCustomHelper ) { + wordsFoundInSentence = wordsFoundInSentence.map( word => escapeRegExp( word ) ); // If a language has a custom helper to match words, we disable the word boundary when creating the regex. - const topicRegex = matchWordCustomHelper ? arrayToRegex( topicFoundInSentence, true ) : arrayToRegex( topicFoundInSentence ); + const wordsRegex = matchWordCustomHelper ? arrayToRegex( wordsFoundInSentence, true ) : arrayToRegex( wordsFoundInSentence ); - // Retrieve the anchors and mark the anchors' text if the topic is found in the anchors' text. - const { anchors, markedAnchors } = getMarkedAnchors( sentence, topicRegex ); + // Retrieve the anchors and mark the anchors' text if the words are found in the anchors' text. + const { anchors, markedAnchors } = getMarkedAnchors( sentence, wordsRegex ); - let markup = sentence.replace( topicRegex, function( x ) { + let markup = sentence.replace( wordsRegex, function( x ) { return addMark( x ); } ); @@ -83,16 +83,16 @@ export const collectMarkingsInSentence = function( sentence, topicFoundInSentenc * @returns {[string]} The sentences with marks. */ export function markWordsInSentences( wordsToMark, sentences, locale, matchWordCustomHelper ) { - let topicFoundInSentence = []; + let wordsFoundInSentence = []; let markings = []; sentences.forEach( function( sentence ) { - topicFoundInSentence = matchWords( sentence, wordsToMark, locale, matchWordCustomHelper ).matches; + wordsFoundInSentence = matchWords( sentence, wordsToMark, locale, matchWordCustomHelper ).matches; - if ( topicFoundInSentence.length > 0 ) { + if ( wordsFoundInSentence.length > 0 ) { markings = markings.concat( new Mark( { original: sentence, - marked: collectMarkingsInSentence( sentence, topicFoundInSentence, matchWordCustomHelper ), + marked: collectMarkingsInSentence( sentence, wordsFoundInSentence, matchWordCustomHelper ), } ) ); } } ); From d45ade71759f46d423b94e74bf62f9c6a4fb007a Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Thu, 17 Nov 2022 15:03:06 +0100 Subject: [PATCH 10/19] Add comment --- packages/js/src/decorator/tinyMCE.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/js/src/decorator/tinyMCE.js b/packages/js/src/decorator/tinyMCE.js index e0a09c942c9..8aee47d2c92 100644 --- a/packages/js/src/decorator/tinyMCE.js +++ b/packages/js/src/decorator/tinyMCE.js @@ -35,14 +35,27 @@ function markTinyMCE( editor, paper, marks ) { let html = editor.getContent(); html = markers.removeMarks( html ); + /* + * Get the information whether we want to mark a specific part of the HTML. If we do, `fieldsToMark` should return an array with that information. + * For example, [ "subehading" ] means that we only want to apply the markings in subheadings only, and not the other parts. + * `selectedHTML` is an array of the HTML parts that we want to apply the marking to. + */ const { fieldsToMark, selectedHTML } = languageProcessing.getFieldsToMark( marks, html ); // Generate marked HTML. forEach( marks, function( mark ) { + /* + * Classic editor uses double quotes for HTML attribute values. However, in `yoastseo`, we use single quotes for the attribute values + * when we create the marked object. As the result, the replacement did not work, as the marks passed by `yoastseo` did not match anything + * in the original text. This step is replacing the single quotes in the marked object output by `yoastseo` with double quotes. + * This way, we make sure that the replacement can find a match between the original text of the marked object and the text in the page. + */ mark._properties.marked = languageProcessing.replaceSingleQuotesInTags( mark._properties.marked ); mark._properties.original = languageProcessing.replaceSingleQuotesInTags( mark._properties.original ); + // Check if we want to mark only specific part of the HTML. if ( fieldsToMark.length > 0 ) { + // Apply the marking to the selected HTML parts. selectedHTML.forEach( element => { const markedElement = mark.applyWithReplace( element ); html = html.replace( element, markedElement ); From e723bfe3e874f3618808da0b3fbdfbc76d9f83d5 Mon Sep 17 00:00:00 2001 From: hdvos Date: Fri, 25 Nov 2022 17:01:29 +0100 Subject: [PATCH 11/19] fix bug that the word in the url is marked instead of the content of the html tag. --- .../helpers/word/markWordsInSentences.js | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 17b660d79cd..bb3d177546c 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -6,6 +6,34 @@ import Mark from "../../../values/Mark"; import { escapeRegExp } from "lodash-es"; import { stripFullTags } from "../sanitize/stripHTMLTags"; +// Regex to deconstruct an anchor into opentag, content an +const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; + +/** + * Deconstructs an anchor in the opening tag, the content and the closing tag. + * @param {string} anchor An anchor of the shape ... + * @returns {object} An object containing the opening tag, the content and the closing tag of the anchor. + */ +const deConstructAnchor = function( anchor ) { + const [ , openTag, content, closeTag ] = anchor.match( anchorDeconstructionRegex ); + return { + openTag: openTag, + content: content, + closeTag: closeTag, + }; +}; + +/** + * Reconstructs an anchor from an openTag, the content, and the closing tag. + * @param {string} openTag The opening tag of the anchor. Must be of the shape + * @param {string} content The text of the anchor. + * @returns {string} An anchor. + */ +const reConstructAnchor = function( openTag, content ) { + return `${openTag}${content}`; +}; + + /** * Gets the anchors and marks the anchors' text if the words are found in it. * @@ -21,10 +49,17 @@ const getMarkedAnchors = function( sentence, wordsRegex ) { const markedAnchors = anchors.map( anchor => { // Get the anchor text. const anchorText = stripFullTags( anchor ); + // Apply the marking to the anchor text. const markedAnchorText = anchorText.replace( wordsRegex, ( x ) => addMark( x ) ); // Replace the original anchor text with the marked anchor text. - return anchor.replace( anchorText, markedAnchorText ); + + const { openTag, content, closeTag } = deConstructAnchor( anchor ); + const newContent = content.replace( anchorText, markedAnchorText ); + const newAnchor = reConstructAnchor( openTag, newContent, closeTag ); + + return newAnchor; + // return anchor.replace( anchorText, markedAnchorText ); } ); return { anchors, markedAnchors }; }; From 1fcd588d4c9b05e5a11a299c9c45cd4eb9246ca9 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 28 Nov 2022 10:41:43 +0100 Subject: [PATCH 12/19] clean up code --- .../helpers/word/markWordsInSentences.js | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index bb3d177546c..4fe7b124c36 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -1,17 +1,19 @@ +import { escapeRegExp } from "lodash-es"; +import addMark from "../../../markers/addMarkSingleWord"; +import Mark from "../../../values/Mark"; import getAnchorsFromText from "../link/getAnchorsFromText"; import matchWords from "../match/matchTextWithArray"; import arrayToRegex from "../regex/createRegexFromArray"; -import addMark from "../../../markers/addMarkSingleWord"; -import Mark from "../../../values/Mark"; -import { escapeRegExp } from "lodash-es"; import { stripFullTags } from "../sanitize/stripHTMLTags"; -// Regex to deconstruct an anchor into opentag, content an +// Regex to deconstruct an anchor into open tag, content and close tag. const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; /** * Deconstructs an anchor in the opening tag, the content and the closing tag. - * @param {string} anchor An anchor of the shape ... + * + * @param {string} anchor An anchor of the shape .... + * * @returns {object} An object containing the opening tag, the content and the closing tag of the anchor. */ const deConstructAnchor = function( anchor ) { @@ -25,12 +27,15 @@ const deConstructAnchor = function( anchor ) { /** * Reconstructs an anchor from an openTag, the content, and the closing tag. - * @param {string} openTag The opening tag of the anchor. Must be of the shape + * + * @param {string} openTag The opening tag of the anchor. Must be of the shape . * @param {string} content The text of the anchor. + * @param {string} closeTag The closing tag of the anchor. Must be the shape of . + * * @returns {string} An anchor. */ -const reConstructAnchor = function( openTag, content ) { - return `${openTag}${content}`; +const reConstructAnchor = function( openTag, content, closeTag ) { + return `${openTag}${content}${closeTag}`; }; @@ -54,12 +59,10 @@ const getMarkedAnchors = function( sentence, wordsRegex ) { const markedAnchorText = anchorText.replace( wordsRegex, ( x ) => addMark( x ) ); // Replace the original anchor text with the marked anchor text. - const { openTag, content, closeTag } = deConstructAnchor( anchor ); + const { openTag, content, closeTag } = deConstructAnchor( anchor ); const newContent = content.replace( anchorText, markedAnchorText ); - const newAnchor = reConstructAnchor( openTag, newContent, closeTag ); - return newAnchor; - // return anchor.replace( anchorText, markedAnchorText ); + return reConstructAnchor( openTag, newContent, closeTag ); } ); return { anchors, markedAnchors }; }; From d1276964160df0a46ea415d50751e740d7d645e6 Mon Sep 17 00:00:00 2001 From: hdvos Date: Mon, 28 Nov 2022 11:46:32 +0100 Subject: [PATCH 13/19] add specs for reconstructAnchor and deconstructAnchor --- .../helpers/word/markWordsInSentenceSpec.js | 31 ++++++++++++++++++- .../helpers/word/markWordsInSentences.js | 6 ++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js index b655d7fb7dc..4e9775a5c14 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js @@ -1,4 +1,4 @@ -import { markWordsInSentences } from "../../../../src/languageProcessing/helpers/word/markWordsInSentences"; +import { deConstructAnchor, markWordsInSentences, reConstructAnchor } from "../../../../src/languageProcessing/helpers/word/markWordsInSentences"; import Mark from "../../../../src/values/Mark"; import matchWordCustomHelper from "../../../../src/languageProcessing/languages/ja/helpers/matchTextWithWord"; @@ -142,3 +142,32 @@ describe( "Adds Yoast marks to specific words in a sentence for languages with c } ); } ); +describe( "test the deconstructAnchor and reconstructAnchor helper", () => { + it( "correctly deconstructs and reconstructs an anchor.", () => { + const testAnchor = "This is yoast."; + const deconstructedAnchor = deConstructAnchor( testAnchor ); + + expect( deconstructedAnchor ).toEqual( { + openTag: "", + content: "This is yoast.", + closeTag: "", + } ); + + const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content, deconstructedAnchor.closeTag ); + expect( reconstructedAnchor ).toEqual( testAnchor ); + } ); + + it( "it correctly deconstructs and reconstructs an anchor that contains html elements itself", () => { + const testAnchor = "This is yoast."; + const deconstructedAnchor = deConstructAnchor( testAnchor ); + + expect( deconstructedAnchor ).toEqual( { + openTag: "", + content: "This is yoast.", + closeTag: "", + } ); + + const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content, deconstructedAnchor.closeTag ); + expect( reconstructedAnchor ).toEqual( testAnchor ); + } ); +} ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 4fe7b124c36..81fc5157499 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -10,13 +10,13 @@ import { stripFullTags } from "../sanitize/stripHTMLTags"; const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; /** - * Deconstructs an anchor in the opening tag, the content and the closing tag. + * Deconstructs an anchor to the opening tag, the content and the closing tag. * * @param {string} anchor An anchor of the shape .... * * @returns {object} An object containing the opening tag, the content and the closing tag of the anchor. */ -const deConstructAnchor = function( anchor ) { +export const deConstructAnchor = function( anchor ) { const [ , openTag, content, closeTag ] = anchor.match( anchorDeconstructionRegex ); return { openTag: openTag, @@ -34,7 +34,7 @@ const deConstructAnchor = function( anchor ) { * * @returns {string} An anchor. */ -const reConstructAnchor = function( openTag, content, closeTag ) { +export const reConstructAnchor = function( openTag, content, closeTag = "" ) { return `${openTag}${content}${closeTag}`; }; From 850941a3a6e544b2d06bdd6aa29ac0e338891f03 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 28 Nov 2022 12:13:17 +0100 Subject: [PATCH 14/19] simplify code --- .../helpers/word/markWordsInSentences.js | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 4fe7b124c36..4e17fd70f30 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -4,24 +4,23 @@ import Mark from "../../../values/Mark"; import getAnchorsFromText from "../link/getAnchorsFromText"; import matchWords from "../match/matchTextWithArray"; import arrayToRegex from "../regex/createRegexFromArray"; -import { stripFullTags } from "../sanitize/stripHTMLTags"; // Regex to deconstruct an anchor into open tag, content and close tag. const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; /** - * Deconstructs an anchor in the opening tag, the content and the closing tag. + * Deconstructs an anchor in the opening tag and the content. The content is the anchor text. + * We don't return the closing tag since the value would always be the same, i.e. . * * @param {string} anchor An anchor of the shape .... * - * @returns {object} An object containing the opening tag, the content and the closing tag of the anchor. + * @returns {object} An object containing the opening tag and the content. */ const deConstructAnchor = function( anchor ) { - const [ , openTag, content, closeTag ] = anchor.match( anchorDeconstructionRegex ); + const [ , openTag, content ] = anchor.match( anchorDeconstructionRegex ); return { openTag: openTag, content: content, - closeTag: closeTag, }; }; @@ -30,12 +29,11 @@ const deConstructAnchor = function( anchor ) { * * @param {string} openTag The opening tag of the anchor. Must be of the shape . * @param {string} content The text of the anchor. - * @param {string} closeTag The closing tag of the anchor. Must be the shape of . * * @returns {string} An anchor. */ -const reConstructAnchor = function( openTag, content, closeTag ) { - return `${openTag}${content}${closeTag}`; +const reConstructAnchor = function( openTag, content ) { + return `${openTag}${content}`; }; @@ -50,20 +48,18 @@ const reConstructAnchor = function( openTag, content, closeTag ) { const getMarkedAnchors = function( sentence, wordsRegex ) { // Retrieve the anchors. const anchors = getAnchorsFromText( sentence ); - // For every anchor, apply the markings only to the anchor tag. Replace the unmarked anchor in the sentence with the marked anchor. + // For every anchor, apply the markings only to the anchor tag. const markedAnchors = anchors.map( anchor => { - // Get the anchor text. - const anchorText = stripFullTags( anchor ); + // Retrieve the open tag and the content/anchor text. + const { openTag, content } = deConstructAnchor( anchor ); // Apply the marking to the anchor text. - const markedAnchorText = anchorText.replace( wordsRegex, ( x ) => addMark( x ) ); - // Replace the original anchor text with the marked anchor text. + const markedAnchorText = content.replace( wordsRegex, ( x ) => addMark( x ) ); - const { openTag, content, closeTag } = deConstructAnchor( anchor ); - const newContent = content.replace( anchorText, markedAnchorText ); - - return reConstructAnchor( openTag, newContent, closeTag ); + // Create a new anchor tag with a marked anchor text if there is a match. + return reConstructAnchor( openTag, markedAnchorText ); } ); + return { anchors, markedAnchors }; }; From 8940fed3c4e0120172058bb0aa74f474ad6f72a6 Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 28 Nov 2022 12:20:56 +0100 Subject: [PATCH 15/19] Adjust unit tests --- .../helpers/word/markWordsInSentenceSpec.js | 6 ++---- .../languageProcessing/helpers/word/markWordsInSentences.js | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js index 4e9775a5c14..b1bc22761c1 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js @@ -150,10 +150,9 @@ describe( "test the deconstructAnchor and reconstructAnchor helper", () => { expect( deconstructedAnchor ).toEqual( { openTag: "", content: "This is yoast.", - closeTag: "", } ); - const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content, deconstructedAnchor.closeTag ); + const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content ); expect( reconstructedAnchor ).toEqual( testAnchor ); } ); @@ -164,10 +163,9 @@ describe( "test the deconstructAnchor and reconstructAnchor helper", () => { expect( deconstructedAnchor ).toEqual( { openTag: "", content: "This is yoast.", - closeTag: "", } ); - const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content, deconstructedAnchor.closeTag ); + const reconstructedAnchor = reConstructAnchor( deconstructedAnchor.openTag, deconstructedAnchor.content ); expect( reconstructedAnchor ).toEqual( testAnchor ); } ); } ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 4e17fd70f30..69c85081fb5 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -9,14 +9,14 @@ import arrayToRegex from "../regex/createRegexFromArray"; const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; /** - * Deconstructs an anchor in the opening tag and the content. The content is the anchor text. + * Deconstructs an anchor to the opening tag and the content. The content is the anchor text. * We don't return the closing tag since the value would always be the same, i.e. . * * @param {string} anchor An anchor of the shape .... * * @returns {object} An object containing the opening tag and the content. */ -const deConstructAnchor = function( anchor ) { +export const deConstructAnchor = function( anchor ) { const [ , openTag, content ] = anchor.match( anchorDeconstructionRegex ); return { openTag: openTag, @@ -32,7 +32,7 @@ const deConstructAnchor = function( anchor ) { * * @returns {string} An anchor. */ -const reConstructAnchor = function( openTag, content ) { +export const reConstructAnchor = function( openTag, content ) { return `${openTag}${content}`; }; From 9de0715855b874834e6294188cb64de6b596a93c Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 28 Nov 2022 12:23:26 +0100 Subject: [PATCH 16/19] adjust test description --- .../helpers/word/markWordsInSentenceSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js index b1bc22761c1..1fc5049810e 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js @@ -143,7 +143,7 @@ describe( "Adds Yoast marks to specific words in a sentence for languages with c } ); describe( "test the deconstructAnchor and reconstructAnchor helper", () => { - it( "correctly deconstructs and reconstructs an anchor.", () => { + it( "correctly deconstructs and reconstructs an anchor", () => { const testAnchor = "This is yoast."; const deconstructedAnchor = deConstructAnchor( testAnchor ); @@ -156,7 +156,7 @@ describe( "test the deconstructAnchor and reconstructAnchor helper", () => { expect( reconstructedAnchor ).toEqual( testAnchor ); } ); - it( "it correctly deconstructs and reconstructs an anchor that contains html elements itself", () => { + it( "correctly deconstructs and reconstructs an anchor that contains html elements itself", () => { const testAnchor = "This is yoast."; const deconstructedAnchor = deConstructAnchor( testAnchor ); From 71a14c38c92f7a25eda7ccf9de58d3916f9fb00c Mon Sep 17 00:00:00 2001 From: FAMarfuaty Date: Mon, 28 Nov 2022 12:33:21 +0100 Subject: [PATCH 17/19] adjust comment --- .../languageProcessing/helpers/word/markWordsInSentences.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index 69c85081fb5..a5eb78a0f85 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -53,10 +53,10 @@ const getMarkedAnchors = function( sentence, wordsRegex ) { // Retrieve the open tag and the content/anchor text. const { openTag, content } = deConstructAnchor( anchor ); - // Apply the marking to the anchor text. + // Apply the marking to the anchor text if there is a match. const markedAnchorText = content.replace( wordsRegex, ( x ) => addMark( x ) ); - // Create a new anchor tag with a marked anchor text if there is a match. + // Create a new anchor tag with a (marked) anchor text. return reConstructAnchor( openTag, markedAnchorText ); } ); From 51f0f99ee0e9d6a6a2e0d0514bce8c94bdb29e07 Mon Sep 17 00:00:00 2001 From: iolandasequino Date: Wed, 30 Nov 2022 18:03:40 +0100 Subject: [PATCH 18/19] edit typos in comments --- packages/js/src/decorator/tinyMCE.js | 4 ++-- .../spec/languageProcessing/helpers/html/replaceQuotesSpec.js | 2 +- .../src/languageProcessing/helpers/html/getFieldsToMark.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/js/src/decorator/tinyMCE.js b/packages/js/src/decorator/tinyMCE.js index 8aee47d2c92..fc5322f3596 100644 --- a/packages/js/src/decorator/tinyMCE.js +++ b/packages/js/src/decorator/tinyMCE.js @@ -37,7 +37,7 @@ function markTinyMCE( editor, paper, marks ) { /* * Get the information whether we want to mark a specific part of the HTML. If we do, `fieldsToMark` should return an array with that information. - * For example, [ "subehading" ] means that we only want to apply the markings in subheadings only, and not the other parts. + * For example, [ "subehading" ] means that we want to apply the markings in subheadings only, and not the other parts. * `selectedHTML` is an array of the HTML parts that we want to apply the marking to. */ const { fieldsToMark, selectedHTML } = languageProcessing.getFieldsToMark( marks, html ); @@ -46,7 +46,7 @@ function markTinyMCE( editor, paper, marks ) { forEach( marks, function( mark ) { /* * Classic editor uses double quotes for HTML attribute values. However, in `yoastseo`, we use single quotes for the attribute values - * when we create the marked object. As the result, the replacement did not work, as the marks passed by `yoastseo` did not match anything + * when we create the marked object. As a result, the replacement did not work, as the marks passed by `yoastseo` did not match anything * in the original text. This step is replacing the single quotes in the marked object output by `yoastseo` with double quotes. * This way, we make sure that the replacement can find a match between the original text of the marked object and the text in the page. */ diff --git a/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js index c0899a9545d..a6545bc8b84 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/html/replaceQuotesSpec.js @@ -12,7 +12,7 @@ describe( "replace-quotes", function() { .toEqual( "This is a test" ); } ); - it( "should not replace single quotes outside HTML tags", function() { + it( "should not replace single quotes (or apostrophes) outside HTML tags", function() { expect( replaceSingleQuotesInTags( "This is a test, let's go!" ) ) .toEqual( "This is a test, let's go!" ); } ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/html/getFieldsToMark.js b/packages/yoastseo/src/languageProcessing/helpers/html/getFieldsToMark.js index be770388e95..04783418366 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/html/getFieldsToMark.js +++ b/packages/yoastseo/src/languageProcessing/helpers/html/getFieldsToMark.js @@ -7,7 +7,7 @@ import { getSubheadings } from "./getSubheadings"; * @param {array} marks The array of mark objects. * @param {string} html The html of the page where we want to apply the marking to. * - * @returns {{selectedHTML: *[], fieldsToMark: *}} The selected part of the html we want to apply the marking tp. + * @returns {{selectedHTML: *[], fieldsToMark: *}} The selected part of the html we want to apply the marking to. */ export function getFieldsToMark( marks, html ) { const fieldsToMark = uniq( flatten( marks.map( mark => { From deef45072655177368c85195b5428b88f9cb01b3 Mon Sep 17 00:00:00 2001 From: iolandasequino Date: Thu, 1 Dec 2022 12:53:07 +0100 Subject: [PATCH 19/19] edit function documentation to add clarity --- packages/js/src/decorator/tinyMCE.js | 7 ++++--- .../helpers/word/markWordsInSentences.js | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/js/src/decorator/tinyMCE.js b/packages/js/src/decorator/tinyMCE.js index fc5322f3596..c3f2b8b4b31 100644 --- a/packages/js/src/decorator/tinyMCE.js +++ b/packages/js/src/decorator/tinyMCE.js @@ -45,9 +45,10 @@ function markTinyMCE( editor, paper, marks ) { // Generate marked HTML. forEach( marks, function( mark ) { /* - * Classic editor uses double quotes for HTML attribute values. However, in `yoastseo`, we use single quotes for the attribute values - * when we create the marked object. As a result, the replacement did not work, as the marks passed by `yoastseo` did not match anything - * in the original text. This step is replacing the single quotes in the marked object output by `yoastseo` with double quotes. + * Classic editor uses double quotes for HTML attribute values. However, Block editor uses single quotes for HTML tag attributes, + * and that's why in `yoastseo`, we use single quotes for the attribute values when we create the marked object. As a result, + * the replacement did not work, as the marks passed by `yoastseo` did not match anything in the original text. + * This step is replacing the single quotes in the marked object output by `yoastseo` with double quotes. * This way, we make sure that the replacement can find a match between the original text of the marked object and the text in the page. */ mark._properties.marked = languageProcessing.replaceSingleQuotesInTags( mark._properties.marked ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js index a5eb78a0f85..b6252dd1264 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/markWordsInSentences.js @@ -17,6 +17,7 @@ const anchorDeconstructionRegex = /(]+>)(.+?)(<\/a>)/; * @returns {object} An object containing the opening tag and the content. */ export const deConstructAnchor = function( anchor ) { + // The const array mirrors the anchorDeconstructionRegex, using a comma to access the first element without a name. const [ , openTag, content ] = anchor.match( anchorDeconstructionRegex ); return { openTag: openTag,