1- import matchWords from "../match/matchTextWithArray" ;
2- import arrayToRegex from "../regex/createRegexFromArray" ;
1+ import { escapeRegExp } from "lodash-es" ;
32import addMark from "../../../markers/addMarkSingleWord" ;
43import Mark from "../../../values/Mark" ;
5- import { escapeRegExp } from "lodash-es" ;
4+ import getAnchorsFromText from "../link/getAnchorsFromText" ;
5+ import matchWords from "../match/matchTextWithArray" ;
6+ import arrayToRegex from "../regex/createRegexFromArray" ;
7+
8+ // Regex to deconstruct an anchor into open tag, content and close tag.
9+ const anchorDeconstructionRegex = / ( < a [ \s ] + [ ^ > ] + > ) ( .+ ?) ( < \/ a > ) / ;
10+
11+ /**
12+ * Deconstructs an anchor to the opening tag and the content. The content is the anchor text.
13+ * We don't return the closing tag since the value would always be the same, i.e. </a>.
14+ *
15+ * @param {string } anchor An anchor of the shape <a ...>...</a>.
16+ *
17+ * @returns {object } An object containing the opening tag and the content.
18+ */
19+ export const deConstructAnchor = function ( anchor ) {
20+ // The const array mirrors the anchorDeconstructionRegex, using a comma to access the first element without a name.
21+ const [ , openTag , content ] = anchor . match ( anchorDeconstructionRegex ) ;
22+ return {
23+ openTag : openTag ,
24+ content : content ,
25+ } ;
26+ } ;
27+
28+ /**
29+ * Reconstructs an anchor from an openTag, the content, and the closing tag.
30+ *
31+ * @param {string } openTag The opening tag of the anchor. Must be of the shape <a ...>.
32+ * @param {string } content The text of the anchor.
33+ *
34+ * @returns {string } An anchor.
35+ */
36+ export const reConstructAnchor = function ( openTag , content ) {
37+ return `${ openTag } ${ content } </a>` ;
38+ } ;
39+
40+
41+ /**
42+ * Gets the anchors and marks the anchors' text if the words are found in it.
43+ *
44+ * @param {string } sentence The sentence to retrieve the anchors from.
45+ * @param {RegExp } wordsRegex The regex of the words.
46+ *
47+ * @returns {Object } The anchors and the marked anchors.
48+ */
49+ const getMarkedAnchors = function ( sentence , wordsRegex ) {
50+ // Retrieve the anchors.
51+ const anchors = getAnchorsFromText ( sentence ) ;
52+ // For every anchor, apply the markings only to the anchor tag.
53+ const markedAnchors = anchors . map ( anchor => {
54+ // Retrieve the open tag and the content/anchor text.
55+ const { openTag, content } = deConstructAnchor ( anchor ) ;
56+
57+ // Apply the marking to the anchor text if there is a match.
58+ const markedAnchorText = content . replace ( wordsRegex , ( x ) => addMark ( x ) ) ;
59+
60+ // Create a new anchor tag with a (marked) anchor text.
61+ return reConstructAnchor ( openTag , markedAnchorText ) ;
62+ } ) ;
63+
64+ return { anchors, markedAnchors } ;
65+ } ;
666
767/**
868 * Adds marks to a sentence and merges marks if those are only separated by a space
969 * (e.g., if highlighting words "ballet" and "shoes" in a sentence "I have a lot of ballet shoes and other paraphernalia."
1070 * the marks will be put around "ballet shoes" together, not "`ballet` `shoes`".)
1171 *
1272 * @param {string } sentence The sentence to mark words in.
13- * @param {[string] } topicFoundInSentence The words to mark in the sentence.
73+ * @param {[string] } wordsFoundInSentence The words to mark in the sentence.
1474 * @param {function } matchWordCustomHelper The language-specific helper function to match word in text.
1575 *
1676 * @returns {string } The sentence with marks.
1777 */
18- export const collectMarkingsInSentence = function ( sentence , topicFoundInSentence , matchWordCustomHelper ) {
19- topicFoundInSentence = topicFoundInSentence . map ( word => escapeRegExp ( word ) ) ;
78+ export const collectMarkingsInSentence = function ( sentence , wordsFoundInSentence , matchWordCustomHelper ) {
79+ wordsFoundInSentence = wordsFoundInSentence . map ( word => escapeRegExp ( word ) ) ;
2080 // If a language has a custom helper to match words, we disable the word boundary when creating the regex.
21- const topicRegex = matchWordCustomHelper ? arrayToRegex ( topicFoundInSentence , true ) : arrayToRegex ( topicFoundInSentence ) ;
22- const markup = sentence . replace ( topicRegex , function ( x ) {
81+ const wordsRegex = matchWordCustomHelper ? arrayToRegex ( wordsFoundInSentence , true ) : arrayToRegex ( wordsFoundInSentence ) ;
82+
83+ // Retrieve the anchors and mark the anchors' text if the words are found in the anchors' text.
84+ const { anchors, markedAnchors } = getMarkedAnchors ( sentence , wordsRegex ) ;
85+
86+ let markup = sentence . replace ( wordsRegex , function ( x ) {
2387 return addMark ( x ) ;
2488 } ) ;
2589
90+ /**
91+ * In 'markup', we apply the markings also inside the anchor's attribute if there is a match, on top of
92+ * marking the anchor's text.
93+ * The step below is to replace the incorrectly marked anchors with the marked anchors that we want:
94+ * where the markings are only applied in the anchor's text.
95+ */
96+ if ( anchors . length > 0 ) {
97+ const markupAnchors = getAnchorsFromText ( markup ) ;
98+ for ( let i = 0 ; i < markupAnchors . length ; i ++ ) {
99+ markup = markup . replace ( markupAnchors [ i ] , markedAnchors [ i ] ) ;
100+ }
101+ }
102+
103+ /*
104+ * If two marks are separated by only a space, remove the closing tag of the first mark and the opening tag of the
105+ * second mark so that the two marks can be combined into one.
106+ */
26107 return ( markup . replace ( new RegExp ( "</yoastmark> <yoastmark class='yoast-text-mark'>" , "ig" ) , " " ) ) ;
27108} ;
28109
@@ -37,16 +118,16 @@ export const collectMarkingsInSentence = function( sentence, topicFoundInSentenc
37118 * @returns {[string] } The sentences with marks.
38119 */
39120export function markWordsInSentences ( wordsToMark , sentences , locale , matchWordCustomHelper ) {
40- let topicFoundInSentence = [ ] ;
121+ let wordsFoundInSentence = [ ] ;
41122 let markings = [ ] ;
42123
43124 sentences . forEach ( function ( sentence ) {
44- topicFoundInSentence = matchWords ( sentence , wordsToMark , locale , matchWordCustomHelper ) . matches ;
125+ wordsFoundInSentence = matchWords ( sentence , wordsToMark , locale , matchWordCustomHelper ) . matches ;
45126
46- if ( topicFoundInSentence . length > 0 ) {
127+ if ( wordsFoundInSentence . length > 0 ) {
47128 markings = markings . concat ( new Mark ( {
48129 original : sentence ,
49- marked : collectMarkingsInSentence ( sentence , topicFoundInSentence , matchWordCustomHelper ) ,
130+ marked : collectMarkingsInSentence ( sentence , wordsFoundInSentence , matchWordCustomHelper ) ,
50131 } ) ) ;
51132 }
52133 } ) ;
0 commit comments