1
- import { registerBidder } from '../src/adapters/bidderFactory.js' ;
1
+ import { registerBidder } from '../src/adapters/bidderFactory.js' ;
2
2
import { getStorageManager } from '../src/storageManager.js' ;
3
3
import { includes } from '../src/polyfill.js' ;
4
4
import { BANNER , VIDEO } from '../src/mediaTypes.js' ;
5
5
6
- const VERSION = '3.2 ' ;
6
+ const VERSION = '3.6 ' ;
7
7
const BAD_WORD_STEP = 0.1 ;
8
8
const BAD_WORD_MIN = 0.2 ;
9
9
const ADHASH_BIDDER_CODE = 'adhash' ;
@@ -19,6 +19,8 @@ const ADHASH_BIDDER_CODE = 'adhash';
19
19
* @returns boolean flag is the page safe
20
20
*/
21
21
function brandSafety ( badWords , maxScore ) {
22
+ const delimiter = '~' ;
23
+
22
24
/**
23
25
* Performs the ROT13 encoding on the string argument and returns the resulting string.
24
26
* The Adhash bidder uses ROT13 so that the response is not blocked by:
@@ -40,17 +42,17 @@ function brandSafety(badWords, maxScore) {
40
42
/**
41
43
* Calculates the scoring for each bad word with dimishing returns
42
44
* @param {integer } points points that this word costs
43
- * @param {integer } occurances number of occurances
45
+ * @param {integer } occurrences number of occurrences
44
46
* @returns {float } final score
45
47
*/
46
- const scoreCalculator = ( points , occurances ) => {
48
+ const scoreCalculator = ( points , occurrences ) => {
47
49
let positive = true ;
48
50
if ( points < 0 ) {
49
51
points *= - 1 ;
50
52
positive = false ;
51
53
}
52
54
let result = 0 ;
53
- for ( let i = 0 ; i < occurances ; i ++ ) {
55
+ for ( let i = 0 ; i < occurrences ; i ++ ) {
54
56
result += Math . max ( points - i * BAD_WORD_STEP , BAD_WORD_MIN ) ;
55
57
}
56
58
return positive ? result : - result ;
@@ -60,22 +62,50 @@ function brandSafety(badWords, maxScore) {
60
62
* Checks what rule will match in the given array with words
61
63
* @param {string } rule rule type (full, partial, starts, ends, regexp)
62
64
* @param {string } decodedWord decoded word
63
- * @param {array } wordsToMatch array to find a match
65
+ * @param {string } wordsToMatch list of all words on the page separated by delimiters
64
66
* @returns {object|boolean } matched rule and occurances. If nothing is matched returns false
65
67
*/
66
68
const wordsMatchedWithRule = function ( rule , decodedWord , wordsToMatch ) {
67
- if ( rule === 'full' && wordsToMatch && wordsToMatch . includes ( decodedWord ) ) {
68
- return { rule, occurances : wordsToMatch . filter ( element => element === decodedWord ) . length } ;
69
- } else if ( rule === 'partial' && wordsToMatch && wordsToMatch . some ( element => element . indexOf ( decodedWord ) > - 1 ) ) {
70
- return { rule, occurances : wordsToMatch . filter ( element => element . indexOf ( decodedWord ) > - 1 ) . length } ;
71
- } else if ( rule === 'starts' && wordsToMatch && wordsToMatch . some ( word => word . startsWith ( decodedWord ) ) ) {
72
- return { rule, occurances : wordsToMatch . filter ( element => element . startsWith ( decodedWord ) ) . length } ;
73
- } else if ( rule === 'ends' && wordsToMatch && wordsToMatch . some ( word => word . endsWith ( decodedWord ) ) ) {
74
- return { rule, occurances : wordsToMatch . filter ( element => element . endsWith ( decodedWord ) ) . length } ;
75
- } else if ( rule === 'regexp' && wordsToMatch && wordsToMatch . some ( element => element . match ( new RegExp ( decodedWord , 'i' ) ) ) ) {
76
- return { rule, occurances : wordsToMatch . filter ( element => element . match ( new RegExp ( decodedWord , 'i' ) ) ) . length } ;
69
+ if ( ! wordsToMatch ) {
70
+ return false ;
71
+ }
72
+
73
+ let occurrences ;
74
+ let adjustedWordToMatch ;
75
+ decodedWord = decodedWord . split ( ' ' ) . join ( `${ delimiter } ${ delimiter } ` ) ;
76
+ switch ( rule ) {
77
+ case 'full' :
78
+ adjustedWordToMatch = `${ delimiter } ${ decodedWord } ${ delimiter } ` ;
79
+ break ;
80
+ case 'partial' :
81
+ adjustedWordToMatch = decodedWord ;
82
+ break ;
83
+ case 'starts' :
84
+ adjustedWordToMatch = `${ delimiter } ${ decodedWord } ` ;
85
+ break ;
86
+ case 'ends' :
87
+ adjustedWordToMatch = `${ decodedWord } ${ delimiter } ` ;
88
+ break ;
89
+ case 'combo' :
90
+ const allOccurrences = [ ] ;
91
+ const paddedWordsToMatch = `${ delimiter } ${ wordsToMatch } ${ delimiter } ` ;
92
+ const decodedWordsSplit = decodedWord . split ( `${ delimiter } ${ delimiter } ` ) ;
93
+ for ( const decodedWordPart of decodedWordsSplit ) {
94
+ adjustedWordToMatch = `${ delimiter } ${ decodedWordPart } ${ delimiter } ` ;
95
+ allOccurrences . push ( paddedWordsToMatch . split ( adjustedWordToMatch ) . length - 1 ) ;
96
+ }
97
+ occurrences = Math . min ( ...allOccurrences ) ;
98
+ return occurrences > 0 ? { rule, occurrences } : false ;
99
+ case 'regexp' :
100
+ occurrences = [ ...wordsToMatch . matchAll ( new RegExp ( decodedWord , 'gi' ) ) ] . length ;
101
+ return occurrences > 0 ? { rule, occurrences } : false ;
102
+ default :
103
+ return false ;
77
104
}
78
- return false ;
105
+
106
+ const paddedWordsToMatch = `${ delimiter } ${ wordsToMatch } ${ delimiter } ` ;
107
+ occurrences = paddedWordsToMatch . split ( adjustedWordToMatch ) . length - 1 ;
108
+ return occurrences > 0 ? { rule, occurrences } : false ;
79
109
} ;
80
110
81
111
// Default parameters if the bidder is unable to send some of them
@@ -91,11 +121,11 @@ function brandSafety(badWords, maxScore) {
91
121
. toLowerCase ( )
92
122
. trim ( ) ;
93
123
const content = window . top . document . body . innerText . toLowerCase ( ) ;
94
- const contentWords = content . trim ( ) . split ( / \s + / ) . length ;
95
124
// \p{L} matches a single unicode code point in the category 'letter'. Matches any kind of letter from any language.
96
125
const regexp = new RegExp ( '[\\p{L}]+' , 'gu' ) ;
97
- const words = content . match ( regexp ) ;
98
- const wordsInUrl = wordsAndNumbersInUrl . match ( regexp ) ;
126
+ const wordsMatched = content . match ( regexp ) ;
127
+ const words = wordsMatched . join ( `${ delimiter } ${ delimiter } ` ) ;
128
+ const wordsInUrl = wordsAndNumbersInUrl . match ( regexp ) . join ( `${ delimiter } ${ delimiter } ` ) ;
99
129
100
130
for ( const [ word , rule , points ] of badWords ) {
101
131
const decodedWord = rot13 ( word . toLowerCase ( ) ) ;
@@ -110,19 +140,11 @@ function brandSafety(badWords, maxScore) {
110
140
111
141
// Check if site content's words match any of our brand safety rules
112
142
const matchedRule = wordsMatchedWithRule ( rule , decodedWord , words ) ;
113
- if ( matchedRule . rule === 'full' ) {
114
- score += scoreCalculator ( points , matchedRule . occurances ) ;
115
- } else if ( matchedRule . rule === 'partial' ) {
116
- score += scoreCalculator ( points , matchedRule . occurances ) ;
117
- } else if ( matchedRule . rule === 'starts' ) {
118
- score += scoreCalculator ( points , matchedRule . occurances ) ;
119
- } else if ( matchedRule . rule === 'ends' ) {
120
- score += scoreCalculator ( points , matchedRule . occurances ) ;
121
- } else if ( matchedRule . rule === 'regexp' ) {
122
- score += scoreCalculator ( points , matchedRule . occurances ) ;
143
+ if ( matchedRule !== false ) {
144
+ score += scoreCalculator ( points , matchedRule . occurrences ) ;
123
145
}
124
146
}
125
- return score < ( maxScore * contentWords ) / 1000 ;
147
+ return score < ( maxScore * wordsMatched . length ) / 1000 ;
126
148
} catch ( e ) {
127
149
return true ;
128
150
}
@@ -183,8 +205,8 @@ export const spec = {
183
205
}
184
206
185
207
// Needed for the ad density calculation
186
- var adHeight = validBidRequests [ i ] . sizes [ index ] [ 1 ] ;
187
- var adWidth = validBidRequests [ i ] . sizes [ index ] [ 0 ] ;
208
+ const adHeight = validBidRequests [ i ] . sizes [ index ] [ 1 ] ;
209
+ const adWidth = validBidRequests [ i ] . sizes [ index ] [ 0 ] ;
188
210
if ( ! window . adsCount ) {
189
211
window . adsCount = 0 ;
190
212
}
@@ -247,7 +269,7 @@ export const spec = {
247
269
const bidderResponse = JSON . stringify ( { responseText : JSON . stringify ( responseBody ) } ) ;
248
270
const requestData = JSON . stringify ( request . data ) ;
249
271
250
- var response = {
272
+ let response = {
251
273
requestId : request . bidRequest . bidId ,
252
274
cpm : responseBody . creatives [ 0 ] . costEUR ,
253
275
width : request . bidRequest . sizes [ 0 ] [ 0 ] ,
0 commit comments