Advanced Ads - Version 1.20.3

Version Description

  • whitelist field groups created by Advanced Custom Fields on the ad edit page
  • prevent including AdSense Auto ads code when the Borlabs Cookie is already adding it
  • prevented adding unneeded escape characters to ads.txt file
  • added compatibility with Funding Choices when consent is not needed
Download this release

Release Info

Developer advancedads
Plugin Icon 128x128 Advanced Ads
Version 1.20.3
Comparing to
See all releases

Code changes from version 1.20.2 to 1.20.3

admin/assets/css/admin.css CHANGED
@@ -191,7 +191,6 @@ select + .advads-conditions-single { padding-left: 10px }
191
  .advads-option > span + div select { vertical-align: top; }
192
  .advads-option > div > .description { max-width: 80%; }
193
  .advads-option + .advads-option { margin-top: 20px; }
194
- .advads-option input, .advads-option select { background: transparent; }
195
 
196
  .advads-placements-table .advads-option > span { padding: 0; }
197
  .advads-placements-table .advads-option > span + div { padding: 0; }
191
  .advads-option > span + div select { vertical-align: top; }
192
  .advads-option > div > .description { max-width: 80%; }
193
  .advads-option + .advads-option { margin-top: 20px; }
 
194
 
195
  .advads-placements-table .advads-option > span { padding: 0; }
196
  .advads-placements-table .advads-option > span + div { padding: 0; }
advanced-ads.php CHANGED
@@ -12,7 +12,7 @@
12
  * Plugin Name: Advanced Ads
13
  * Plugin URI: https://wpadvancedads.com
14
  * Description: Manage and optimize your ads in WordPress
15
- * Version: 1.20.2
16
  * Author: Thomas Maier, Advanced Ads GmbH
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
@@ -39,7 +39,7 @@ define( 'ADVADS_BASE_DIR', dirname( ADVADS_BASE ) ); // directory of the plugin
39
  // general and global slug, e.g. to store options in WP.
40
  define( 'ADVADS_SLUG', 'advanced-ads' );
41
  define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
42
- define( 'ADVADS_VERSION', '1.20.2' );
43
 
44
  // Autoloading, modules and functions.
45
 
12
  * Plugin Name: Advanced Ads
13
  * Plugin URI: https://wpadvancedads.com
14
  * Description: Manage and optimize your ads in WordPress
15
+ * Version: 1.20.3
16
  * Author: Thomas Maier, Advanced Ads GmbH
17
  * Author URI: https://wpadvancedads.com
18
  * Text Domain: advanced-ads
39
  // general and global slug, e.g. to store options in WP.
40
  define( 'ADVADS_SLUG', 'advanced-ads' );
41
  define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
42
+ define( 'ADVADS_VERSION', '1.20.3' );
43
 
44
  // Autoloading, modules and functions.
45
 
classes/compatibility.php CHANGED
@@ -30,16 +30,25 @@ class Advanced_Ads_Compatibility {
30
  // Add shortcode for MailPoet.
31
  add_filter( 'mailpoet_newsletter_shortcode', array( $this, 'mailpoet_ad_shortcode' ), 10, 5 );
32
 
 
 
 
 
 
33
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_dequeue_scripts_and_styles' ), 100 );
 
 
 
 
 
34
  }
35
 
36
  /**
37
  * Modify xPath expression for Elementor plugin.
38
  * The plugin does not wrap newly created text in 'p' tags.
39
  *
40
- * @param str $tag xpath tag.
41
- *
42
- * @return xPath expression
43
  */
44
  public function content_injection_elementor( $tag ) {
45
  if ( 'p' === $tag ) {
@@ -56,7 +65,6 @@ class Advanced_Ads_Compatibility {
56
  * the code that depends on this function into the footer.
57
  *
58
  * @param array $pattern Patterns to match in inline JS content.
59
- *
60
  * @return array
61
  */
62
  public function exclude_inline_js( $pattern ) {
@@ -70,7 +78,6 @@ class Advanced_Ads_Compatibility {
70
  * show only all languages in language switcher on Advanced Ads pages if ads and groups are translated
71
  *
72
  * @param array $active_languages languages that can be used in language switcher.
73
- *
74
  * @return array
75
  */
76
  public function wpml_language_switcher( $active_languages ) {
@@ -106,8 +113,8 @@ class Advanced_Ads_Compatibility {
106
  *
107
  * @param array $url Array of URL parts.
108
  * @param string $type URL type.
109
- * @param obj $post WP_Post object of attachment.
110
- * @return array/bool Unmodified array of URL parts or false to remove URL.
111
  */
112
  public function wordpress_seo_noindex_ad_attachments( $url, $type, $post ) {
113
  if ( 'post' !== $type ) {
@@ -212,4 +219,102 @@ class Advanced_Ads_Compatibility {
212
  wp_dequeue_style( 'jnews-admin' );
213
  }
214
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  }
30
  // Add shortcode for MailPoet.
31
  add_filter( 'mailpoet_newsletter_shortcode', array( $this, 'mailpoet_ad_shortcode' ), 10, 5 );
32
 
33
+ // Enable Advanced Custom Fields on ad edit pages.
34
+ if ( class_exists( 'ACF', false ) ) {
35
+ add_filter( 'advanced-ads-ad-edit-allowed-metaboxes', array( $this, 'advanced_custom_fields_box' ) );
36
+ }
37
+
38
  add_action( 'admin_enqueue_scripts', array( $this, 'admin_dequeue_scripts_and_styles' ), 100 );
39
+
40
+ if ( defined( 'BORLABS_COOKIE_VERSION' ) ) {
41
+ // Check if Verification code & Auto ads ads can be displayed.
42
+ add_filter( 'advanced-ads-can-display-ads-in-header', array( $this, 'borlabs_cookie_can_add_auto_ads_code' ), 10 );
43
+ }
44
  }
45
 
46
  /**
47
  * Modify xPath expression for Elementor plugin.
48
  * The plugin does not wrap newly created text in 'p' tags.
49
  *
50
+ * @param string $tag xpath tag.
51
+ * @return string xPath expression
 
52
  */
53
  public function content_injection_elementor( $tag ) {
54
  if ( 'p' === $tag ) {
65
  * the code that depends on this function into the footer.
66
  *
67
  * @param array $pattern Patterns to match in inline JS content.
 
68
  * @return array
69
  */
70
  public function exclude_inline_js( $pattern ) {
78
  * show only all languages in language switcher on Advanced Ads pages if ads and groups are translated
79
  *
80
  * @param array $active_languages languages that can be used in language switcher.
 
81
  * @return array
82
  */
83
  public function wpml_language_switcher( $active_languages ) {
113
  *
114
  * @param array $url Array of URL parts.
115
  * @param string $type URL type.
116
+ * @param object $post WP_Post object of attachment.
117
+ * @return array|bool Unmodified array of URL parts or false to remove URL.
118
  */
119
  public function wordpress_seo_noindex_ad_attachments( $url, $type, $post ) {
120
  if ( 'post' !== $type ) {
219
  wp_dequeue_style( 'jnews-admin' );
220
  }
221
  }
222
+
223
+ /**
224
+ * Check if Adsense Auto ads code can be added to the header.
225
+ *
226
+ * @param bool $can_display if the ad can already be displayed.
227
+ * @return bool
228
+ */
229
+ public function borlabs_cookie_can_add_auto_ads_code( $can_display ) {
230
+ if ( ! $can_display ) {
231
+ return false;
232
+ }
233
+
234
+ return ! self::borlabs_cookie_adsense_auto_ads_code_exists();
235
+ }
236
+
237
+ /**
238
+ * Check if Adsense Auto ads code is added by the Borlabs Cookie plugin.
239
+ *
240
+ * This allows to prevent the "Only one 'enable_page_level_ads' allowed per page" error
241
+ * that makes impossible to close the "Privacy Preference" window created by the "Borlabs Cookie" plugin.
242
+ *
243
+ * @return bool
244
+ */
245
+ public static function borlabs_cookie_adsense_auto_ads_code_exists() {
246
+ // Cache the result in order to perform the check only once.
247
+ static $result = null;
248
+
249
+ if ( null !== $result ) {
250
+ return $result;
251
+ }
252
+
253
+ // Set the `autoload` param to `true` so that the class loads both in frontend and backend.
254
+ if ( class_exists( '\BorlabsCookie\Cookie\Frontend\Cookies', true ) ) {
255
+ try {
256
+ $refl_cookies = new ReflectionClass( '\BorlabsCookie\Cookie\Frontend\Cookies' );
257
+
258
+ if ( $refl_cookies->hasMethod( 'getInstance' ) && $refl_cookies->hasMethod( 'getAllCookieGroups' ) ) {
259
+ $instance = $refl_cookies->getMethod( 'getInstance' );
260
+ $cookie_groups = $refl_cookies->getMethod( 'getAllCookieGroups' );
261
+
262
+ if ( $instance->isPublic() && $instance->isStatic() && $cookie_groups->isPublic() ) {
263
+ $all_cookies = BorlabsCookie\Cookie\Frontend\Cookies::getInstance()->getAllCookieGroups();
264
+ }
265
+ }
266
+ } catch ( Exception $e ) {
267
+ $result = false;
268
+ return $result;
269
+ }
270
+ }
271
+
272
+ if ( empty( $all_cookies ) ) {
273
+ $result = false;
274
+ return $result;
275
+ }
276
+
277
+ foreach ( $all_cookies as $cookie_group_data ) {
278
+ if ( ! empty( $cookie_group_data->group_id ) && 'marketing' === $cookie_group_data->group_id
279
+ && ! empty( $cookie_group_data->cookies ) ) {
280
+ foreach ( $cookie_group_data->cookies as $cookie_data ) {
281
+ if ( ! empty( $cookie_data->cookie_id ) && 'google-adsense' === $cookie_data->cookie_id
282
+ && ! empty( $cookie_data->opt_in_js ) ) {
283
+ $opt_in_js = $cookie_data->opt_in_js;
284
+ }
285
+ }
286
+ }
287
+ }
288
+
289
+ if ( empty( $opt_in_js ) ) {
290
+ $result = false;
291
+ return $result;
292
+ }
293
+
294
+ $result = preg_match( '/<script[^>]+data-ad-client/', $opt_in_js ) || false !== strpos( $opt_in_js, 'enable_page_level_ads:' );
295
+ return $result;
296
+ }
297
+
298
+ /**
299
+ * Whitelist meta boxes created by the Advanced Custom Fields plugin on the ad edit pages
300
+ * when they are dedicated for the "Ad" post type.
301
+ *
302
+ * @param array $meta_boxes already whitelisted meta boxes.
303
+ * @return array
304
+ */
305
+ public function advanced_custom_fields_box( $meta_boxes ) {
306
+
307
+ // load ACF field groups dedicated to the Advanced Ads post type
308
+ $groups = acf_get_field_groups( array( 'post_type' => Advanced_Ads::POST_TYPE_SLUG ) );
309
+
310
+ if ( is_array( $groups ) && $groups ) {
311
+ foreach ( $groups as $_group ) {
312
+ if ( isset( $_group['key'] ) ) {
313
+ $meta_boxes[] = 'acf-' . $_group['key'];
314
+ }
315
+ }
316
+ }
317
+
318
+ return $meta_boxes;
319
+ }
320
  }
classes/plugin.php CHANGED
@@ -165,7 +165,7 @@ class Advanced_Ads_Plugin {
165
  if ( $activated_js || ! empty( $_COOKIE['advads_frontend_picker'] ) ) {
166
  wp_enqueue_script(
167
  $this->get_plugin_slug() . '-advanced-js',
168
- sprintf( '%spublic/assets/js/advanced%s.js', ADVADS_BASE_URL, defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.orig' : '' ),
169
  array( 'jquery' ),
170
  ADVADS_VERSION,
171
  false
165
  if ( $activated_js || ! empty( $_COOKIE['advads_frontend_picker'] ) ) {
166
  wp_enqueue_script(
167
  $this->get_plugin_slug() . '-advanced-js',
168
+ sprintf( '%spublic/assets/js/advanced%s.js', ADVADS_BASE_URL, defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ),
169
  array( 'jquery' ),
170
  ADVADS_VERSION,
171
  false
languages/advanced-ads.pot CHANGED
@@ -2,14 +2,14 @@
2
  # This file is distributed under the same license as the Advanced Ads plugin.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Advanced Ads 1.20.2\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/advanced-ads/\n"
7
  "Last-Translator: Thomas Maier <post@webzunft.de>\n"
8
  "Language-Team: webgilde <support@wpadvancedads.com>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "POT-Creation-Date: 2020-10-01T09:48:50+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.4.0\n"
15
  "X-Domain: advanced-ads\n"
@@ -1372,7 +1372,7 @@ msgstr ""
1372
  #: admin/views/placements-ad-label.php:9
1373
  #: admin/views/placements-ad-label.php:11
1374
  #: admin/views/placements.php:150
1375
- #: modules/gadsense/includes/class-network-adsense.php:324
1376
  msgid "default"
1377
  msgstr ""
1378
 
@@ -1628,7 +1628,7 @@ msgid "Visitor conditions limit the number of users who can see your ad. There i
1628
  msgstr ""
1629
 
1630
  #: admin/views/conditions/visitor-conditions-form-top.php:9
1631
- #: modules/privacy/admin/views/setting-general.php:59
1632
  msgid "It seems that a caching plugin is activated."
1633
  msgstr ""
1634
 
@@ -3086,7 +3086,7 @@ msgid "I want to change the position of the ads"
3086
  msgstr ""
3087
 
3088
  #: classes/frontend_checks.php:854
3089
- #: modules/gadsense/includes/class-network-adsense.php:256
3090
  msgid "Display Auto ads only on specific pages"
3091
  msgstr ""
3092
 
@@ -3213,7 +3213,7 @@ msgid "Ad blocker fix"
3213
  msgstr ""
3214
 
3215
  #: modules/ad-blocker/admin/admin.php:150
3216
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:365
3217
  msgid "Unable to connect to the filesystem. Please confirm your credentials."
3218
  msgstr ""
3219
 
@@ -3300,49 +3300,49 @@ msgstr ""
3300
  msgid "Want to know how many of your visitors are using an ad blocker? Enter your Google Analytics property ID above to count them."
3301
  msgstr ""
3302
 
3303
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:179
3304
  msgid "The ads.txt file cannot be placed because the URL contains a subdirectory. You need to make the file available at %s"
3305
  msgstr ""
3306
 
3307
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:190
3308
  msgid "The file is available on %s."
3309
  msgstr ""
3310
 
3311
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:194
3312
  msgid "The file was not created."
3313
  msgstr ""
3314
 
3315
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:201
3316
  msgid "Import & Replace"
3317
  msgstr ""
3318
 
3319
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:203
3320
  msgid "Move the content of the existing ads.txt file into Advanced Ads and remove it."
3321
  msgstr ""
3322
 
3323
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:210
3324
  #: modules/ads-txt/admin/views/setting-additional-content.php:29
3325
  msgid "An error occured: %s."
3326
  msgstr ""
3327
 
3328
  #. translators: %s the line that may need to be added manually
3329
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:223
3330
  msgid "If your site is located on a subdomain, you need to add the following line to the ads.txt file of the root domain: %s"
3331
  msgstr ""
3332
 
3333
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:338
3334
  msgid "The ads.txt is now managed with Advanced Ads."
3335
  msgstr ""
3336
 
3337
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:383
3338
  msgid "Not the main blog"
3339
  msgstr ""
3340
 
3341
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:412
3342
  msgid "Could not delete the existing ads.txt file"
3343
  msgstr ""
3344
 
3345
- #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:415
3346
  msgid "Could not find the existing ads.txt file"
3347
  msgstr ""
3348
 
@@ -3544,6 +3544,11 @@ msgstr ""
3544
  msgid "How to enable Auto ads in 30 seconds (video tutorial)"
3545
  msgstr ""
3546
 
 
 
 
 
 
3547
  #: modules/gadsense/admin/views/connect-adsense.php:35
3548
  msgid "Please enter the confirmation code."
3549
  msgstr ""
@@ -3748,31 +3753,31 @@ msgid "An error occurred while requesting account details."
3748
  msgstr ""
3749
 
3750
  #: modules/gadsense/includes/class-mapi.php:1320
3751
- #: modules/gadsense/includes/class-network-adsense.php:515
3752
  msgctxt "AdSense ad type"
3753
  msgid "Matched Content"
3754
  msgstr ""
3755
 
3756
  #: modules/gadsense/includes/class-mapi.php:1323
3757
- #: modules/gadsense/includes/class-network-adsense.php:516
3758
  msgctxt "AdSense ad type"
3759
  msgid "In-article"
3760
  msgstr ""
3761
 
3762
  #: modules/gadsense/includes/class-mapi.php:1325
3763
- #: modules/gadsense/includes/class-network-adsense.php:517
3764
  msgctxt "AdSense ad type"
3765
  msgid "In-feed"
3766
  msgstr ""
3767
 
3768
  #: modules/gadsense/includes/class-mapi.php:1330
3769
- #: modules/gadsense/includes/class-network-adsense.php:518
3770
  msgctxt "AdSense ad type"
3771
  msgid "Display"
3772
  msgstr ""
3773
 
3774
  #: modules/gadsense/includes/class-mapi.php:1332
3775
- #: modules/gadsense/includes/class-network-adsense.php:519
3776
  msgctxt "AdSense ad type"
3777
  msgid "Link"
3778
  msgstr ""
@@ -3843,42 +3848,41 @@ msgstr ""
3843
  msgid "Enable this option to stop loading stats from AdSense into your WordPress backend."
3844
  msgstr ""
3845
 
3846
- #: modules/gadsense/includes/class-network-adsense.php:232
3847
- msgid "Adjust Auto ads options"
3848
  msgstr ""
3849
 
3850
- #. Translators: %s is a URL.
3851
- #: modules/gadsense/includes/class-network-adsense.php:243
3852
- msgid "Please read <a href=\"%s\" target=\"_blank\">this article</a> if <strong>ads appear in random places</strong>."
3853
  msgstr ""
3854
 
3855
- #: modules/gadsense/includes/class-network-adsense.php:261
3856
  msgid "Enable AMP Auto ads"
3857
  msgstr ""
3858
 
3859
- #: modules/gadsense/includes/class-network-adsense.php:282
3860
  msgid "Disable warnings about potential violations of the AdSense terms."
3861
  msgstr ""
3862
 
3863
  #. Translators: %s is a URL.
3864
- #: modules/gadsense/includes/class-network-adsense.php:288
3865
  msgid "Our <a href=\"%s\" target=\"_blank\">Ad Health</a> feature monitors if AdSense is implemented correctly on your site. It also considers ads not managed with Advanced Ads. Enable this option to remove these checks"
3866
  msgstr ""
3867
 
3868
- #: modules/gadsense/includes/class-network-adsense.php:312
3869
  msgid "Enable this option in case your theme adds an unfortunate background color to AdSense ads."
3870
  msgstr ""
3871
 
3872
- #: modules/gadsense/includes/class-network-adsense.php:325
3873
  msgid "enable"
3874
  msgstr ""
3875
 
3876
- #: modules/gadsense/includes/class-network-adsense.php:326
3877
  msgid "disable"
3878
  msgstr ""
3879
 
3880
  #. Translators: %s is a URL.
3881
- #: modules/gadsense/includes/class-network-adsense.php:333
3882
  msgid "Whether your responsive ad unit may expand to <a href='%s' target='blank'>use the full width</a> of your visitor's mobile device screen"
3883
  msgstr ""
3884
 
@@ -4089,20 +4093,20 @@ msgstr ""
4089
  msgid "Show non-personalized AdSense ads until consent is given."
4090
  msgstr ""
4091
 
4092
- #: modules/privacy/admin/views/setting-general.php:62
4093
  msgid "Your users’ consent might get cached and show ads to users who didn’t give their consent yet. "
4094
  msgstr ""
4095
 
4096
- #: modules/privacy/admin/views/setting-general.php:65
4097
  msgid "Cache-busting in Advanced Ads Pro solves that."
4098
  msgstr ""
4099
 
4100
- #: modules/privacy/admin/views/setting-general.php:74
4101
  msgid "Ads are loaded after the user gives their consent and reloads the page."
4102
  msgstr ""
4103
 
4104
  #. Translators: 1: opening link tag with link to Advanced Ads Pro 2: closing link tag
4105
- #: modules/privacy/admin/views/setting-general.php:78
4106
  msgid "Install %1$sAdvanced Ads Pro%2$s to reload the ads instantly without an additional page request."
4107
  msgstr ""
4108
 
2
  # This file is distributed under the same license as the Advanced Ads plugin.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Advanced Ads 1.20.3\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/advanced-ads/\n"
7
  "Last-Translator: Thomas Maier <post@webzunft.de>\n"
8
  "Language-Team: webgilde <support@wpadvancedads.com>\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=UTF-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "POT-Creation-Date: 2020-10-23T08:57:18+00:00\n"
13
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
14
  "X-Generator: WP-CLI 2.4.0\n"
15
  "X-Domain: advanced-ads\n"
1372
  #: admin/views/placements-ad-label.php:9
1373
  #: admin/views/placements-ad-label.php:11
1374
  #: admin/views/placements.php:150
1375
+ #: modules/gadsense/includes/class-network-adsense.php:318
1376
  msgid "default"
1377
  msgstr ""
1378
 
1628
  msgstr ""
1629
 
1630
  #: admin/views/conditions/visitor-conditions-form-top.php:9
1631
+ #: modules/privacy/admin/views/setting-general.php:64
1632
  msgid "It seems that a caching plugin is activated."
1633
  msgstr ""
1634
 
3086
  msgstr ""
3087
 
3088
  #: classes/frontend_checks.php:854
3089
+ #: modules/gadsense/includes/class-network-adsense.php:228
3090
  msgid "Display Auto ads only on specific pages"
3091
  msgstr ""
3092
 
3213
  msgstr ""
3214
 
3215
  #: modules/ad-blocker/admin/admin.php:150
3216
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:367
3217
  msgid "Unable to connect to the filesystem. Please confirm your credentials."
3218
  msgstr ""
3219
 
3300
  msgid "Want to know how many of your visitors are using an ad blocker? Enter your Google Analytics property ID above to count them."
3301
  msgstr ""
3302
 
3303
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:181
3304
  msgid "The ads.txt file cannot be placed because the URL contains a subdirectory. You need to make the file available at %s"
3305
  msgstr ""
3306
 
3307
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:192
3308
  msgid "The file is available on %s."
3309
  msgstr ""
3310
 
3311
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:196
3312
  msgid "The file was not created."
3313
  msgstr ""
3314
 
3315
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:203
3316
  msgid "Import & Replace"
3317
  msgstr ""
3318
 
3319
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:205
3320
  msgid "Move the content of the existing ads.txt file into Advanced Ads and remove it."
3321
  msgstr ""
3322
 
3323
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:212
3324
  #: modules/ads-txt/admin/views/setting-additional-content.php:29
3325
  msgid "An error occured: %s."
3326
  msgstr ""
3327
 
3328
  #. translators: %s the line that may need to be added manually
3329
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:225
3330
  msgid "If your site is located on a subdomain, you need to add the following line to the ads.txt file of the root domain: %s"
3331
  msgstr ""
3332
 
3333
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:340
3334
  msgid "The ads.txt is now managed with Advanced Ads."
3335
  msgstr ""
3336
 
3337
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:385
3338
  msgid "Not the main blog"
3339
  msgstr ""
3340
 
3341
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:414
3342
  msgid "Could not delete the existing ads.txt file"
3343
  msgstr ""
3344
 
3345
+ #: modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php:417
3346
  msgid "Could not find the existing ads.txt file"
3347
  msgstr ""
3348
 
3544
  msgid "How to enable Auto ads in 30 seconds (video tutorial)"
3545
  msgstr ""
3546
 
3547
+ #. translators: 1: the plugin name that is managing the Auto ads code.
3548
+ #: modules/gadsense/admin/views/borlabs-cookie-auto-ads-warning.php:4
3549
+ msgid "Advanced Ads detected that <strong>%s</strong> is managing the Auto ads code and will therefore not add it."
3550
+ msgstr ""
3551
+
3552
  #: modules/gadsense/admin/views/connect-adsense.php:35
3553
  msgid "Please enter the confirmation code."
3554
  msgstr ""
3753
  msgstr ""
3754
 
3755
  #: modules/gadsense/includes/class-mapi.php:1320
3756
+ #: modules/gadsense/includes/class-network-adsense.php:509
3757
  msgctxt "AdSense ad type"
3758
  msgid "Matched Content"
3759
  msgstr ""
3760
 
3761
  #: modules/gadsense/includes/class-mapi.php:1323
3762
+ #: modules/gadsense/includes/class-network-adsense.php:510
3763
  msgctxt "AdSense ad type"
3764
  msgid "In-article"
3765
  msgstr ""
3766
 
3767
  #: modules/gadsense/includes/class-mapi.php:1325
3768
+ #: modules/gadsense/includes/class-network-adsense.php:511
3769
  msgctxt "AdSense ad type"
3770
  msgid "In-feed"
3771
  msgstr ""
3772
 
3773
  #: modules/gadsense/includes/class-mapi.php:1330
3774
+ #: modules/gadsense/includes/class-network-adsense.php:512
3775
  msgctxt "AdSense ad type"
3776
  msgid "Display"
3777
  msgstr ""
3778
 
3779
  #: modules/gadsense/includes/class-mapi.php:1332
3780
+ #: modules/gadsense/includes/class-network-adsense.php:513
3781
  msgctxt "AdSense ad type"
3782
  msgid "Link"
3783
  msgstr ""
3848
  msgid "Enable this option to stop loading stats from AdSense into your WordPress backend."
3849
  msgstr ""
3850
 
3851
+ #: modules/gadsense/includes/class-network-adsense.php:229
3852
+ msgid "Why are ads appearing in random positions?"
3853
  msgstr ""
3854
 
3855
+ #: modules/gadsense/includes/class-network-adsense.php:238
3856
+ msgid "Adjust Auto ads options"
 
3857
  msgstr ""
3858
 
3859
+ #: modules/gadsense/includes/class-network-adsense.php:255
3860
  msgid "Enable AMP Auto ads"
3861
  msgstr ""
3862
 
3863
+ #: modules/gadsense/includes/class-network-adsense.php:276
3864
  msgid "Disable warnings about potential violations of the AdSense terms."
3865
  msgstr ""
3866
 
3867
  #. Translators: %s is a URL.
3868
+ #: modules/gadsense/includes/class-network-adsense.php:282
3869
  msgid "Our <a href=\"%s\" target=\"_blank\">Ad Health</a> feature monitors if AdSense is implemented correctly on your site. It also considers ads not managed with Advanced Ads. Enable this option to remove these checks"
3870
  msgstr ""
3871
 
3872
+ #: modules/gadsense/includes/class-network-adsense.php:306
3873
  msgid "Enable this option in case your theme adds an unfortunate background color to AdSense ads."
3874
  msgstr ""
3875
 
3876
+ #: modules/gadsense/includes/class-network-adsense.php:319
3877
  msgid "enable"
3878
  msgstr ""
3879
 
3880
+ #: modules/gadsense/includes/class-network-adsense.php:320
3881
  msgid "disable"
3882
  msgstr ""
3883
 
3884
  #. Translators: %s is a URL.
3885
+ #: modules/gadsense/includes/class-network-adsense.php:327
3886
  msgid "Whether your responsive ad unit may expand to <a href='%s' target='blank'>use the full width</a> of your visitor's mobile device screen"
3887
  msgstr ""
3888
 
4093
  msgid "Show non-personalized AdSense ads until consent is given."
4094
  msgstr ""
4095
 
4096
+ #: modules/privacy/admin/views/setting-general.php:67
4097
  msgid "Your users’ consent might get cached and show ads to users who didn’t give their consent yet. "
4098
  msgstr ""
4099
 
4100
+ #: modules/privacy/admin/views/setting-general.php:70
4101
  msgid "Cache-busting in Advanced Ads Pro solves that."
4102
  msgstr ""
4103
 
4104
+ #: modules/privacy/admin/views/setting-general.php:79
4105
  msgid "Ads are loaded after the user gives their consent and reloads the page."
4106
  msgstr ""
4107
 
4108
  #. Translators: 1: opening link tag with link to Advanced Ads Pro 2: closing link tag
4109
+ #: modules/privacy/admin/views/setting-general.php:83
4110
  msgid "Install %1$sAdvanced Ads Pro%2$s to reload the ads instantly without an additional page request."
4111
  msgstr ""
4112
 
modules/ads-txt/admin/class-advanced-ads-ads-txt-admin.php CHANGED
@@ -33,9 +33,11 @@ class Advanced_Ads_Ads_Txt_Admin {
33
  * @return array $options Options.
34
  */
35
  public function toggle( $options ) {
36
- $create = ! empty( $_POST['advads-ads-txt-create'] );
37
- $all_network = ! empty( $_POST['advads-ads-txt-all-network'] );
38
- $additional_content = ! empty( $_POST['advads-ads-txt-additional-content'] ) ? $_POST['advads-ads-txt-additional-content'] : '';
 
 
39
 
40
  $this->strategy->toggle( $create, $all_network, $additional_content );
41
  $content = $this->get_adsense_blog_data();
33
  * @return array $options Options.
34
  */
35
  public function toggle( $options ) {
36
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
37
+ $create = ! empty( $_POST['advads-ads-txt-create'] );
38
+ $all_network = ! empty( $_POST['advads-ads-txt-all-network'] );
39
+ $additional_content = ! empty( $_POST['advads-ads-txt-additional-content'] ) ? trim( wp_unslash( $_POST['advads-ads-txt-additional-content'] ) ) : '';
40
+ // phpcs:enable
41
 
42
  $this->strategy->toggle( $create, $all_network, $additional_content );
43
  $content = $this->get_adsense_blog_data();
modules/gadsense/admin/views/borlabs-cookie-auto-ads-warning.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php printf(
2
+ wp_kses(
3
+ /* translators: 1: the plugin name that is managing the Auto ads code. */
4
+ __( 'Advanced Ads detected that <strong>%s</strong> is managing the Auto ads code and will therefore not add it.', 'advanced-ads' ),
5
+ array(
6
+ 'strong' => array(),
7
+ )
8
+ ),
9
+ 'Borlabs Cookies'
10
+ );
11
+
modules/gadsense/includes/class-network-adsense.php CHANGED
@@ -222,38 +222,32 @@ class Advanced_Ads_Network_Adsense extends Advanced_Ads_Ad_Network {
222
  <label><input type="checkbox" name="<?php echo esc_attr( GADSENSE_OPT_NAME ); ?>[page-level-enabled]" value="1" <?php checked( $page_level ); ?> />
223
  <?php
224
  esc_attr_e( 'Insert the AdSense header code used for verification and the Auto Ads feature.', 'advanced-ads' );
225
- if ( ! empty( $options['adsense-id'] ) ) :
226
- ?>
227
- &nbsp<a href="https://www.google.com/adsense/new/u/0/<?php echo esc_attr( $options['adsense-id'] ); ?>/myads/auto-ads" target="_blank">
 
 
228
  <?php
 
 
 
 
229
  /**
230
  * Translators: this is the text for a link to a sub-page in an AdSense account
231
  */
232
  esc_attr_e( 'Adjust Auto ads options', 'advanced-ads' );
233
- ?>
234
- </a>
235
- <?php
236
  endif;
237
- ?>
238
- </label><p class="description">
239
- <?php
240
- printf(
241
- wp_kses(
242
- // Translators: %s is a URL.
243
- __( 'Please read <a href="%s" target="_blank">this article</a> if <strong>ads appear in random places</strong>.', 'advanced-ads' ),
244
- array(
245
- 'a' => array(
246
- 'href' => array(),
247
- 'target' => array(),
248
- ),
249
- 'strong' => array(),
250
- )
251
- ),
252
- esc_url( ADVADS_URL ) . 'adsense-in-random-positions-auto-ads/#utm_source=advanced-ads&utm_medium=link&utm_campaign=backend-autoads-ads'
253
- );
254
- ?>
255
- </p>
256
- <p class="description"><a href="<?php echo esc_url( ADVADS_URL ) . 'adsense-auto-ads-wordpress/#Display_Auto_Ads_only_on_specific_pages'; ?>" target="_blank"><?php esc_attr_e( 'Display Auto ads only on specific pages', 'advanced-ads' ); ?></a></p>
257
  <?php
258
  // Show information about AMP Auto ads when an AMP plugin is installed and Responsive Ads is missing.
259
  if ( ! defined( 'AAR_VERSION' ) && Advanced_Ads_Checks::active_amp_plugin() ) :
222
  <label><input type="checkbox" name="<?php echo esc_attr( GADSENSE_OPT_NAME ); ?>[page-level-enabled]" value="1" <?php checked( $page_level ); ?> />
223
  <?php
224
  esc_attr_e( 'Insert the AdSense header code used for verification and the Auto Ads feature.', 'advanced-ads' );
225
+ ?>
226
+ </label>
227
+ <ul>
228
+ <li><a href="<?php echo esc_url( ADVADS_URL ) . 'adsense-auto-ads-wordpress/#Display_Auto_Ads_only_on_specific_pages'; ?>" target="_blank"><?php esc_attr_e( 'Display Auto ads only on specific pages', 'advanced-ads' ); ?></a></li>
229
+ <li><a href="<?php echo esc_url( ADVADS_URL ) . 'adsense-in-random-positions-auto-ads/#utm_source=advanced-ads&utm_medium=link&utm_campaign=backend-autoads-ads'; ?>" target="_blank"><?php esc_attr_e( 'Why are ads appearing in random positions?', 'advanced-ads' ); ?></a></li>
230
  <?php
231
+ if ( ! empty( $options['adsense-id'] ) ) :
232
+ ?>
233
+ <li><a href="https://www.google.com/adsense/new/u/0/<?php echo esc_attr( $options['adsense-id'] ); ?>/myads/auto-ads" target="_blank">
234
+ <?php
235
  /**
236
  * Translators: this is the text for a link to a sub-page in an AdSense account
237
  */
238
  esc_attr_e( 'Adjust Auto ads options', 'advanced-ads' );
239
+ ?>
240
+ </a></li>
241
+ <?php
242
  endif;
243
+ ?>
244
+ </ul>
245
+ <?php if ( Advanced_Ads_Compatibility::borlabs_cookie_adsense_auto_ads_code_exists() ) : ?>
246
+ <p class="advads-error-message">
247
+ <?php require GADSENSE_BASE_PATH . 'admin/views/borlabs-cookie-auto-ads-warning.php'; ?>
248
+ </p>
249
+ <?php endif; ?>
250
+
 
 
 
 
 
 
 
 
 
 
 
 
251
  <?php
252
  // Show information about AMP Auto ads when an AMP plugin is installed and Responsive Ads is missing.
253
  if ( ! defined( 'AAR_VERSION' ) && Advanced_Ads_Checks::active_amp_plugin() ) :
modules/privacy/admin/views/setting-general.php CHANGED
@@ -52,6 +52,11 @@
52
  <input type="checkbox" name="<?php echo esc_attr( Advanced_Ads_Privacy::OPTION_KEY ); ?>[show-non-personalized-adsense]" <?php checked( $show_non_personalized_adsense ); ?> />
53
  <?php esc_html_e( 'Show non-personalized AdSense ads until consent is given.', 'advanced-ads' ); ?>
54
  </label>
 
 
 
 
 
55
  </div>
56
 
57
  <?php if ( apply_filters( 'advanced-ads-privacy-custom-show-warning', ! empty( $checked ) && Advanced_Ads_Checks::cache() ) ) : ?>
52
  <input type="checkbox" name="<?php echo esc_attr( Advanced_Ads_Privacy::OPTION_KEY ); ?>[show-non-personalized-adsense]" <?php checked( $show_non_personalized_adsense ); ?> />
53
  <?php esc_html_e( 'Show non-personalized AdSense ads until consent is given.', 'advanced-ads' ); ?>
54
  </label>
55
+ <?php if ( Advanced_Ads_Compatibility::borlabs_cookie_adsense_auto_ads_code_exists() ) : ?>
56
+ <p class="description">
57
+ <?php require GADSENSE_BASE_PATH . 'admin/views/borlabs-cookie-auto-ads-warning.php'; ?>
58
+ </p>
59
+ <?php endif; ?>
60
  </div>
61
 
62
  <?php if ( apply_filters( 'advanced-ads-privacy-custom-show-warning', ! empty( $checked ) && Advanced_Ads_Checks::cache() ) ) : ?>
public/assets/js/advanced.js CHANGED
@@ -1 +1,874 @@
1
- advads={supports_localstorage:function(){"use strict";try{return window&&void 0!==window.localStorage?(window.localStorage.setItem("x","x"),window.localStorage.removeItem("x"),!0):!1}catch(e){return!1}},max_per_session:function(e,t){var a=1;if(void 0!==t&&0!==parseInt(t)||(t=1),this.cookie_exists(e)){if(this.get_cookie(e)>=t)return!0;a+=parseInt(this.get_cookie(e))}return this.set_cookie(e,a),!1},count_up:function(e,t){var a=1;this.cookie_exists(e)&&(a+=parseInt(this.get_cookie(e))),this.set_cookie(e,a)},set_cookie_exists:function(e){return!!get_cookie(e)||(set_cookie(e,"",0),!1)},get_cookie:function(e){for(var t,a,o=document.cookie.split(";"),n=0;n<o.length;n++)if(t=o[n].substr(0,o[n].indexOf("=")),a=o[n].substr(o[n].indexOf("=")+1),(t=t.replace(/^\s+|\s+$/g,""))===e)return unescape(a)},set_cookie:function(e,t,a,o,n,r){var i=null==a?null:24*a*60*60;this.set_cookie_sec(e,t,i,o,n,r)},set_cookie_sec:function(e,t,a,o,n,r){var i=new Date;i.setSeconds(i.getSeconds()+parseInt(a)),document.cookie=e+"="+escape(t)+(null==a?"":"; expires="+i.toUTCString())+(null==o?"; path=/":"; path="+o)+(null==n?"":"; domain="+n)+(null==r?"":"; secure")},cookie_exists:function(e){var t=this.get_cookie(e);return null!==t&&""!==t&&void 0!==t},move:function(e,t,a){var o=jQuery(e),n=t;if(void 0===a&&(a={}),void 0===a.css&&(a.css={}),void 0===a.method&&(a.method="prependTo"),""===t&&void 0!==a.target)switch(a.target){case"wrapper":var r="left";void 0!==a.offset&&(r=a.offset),t=this.find_wrapper(e,r)}switch(1<(t=void 0===a.moveintohidden?jQuery(t).filter(":visible"):jQuery(t)).length&&console.log("Advanced Ads: element '"+n+"' found "+t.length+" times."),a.method){case"insertBefore":o.insertBefore(t);break;case"insertAfter":o.insertAfter(t);break;case"appendTo":o.appendTo(t);break;case"prependTo":o.prependTo(t);break;default:o.prependTo(t)}},set_parent_relative:function(e,t){var t=void 0!==t?t:{},a=jQuery(e).parent();t.use_grandparent&&(a=a.parent()),"static"!==a.css("position")&&""!==a.css("position")||a.css("position","relative")},fix_element:function(e,t){var t=void 0!==t?t:{},a=jQuery(e);t.use_grandparent?this.set_parent_relative(a.parent()):this.set_parent_relative(a),t.is_invisible&&a.show();var o,n=parseInt(a.offset().top),r=parseInt(a.offset().left);t.is_invisible&&a.hide(),"left"===t.offset?(o=jQuery(window).width()-r-a.outerWidth(),a.css("position","fixed").css("top",n+"px").css("right",o+"px").css("left","")):a.css("position","fixed").css("top",n+"px").css("left",r+"px").css("right","")},find_wrapper:function(o,n){var r;return jQuery("body").children().each(function(e,t){if(t.id!==o.substring(1)){var a=jQuery(t);if("right"===n&&a.offset().left+jQuery(a).width()<jQuery(window).width()||"left"===n&&0<a.offset().left)return"static"!==a.css("position")&&""!==a.css("position")||a.css("position","relative"),r=t,!1}}),r},center_fixed_element:function(e){var t=jQuery(e),a=jQuery(window).width()/2-parseInt(t.css("width"))/2;t.css("left",a+"px")},center_vertically:function(e){var t=jQuery(e),a=jQuery(window).height()/2-parseInt(t.css("height"))/2;"fixed"!==t.css("position")&&(a-=topoffset=parseInt(t.offset().top)),t.css("top",a+"px")},close:function(e){jQuery(e).remove()},wait_for_images:function(n,r){var i=0,s=[];n.find('img[src][src!=""]').each(function(){s.push(this.src)}),0===s.length&&r.call(n),jQuery.each(s,function(e,t){var a=new Image;a.src=t;var o="load error";jQuery(a).one(o,function e(t){if(jQuery(this).off(o,e),++i==s.length)return r.call(n[0]),!1})})},privacy:{state:"unknown",state_executed:!1,get_state:function(){if("unknown"!==window.advads_options.privacy.state)return advads.privacy.state_executed||(advads.privacy.state_executed=!0,advads.privacy.dispatch_event(window.advads_options.privacy.state,!1)),advads.privacy.state;var e;"custom"===window.advads_options.privacy["consent-method"]&&(e=new RegExp(window.advads_options.privacy["custom-cookie-name"]+"=.*?"+window.advads_options.privacy["custom-cookie-value"]+"[^;]*"),advads.privacy.state_executed||(advads.privacy.state_executed=!0,advads.privacy.dispatch_event(null!==document.cookie.match(e)?"accepted":"unknown",!0))),advads.privacy.state_executed=!0;var t=0,a=setInterval(function(){switch(600==++t&&clearInterval(a),window.advads_options.privacy["consent-method"]){case"custom":null!==document.cookie.match(e)&&(clearInterval(a),"accepted"!==advads.privacy.state&&advads.privacy.dispatch_event("accepted",!0));break;case"iab_tcf_20":if(void 0===window.__tcfapi)return;clearInterval(a),window.__tcfapi("addEventListener",2,function(e,t){if(t&&("tcloaded"===e.eventStatus||"useractioncomplete"===e.eventStatus)){var a="useractioncomplete"===e.eventStatus;if(!e.gdprApplies)return void("not_needed"!==advads.privacy.state&&advads.privacy.dispatch_event("not_needed",a));if(e.purpose.consents[1])return void("accepted"!==advads.privacy.state&&advads.privacy.dispatch_event("accepted",a));"rejected"!==advads.privacy.state&&advads.privacy.dispatch_event("rejected",a)}})}},100);return advads.privacy.state},is_adsense_npa_enabled:function(){return!window.advads_options||!window.advads_options.privacy||!(!window.advads_options.privacy["show-non-personalized-adsense"]||"custom"!==window.advads_options.privacy["consent-method"])},dispatch_event:function(e,t){function a(){document.dispatchEvent(new CustomEvent("advanced_ads_privacy",{detail:{state:e,previousState:o,userAction:t}}))}var o=advads.privacy.state;if(advads.privacy.state=e,"loading"!==document.readyState)return a();document.addEventListener("readystatechange",a,{once:!0})},is_ad_decoded:function(e){return null===document.querySelector('script[data-tcf="waiting-for-consent"][data-id="'+e+'"]')},decode_ad:function(e,t){t="boolean"!=typeof t||t;var a=decodeURIComponent(Array.prototype.map.call(atob(e.textContent),function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""));if(!t)return a;e.replaceWith(document.createRange().createContextualFragment(a))}}},(window.advanced_ads_ready||jQuery(document).ready).call(null,function(){advads.privacy.get_state()}),document.addEventListener("advanced_ads_privacy",function(e){"accepted"!==e.detail.state&&"not_needed"!==e.detail.state||e.detail.userAction||"loading"===document.readyState||document.querySelectorAll('script[type="text/plain"][data-tcf="waiting-for-consent"]').forEach(advads.privacy.decode_ad)}),jQuery(document).ready(function(){var i,s,d,c;!advads.supports_localstorage()||!localStorage.getItem("advads_frontend_picker")||window.advads_options.blog_id&&localStorage.getItem("advads_frontend_blog_id")&&window.advads_options.blog_id!==localStorage.getItem("advads_frontend_blog_id")||localStorage.getItem("advads_frontend_starttime")&&parseInt(localStorage.getItem("advads_frontend_starttime"),10)<(new Date).getTime()-27e5&&(localStorage.removeItem("advads_frontend_action"),localStorage.removeItem("advads_frontend_element"),localStorage.removeItem("advads_frontend_picker"),localStorage.removeItem("advads_prev_url"),localStorage.removeItem("advads_frontend_pathtype"),localStorage.removeItem("advads_frontend_boundary"),localStorage.removeItem("advads_frontend_blog_id"),localStorage.removeItem("advads_frontend_starttime"),!void advads.set_cookie("advads_frontend_picker","",-1))||(s=jQuery("<div id='advads-picker-overlay'>"),d=[document.body,document.documentElement,document],s.css({position:"absolute",border:"solid 2px #428bca",backgroundColor:"rgba(66,139,202,0.5)",boxSizing:"border-box",zIndex:1e6,pointerEvents:"none"}).prependTo("body"),"true"===localStorage.getItem("advads_frontend_boundary")&&jQuery("body").css("cursor","not-allowed"),window.advads.is_boundary_reached=function(e){if("true"!==localStorage.getItem("advads_frontend_boundary"))return!1;$advads_picker_cur=jQuery(e);var t=jQuery(".advads-frontend-picker-boundary-helper");return $boundaries=t.parent(),$boundaries.css("cursor","pointer"),$advads_picker_cur.is($boundaries)||!$advads_picker_cur.closest($boundaries).length},c="xpath"===localStorage.getItem("advads_frontend_pathtype")?"getXPath":"getPath",jQuery(document).mousemove(function(e){if(e.target!==i){if(~d.indexOf(e.target))return i=null,void s.hide();var t=jQuery(e.target),a=t.offset(),o=t.outerWidth(),n=t.outerHeight();i=e.target;var r=jQuery(i)[c]();r&&(console.log(r),s.css({top:a.top,left:a.left,width:o,height:n}).show())}}),jQuery(document).click(function(e){var t=jQuery(i)[c]();advads.is_boundary_reached(i)||(localStorage.setItem("advads_frontend_element",t),window.location=localStorage.getItem("advads_prev_url"))}))}),jQuery.fn.extend({getPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("html"))return"html > "+e;if(3===t)return e;var a=this.get(0).nodeName.toLowerCase(),o=this.attr("id"),n=this.attr("class");return t+=1,void 0===o||/\d/.test(o)?void 0!==n&&(n=n.split(/[\s\n]+/),(n=jQuery.grep(n,function(e,t){return!/\d/.test(e)})).length&&(a+="."+n.slice(0,2).join("."))):a+="#"+o,this.siblings(a).length&&(a+=":eq("+this.siblings(a).addBack().not("#advads-picker-overlay").index(this)+")"),""===e?this.parent().getPath(a,t):this.parent().getPath(a+" > "+e,t)},getXPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("body")||3===t)return e;if(advads.is_boundary_reached(this))return e;var a,o=this.get(0).nodeName.toLowerCase(),n=o,r=this.attr("id"),i=this.attr("class"),s=[];if(void 0!==r&&!/\d/.test(r))return n+'[@id and id="'+r+'"]/'+e;if(void 0!==i&&(i=i.split(/[\s\n]+/),(i=jQuery.grep(i,function(e,t){return!/\d/.test(e)})).length)){t+=1;for(var s=i.slice(0,2),d=[],c=0;c<s.length;c++)d.push('(@class and contains(concat(" ", normalize-space(@class), " "), " '+s[c]+' "))');n+="["+d.join(" and ")+"]"}return(a=s.length?this.siblings(o+"."+s.join(".")):this.siblings(o)).length&&(n+="["+a.addBack().not("#advads-picker-overlay").index(this)+"]"),""===e?this.parent().getXPath(n,t):this.parent().getXPath(n+"/"+e,t)}});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * advanced ads functions to be used directly within ad codes
3
+ */
4
+
5
+ advads = {
6
+ /**
7
+ * check if localstorage is supported/enabled by client
8
+ */
9
+ supports_localstorage: function () {
10
+ "use strict";
11
+ try {
12
+ if ( ! window || window.localStorage === undefined ) {
13
+ return false;
14
+ }
15
+ // storage might be full or disabled
16
+ window.localStorage.setItem( "x", "x" );
17
+ window.localStorage.removeItem( "x" );
18
+ return true;
19
+ } catch ( e ) {
20
+ return false;
21
+ }
22
+ },
23
+ /**
24
+ * check if the ad is displayed more than {max} times per session
25
+ * every check increases the counter
26
+ *
27
+ * @param {string} name (no id needed, just any id-formated string)
28
+ * @param {type} max number of maximum times the ad can be displayed within the period
29
+ * @returns {bool} true if limit is reached
30
+ */
31
+ max_per_session: function ( name, max ) {
32
+ var num = 1;
33
+ if ( max === undefined || parseInt( max ) === 0 ) {
34
+ max = 1;
35
+ }
36
+
37
+ // check if cookie exists and get the value
38
+ if ( this.cookie_exists( name ) ) {
39
+ if ( this.get_cookie( name ) >= max ) {
40
+ return true;
41
+ }
42
+ num = num + parseInt( this.get_cookie( name ) );
43
+ }
44
+ this.set_cookie( name, num );
45
+ return false;
46
+ },
47
+ /**
48
+ * increase a cookie with an integer value by 1
49
+ *
50
+ * @param {str} name of the cookie
51
+ * @param {int} exdays days until cookie expires
52
+ */
53
+ count_up: function ( name, exdays ) {
54
+ var num = 1;
55
+
56
+ // check if cookie exists and get the value
57
+ if ( this.cookie_exists( name ) ) {
58
+ num = num + parseInt( this.get_cookie( name ) );
59
+ }
60
+ this.set_cookie( name, num );
61
+ },
62
+ /**
63
+ * return true, if cookie exists
64
+ * return false, if not
65
+ * if not exists, create it
66
+ * use case: to check if something already happened in this page impression
67
+ *
68
+ * @param {type} name
69
+ * @returns {unresolved}
70
+ */
71
+ set_cookie_exists: function ( name ) {
72
+ if ( get_cookie( name ) ) {
73
+ return true;
74
+ }
75
+ set_cookie( name, '', 0 );
76
+ return false;
77
+ },
78
+ /**
79
+ * get a cookie value
80
+ *
81
+ * @param {str} name of the cookie
82
+ */
83
+ get_cookie: function ( name ) {
84
+ var i, x, y, ADVcookies = document.cookie.split( ";" );
85
+ for ( i = 0; i < ADVcookies.length; i ++ ) {
86
+ x = ADVcookies[i].substr( 0, ADVcookies[i].indexOf( "=" ) );
87
+ y = ADVcookies[i].substr( ADVcookies[i].indexOf( "=" ) + 1 );
88
+ x = x.replace( /^\s+|\s+$/g, "" );
89
+ if ( x === name ) {
90
+ return unescape( y );
91
+ }
92
+ }
93
+ },
94
+ /**
95
+ * set a cookie value
96
+ *
97
+ * @param {str} name of the cookie
98
+ * @param {str} value of the cookie
99
+ * @param {int} exdays days until cookie expires
100
+ * set 0 to expire cookie immidiatelly
101
+ * set null to expire cookie in the current session
102
+ */
103
+ set_cookie: function ( name, value, exdays, path, domain, secure ) {
104
+ // days in seconds
105
+ var expiry = (
106
+ exdays == null
107
+ ) ? null : exdays * 24 * 60 * 60;
108
+ this.set_cookie_sec( name, value, expiry, path, domain, secure );
109
+ },
110
+ /**
111
+ * set a cookie with expiry given in seconds
112
+ *
113
+ * @param {str} name of the cookie
114
+ * @param {str} value of the cookie
115
+ * @param {int} expiry seconds until cookie expires
116
+ * set 0 to expire cookie immidiatelly
117
+ * set null to expire cookie in the current session
118
+ */
119
+ set_cookie_sec: function ( name, value, expiry, path, domain, secure ) {
120
+ var exdate = new Date();
121
+ exdate.setSeconds( exdate.getSeconds() + parseInt( expiry ) );
122
+ document.cookie = name + "=" + escape( value ) +
123
+ (
124
+ (
125
+ expiry == null
126
+ ) ? "" : "; expires=" + exdate.toUTCString()
127
+ ) +
128
+ (
129
+ (
130
+ path == null
131
+ ) ? "; path=/" : "; path=" + path
132
+ ) +
133
+ (
134
+ (
135
+ domain == null
136
+ ) ? "" : "; domain=" + domain
137
+ ) +
138
+ (
139
+ (
140
+ secure == null
141
+ ) ? "" : "; secure"
142
+ );
143
+ },
144
+ /**
145
+ * check if a cookie is set and contains a value
146
+ *
147
+ * @param {str} name of the cookie
148
+ * @returns {bool} true, if cookie is set
149
+ */
150
+ cookie_exists: function ( name ) {
151
+ var c_value = this.get_cookie( name );
152
+ if ( c_value !== null && c_value !== "" && c_value !== undefined ) {
153
+ return true;
154
+ }
155
+ return false;
156
+ },
157
+ /**
158
+ * move one element into another
159
+ *
160
+ * @param {str} element selector of the element that should be moved
161
+ * @param {str} target selector of the element where to move
162
+ * @param {arr} options
163
+ */
164
+ move: function ( element, target, options ) {
165
+
166
+ var el = jQuery( element );
167
+ var target_string = target;
168
+
169
+ if ( typeof options === 'undefined' ) {
170
+ options = {};
171
+ }
172
+ if ( typeof options.css === 'undefined' ) {
173
+ options.css = {};
174
+ }
175
+ if ( typeof options.method === 'undefined' ) {
176
+ options.method = 'prependTo';
177
+ }
178
+
179
+ // search for abstract target element
180
+ if ( target === '' && typeof options.target !== 'undefined' ) {
181
+ switch ( options.target ) {
182
+ case 'wrapper' : // wrapper
183
+ var offset = 'left';
184
+ if ( typeof options.offset !== 'undefined' ) {
185
+ offset = options.offset;
186
+ }
187
+ target = this.find_wrapper( element, offset );
188
+ break;
189
+ }
190
+ }
191
+
192
+ // use only visible elements
193
+ if ( typeof options.moveintohidden === 'undefined' ) {
194
+ target = jQuery( target ).filter( ':visible' );
195
+ } else {
196
+ target = jQuery( target );
197
+ }
198
+
199
+ // print warning in console if the element appears multiple times
200
+ if ( target.length > 1 ) {
201
+ console.log( "Advanced Ads: element '" + target_string + "' found " + target.length + " times." );
202
+ }
203
+
204
+ // switch insert method
205
+ switch ( options.method ) {
206
+ case 'insertBefore' :
207
+ el.insertBefore( target );
208
+ break;
209
+ case 'insertAfter' :
210
+ el.insertAfter( target );
211
+ break;
212
+ case 'appendTo' :
213
+ el.appendTo( target );
214
+ break;
215
+ case 'prependTo' :
216
+ el.prependTo( target );
217
+ break;
218
+ default :
219
+ el.prependTo( target );
220
+ }
221
+ },
222
+
223
+ /**
224
+ * Set 'relative' position for a parent element.
225
+ *
226
+ * @param {str} element selector
227
+ */
228
+ set_parent_relative: function ( element, options ) {
229
+ var options = typeof options !== 'undefined' ? options : {};
230
+ var el = jQuery( element );
231
+ // give "position" style to parent element, if missing
232
+ var parent = el.parent();
233
+
234
+ if ( options.use_grandparent ) {
235
+ parent = parent.parent();
236
+ }
237
+
238
+ if ( parent.css( 'position' ) === 'static' || parent.css( 'position' ) === '' ) {
239
+ parent.css( 'position', 'relative' );
240
+ }
241
+ },
242
+
243
+ /**
244
+ * make an absolute position element fixed at the current position
245
+ * hint: use only after DOM is fully loaded in order to fix a wrong position
246
+ *
247
+ * @param {str} element selector
248
+ * @param {obj} options
249
+ */
250
+ fix_element: function ( element, options ) {
251
+ var options = typeof options !== 'undefined' ? options : {};
252
+
253
+ var el = jQuery( element );
254
+
255
+ if ( options.use_grandparent ) {
256
+ this.set_parent_relative( el.parent() );
257
+ } else {
258
+ this.set_parent_relative( el );
259
+ }
260
+
261
+ // fix element at current position
262
+ // get position for hidden elements by showing them for a very short time
263
+ if ( options.is_invisible ) {
264
+ el.show();
265
+ }
266
+ var topoffset = parseInt( el.offset().top );
267
+ var leftoffset = parseInt( el.offset().left );
268
+ if ( options.is_invisible ) {
269
+ el.hide();
270
+ }
271
+ if ( 'left' === options.offset ) {
272
+ // Allow to scale the nested image down when it has `max-width: 100%` and touches the left edge of the viewport.
273
+ var rightoffset = jQuery( window ).width() - leftoffset - el.outerWidth();
274
+ el.css( 'position', 'fixed' ).css( 'top', topoffset + 'px' ).css( 'right', rightoffset + 'px' ).css( 'left', '' );
275
+ } else {
276
+ // reset "right" to prevent conflicts
277
+ el.css( 'position', 'fixed' ).css( 'top', topoffset + 'px' ).css( 'left', leftoffset + 'px' ).css( 'right', '' );
278
+ }
279
+
280
+ },
281
+
282
+ /**
283
+ * find the main wrapper
284
+ * either id or first of its class
285
+ *
286
+ * @param {str} element selector
287
+ * @param {str} offset which position of the offset to check (left or right)
288
+ * @return {str} selector
289
+ */
290
+ find_wrapper: function ( element, offset ) {
291
+ // first margin: auto element after body
292
+ var returnValue;
293
+ jQuery( 'body' ).children().each( function ( key, value ) {
294
+ // exclude current element
295
+ // TODO exclude <script>
296
+ if ( value.id !== element.substring( 1 ) ) {
297
+ // check offset value
298
+ var checkedelement = jQuery( value );
299
+ // check if there is space left or right of the element
300
+ if ( (
301
+ offset === 'right' && (
302
+ checkedelement.offset().left + jQuery( checkedelement ).width() < jQuery( window ).width()
303
+ )
304
+ ) ||
305
+ (
306
+ offset === 'left' && checkedelement.offset().left > 0
307
+ ) ) {
308
+ // fix element
309
+ if ( checkedelement.css( 'position' ) === 'static' || checkedelement.css( 'position' ) === '' ) {
310
+ checkedelement.css( 'position', 'relative' );
311
+ }
312
+ // set return value
313
+ returnValue = value;
314
+ return false;
315
+ }
316
+ }
317
+ } );
318
+ return returnValue;
319
+ },
320
+ /**
321
+ * center fixed element on the screen
322
+ *
323
+ * @param {str} element selector
324
+ */
325
+ center_fixed_element: function ( element ) {
326
+ var el = jQuery( element );
327
+ // half window width minus half element width
328
+ var left = (
329
+ jQuery( window ).width() / 2
330
+ ) - (
331
+ parseInt( el.css( 'width' ) ) / 2
332
+ );
333
+ el.css( 'left', left + 'px' );
334
+ },
335
+ /**
336
+ * center element vertically on the screen
337
+ *
338
+ * @param {str} element selector
339
+ */
340
+ center_vertically: function ( element ) {
341
+ var el = jQuery( element );
342
+ // half window height minus half element height
343
+ var left = (
344
+ jQuery( window ).height() / 2
345
+ ) - (
346
+ parseInt( el.css( 'height' ) ) / 2
347
+ );
348
+
349
+ // Center correctly when the ad is attached to the element that begins lower.
350
+ if ( el.css( 'position' ) !== 'fixed' ) {
351
+ left -= topoffset = parseInt( el.offset().top );
352
+ }
353
+ el.css( 'top', left + 'px' );
354
+ },
355
+ /**
356
+ * close an ad and add a cookie
357
+ *
358
+ * @param {str} element selector
359
+ */
360
+ close: function ( element ) {
361
+ var wrapper = jQuery( element );
362
+ // remove the ad
363
+ wrapper.remove();
364
+ },
365
+ /**
366
+ * Wait until images are ready.
367
+ *
368
+ * @param {obj} $el jQuery object.
369
+ * @param {function} ready_callback Ready callback.
370
+ * derrived from https://github.com/alexanderdickson/waitForImages/blob/master/dist/jquery.waitforimages.js
371
+ */
372
+ wait_for_images: function ( $el, ready_callback ) {
373
+ var loaded_count = 0;
374
+ var srcs = [];
375
+
376
+ $el.find( 'img[src][src!=""]' ).each( function () {
377
+ srcs.push( this.src );
378
+ } );
379
+
380
+ if ( srcs.length === 0 ) {
381
+ ready_callback.call( $el );
382
+ }
383
+
384
+ jQuery.each( srcs, function ( i, src ) {
385
+ var image = new Image();
386
+ image.src = src;
387
+ var events = 'load error';
388
+
389
+ jQuery( image ).one( events, function me( event ) {
390
+ // Remove remaining handler (either 'load' or 'error').
391
+ jQuery( this ).off( events, me );
392
+ loaded_count ++;
393
+
394
+ if ( loaded_count == srcs.length ) {
395
+ ready_callback.call( $el[0] );
396
+ return false;
397
+ }
398
+ } );
399
+ } );
400
+ },
401
+
402
+ privacy: {
403
+ state: 'unknown',
404
+ state_executed: false,
405
+ /**
406
+ * Get consent state.
407
+ * IIFE so the events fire only once per event.
408
+ *
409
+ * @return string
410
+ * 'not_needed' - consent is not needed.
411
+ * 'accepted' - consent was given.
412
+ * 'unknown' - consent was not given yet.
413
+ */
414
+ get_state: (
415
+ function () {
416
+ return function () {
417
+ // if we already have a state, return that.
418
+ if ( window.advads_options.privacy.state !== 'unknown' ) {
419
+ // make sure this only gets executed once.
420
+ if ( ! advads.privacy.state_executed ) {
421
+ advads.privacy.state_executed = true;
422
+ advads.privacy.dispatch_event( window.advads_options.privacy.state, false );
423
+ }
424
+ return advads.privacy.state;
425
+ }
426
+
427
+ // If using the cookie method, fire an initial event, regardless if cookie set or not.
428
+ if ( window.advads_options.privacy['consent-method'] === 'custom' ) {
429
+ var cookie_regex = new RegExp( window.advads_options.privacy['custom-cookie-name'] + '=.*?' + window.advads_options.privacy['custom-cookie-value'] + '[^;]*' );
430
+ // Force the event, if we haven't yet fired one.
431
+ if ( ! advads.privacy.state_executed ) {
432
+ advads.privacy.state_executed = true;
433
+ advads.privacy.dispatch_event( document.cookie.match( cookie_regex ) !== null ? 'accepted' : 'unknown', true );
434
+ }
435
+ }
436
+
437
+ // make sure this only gets executed once.
438
+ advads.privacy.state_executed = true;
439
+
440
+ // Run this in an interval (every 0.1s) just in case we are still waiting for consent
441
+ var cnt = 0,
442
+ consentSetInterval = setInterval( function () {
443
+ // Bail if we have not gotten a consent response after 60 seconds.
444
+ if ( ++ cnt === 600 ) {
445
+ clearInterval( consentSetInterval );
446
+ }
447
+ switch ( window.advads_options.privacy['consent-method'] ) {
448
+ case 'custom' :
449
+ // check if custom cookie is set and matches value.
450
+ if ( document.cookie.match( cookie_regex ) !== null ) {
451
+ clearInterval( consentSetInterval );
452
+ if ( advads.privacy.state !== 'accepted' ) {
453
+ advads.privacy.dispatch_event( 'accepted', true );
454
+ }
455
+ }
456
+ break;
457
+
458
+ case 'iab_tcf_20' :
459
+ // Check if window.__tcfapi has been set.
460
+ if ( typeof window.__tcfapi === 'undefined' ) {
461
+ return;
462
+ }
463
+ clearInterval( consentSetInterval );
464
+
465
+ window.__tcfapi( 'addEventListener', 2, function ( TCData, listenerSuccess ) {
466
+ if ( ! listenerSuccess ) {
467
+ return;
468
+ }
469
+ if (
470
+ TCData.eventStatus === 'tcloaded'
471
+ || TCData.eventStatus === 'useractioncomplete'
472
+ // if this is google funding choices, eventStatus is not set. Check if either gdpr doesn't apply or if there is a purpose object.
473
+ || ( TCData.eventStatus === null && typeof window.googlefc !== 'undefined' && (
474
+ typeof TCData.purpose !== 'undefined' || ! TCData.gdprApplies
475
+ ) )
476
+ ) {
477
+ var userAction = TCData.eventStatus === 'useractioncomplete';
478
+ if ( ! TCData.gdprApplies ) {
479
+ if ( advads.privacy.state !== 'not_needed' ) {
480
+ advads.privacy.dispatch_event( 'not_needed', userAction );
481
+ }
482
+ return;
483
+ }
484
+
485
+ if ( TCData.purpose.consents[1] ) {
486
+ if ( advads.privacy.state !== 'accepted' ) {
487
+ advads.privacy.dispatch_event( 'accepted', userAction );
488
+ }
489
+ return;
490
+ }
491
+
492
+ // fire another event, in case the user revokes the previous consent.
493
+ if ( advads.privacy.state !== 'rejected' ) {
494
+ advads.privacy.dispatch_event( 'rejected', userAction );
495
+ }
496
+ }
497
+ }
498
+ );
499
+ break;
500
+ }
501
+ }, 100 );
502
+
503
+ return advads.privacy.state;
504
+ }
505
+ }
506
+ )(),
507
+ /**
508
+ * Check if the privacy_method is custom cookie, and non personalized ads are allowed.
509
+ *
510
+ * @returns {boolean}
511
+ */
512
+ is_adsense_npa_enabled: function () {
513
+ if ( ! window.advads_options || ! window.advads_options.privacy ) {
514
+ return true;
515
+ }
516
+ return !! (
517
+ window.advads_options.privacy['show-non-personalized-adsense'] && window.advads_options.privacy['consent-method'] === 'custom'
518
+ );
519
+ },
520
+ /**
521
+ * Dispatch a custom event whenever the state changes.
522
+ *
523
+ * @param {String} state The current privacy state.
524
+ * @param {boolean} userAction This is result of action by user.
525
+ */
526
+ dispatch_event: function ( state, userAction ) {
527
+ var previousState = advads.privacy.state,
528
+ fire_event = function () {
529
+ document.dispatchEvent( new CustomEvent( 'advanced_ads_privacy', {
530
+ detail: {
531
+ state: state,
532
+ previousState: previousState,
533
+ userAction: userAction
534
+ }
535
+ } ) );
536
+ };
537
+
538
+ advads.privacy.state = state;
539
+
540
+ console.log( {
541
+ state: state,
542
+ previousState: previousState,
543
+ userAction: userAction
544
+ } );
545
+
546
+ // DOM is ready.
547
+ if ( document.readyState !== 'loading' ) {
548
+ return fire_event();
549
+ }
550
+
551
+ // If DOM is still loading, wait for it to be interactive/complete.
552
+ document.addEventListener( 'readystatechange', fire_event, {once: true} );
553
+ },
554
+ /**
555
+ * Check if ad is decoded.
556
+ *
557
+ * @param {integer} id
558
+ *
559
+ * @returns {boolean}
560
+ */
561
+ is_ad_decoded: function ( id ) {
562
+ return document.querySelector( 'script[data-tcf="waiting-for-consent"][data-id="' + id + '"]' ) === null;
563
+ },
564
+ /**
565
+ * Decode ad content.
566
+ *
567
+ * @param {Element} el
568
+ * @param {boolean} inject
569
+ */
570
+ decode_ad: function ( el, inject ) {
571
+ // this can also be a number if used in a foreach.
572
+ inject = typeof inject === 'boolean' ? inject : true;
573
+ var string = decodeURIComponent( Array.prototype.map.call( atob( el.textContent ), function ( c ) {
574
+ return '%' + (
575
+ '00' + c.charCodeAt( 0 ).toString( 16 )
576
+ ).slice( - 2 )
577
+ } ).join( '' ) );
578
+
579
+ if ( ! inject ) {
580
+ return string;
581
+ }
582
+
583
+ el.replaceWith( document.createRange().createContextualFragment( string ) );
584
+ }
585
+ }
586
+ };
587
+
588
+ (
589
+ window.advanced_ads_ready || jQuery( document ).ready
590
+ ).call( null, function () {
591
+ advads.privacy.get_state();
592
+ } );
593
+
594
+ document.addEventListener( 'advanced_ads_privacy', function ( event ) {
595
+ if (
596
+ (
597
+ event.detail.state !== 'accepted' && event.detail.state !== 'not_needed'
598
+ )
599
+ || event.detail.userAction
600
+ || document.readyState === 'loading'
601
+ ) {
602
+ return;
603
+ }
604
+
605
+ // Find all scripts waiting for consent and decode them.
606
+ document.querySelectorAll( 'script[type="text/plain"][data-tcf="waiting-for-consent"]' ).forEach( advads.privacy.decode_ad );
607
+ } );
608
+
609
+ // highlight elements in frontend, if local storage variable is set
610
+ jQuery( document ).ready( function () {
611
+
612
+ function is_enabled() {
613
+ if ( ! advads.supports_localstorage() || ! localStorage.getItem( 'advads_frontend_picker' ) ) {
614
+ return false;
615
+ }
616
+
617
+ // Check if the frontend picker was started on the current blog.
618
+ if ( window.advads_options.blog_id
619
+ && localStorage.getItem( 'advads_frontend_blog_id' )
620
+ && window.advads_options.blog_id !== localStorage.getItem( 'advads_frontend_blog_id' ) ) {
621
+ return false;
622
+ }
623
+
624
+ // Deactivate the frontend picker if it was started more than 45 minutes ago.
625
+ if ( localStorage.getItem( 'advads_frontend_starttime' )
626
+ && parseInt( localStorage.getItem( 'advads_frontend_starttime' ), 10 ) < (
627
+ new Date().getTime()
628
+ ) - 45 * 60 * 1000 ) {
629
+ localStorage.removeItem( 'advads_frontend_action' );
630
+ localStorage.removeItem( 'advads_frontend_element' );
631
+ localStorage.removeItem( 'advads_frontend_picker' );
632
+ localStorage.removeItem( 'advads_prev_url' );
633
+ localStorage.removeItem( 'advads_frontend_pathtype' );
634
+ localStorage.removeItem( 'advads_frontend_boundary' );
635
+ localStorage.removeItem( 'advads_frontend_blog_id' );
636
+ localStorage.removeItem( 'advads_frontend_starttime' );
637
+ advads.set_cookie( 'advads_frontend_picker', '', - 1 );
638
+ return false;
639
+ }
640
+
641
+ return true;
642
+ }
643
+
644
+ // only trigger if local storage is available
645
+ if ( is_enabled() ) {
646
+ var advads_picker_cur, advads_picker_overlay = jQuery( "<div id='advads-picker-overlay'>" ),
647
+ advads_picker_no = [document.body, document.documentElement, document];
648
+ advads_picker_overlay.css( {
649
+ position: 'absolute', border: 'solid 2px #428bca',
650
+ backgroundColor: 'rgba(66,139,202,0.5)', boxSizing: 'border-box',
651
+ zIndex: 1000000, pointerEvents: 'none'
652
+ } ).prependTo( 'body' );
653
+
654
+ if ( 'true' === localStorage.getItem( 'advads_frontend_boundary' ) ) {
655
+ jQuery( 'body' ).css( 'cursor', 'not-allowed' );
656
+ }
657
+
658
+ /**
659
+ * Check if we can traverse up the dom tree.
660
+ *
661
+ * We cannot use event delegation because:
662
+ * - the content can be loaded via AJAX dynamically
663
+ * - we cannot wrap the content in a `div` that represents post boundary
664
+ * because that may prevent css rules from working
665
+ *
666
+ * @param HTMLElement The current element.
667
+ * return bool
668
+ */
669
+ window.advads.is_boundary_reached = function ( advads_picker_cur ) {
670
+ if ( 'true' !== localStorage.getItem( 'advads_frontend_boundary' ) ) {
671
+ return false;
672
+ }
673
+ $advads_picker_cur = jQuery( advads_picker_cur );
674
+ // A boundary helper is the `ins` element inside of the post content
675
+ // that is used to determine the post boundary (where the content starts and ends).
676
+ var $boundary_helpers = jQuery( '.advads-frontend-picker-boundary-helper' );
677
+
678
+ $boundaries = $boundary_helpers.parent();
679
+ $boundaries.css( 'cursor', 'pointer' );
680
+ return $advads_picker_cur.is( $boundaries ) || ! $advads_picker_cur.closest( $boundaries ).length;
681
+ }
682
+
683
+ if ( 'xpath' === localStorage.getItem( 'advads_frontend_pathtype' ) ) {
684
+ var fn = 'getXPath';
685
+ } else {
686
+ var fn = 'getPath';
687
+ }
688
+
689
+ jQuery( document ).mousemove( function ( e ) {
690
+ if ( e.target === advads_picker_cur ) {
691
+ return;
692
+ }
693
+
694
+ if ( ~ advads_picker_no.indexOf( e.target ) ) {
695
+ advads_picker_cur = null;
696
+ advads_picker_overlay.hide();
697
+ return;
698
+ }
699
+
700
+ var target = jQuery( e.target ),
701
+ offset = target.offset(),
702
+ width = target.outerWidth(),
703
+ height = target.outerHeight();
704
+
705
+ advads_picker_cur = e.target;
706
+
707
+ var path = jQuery( advads_picker_cur )[fn]();
708
+ if ( ! path ) {
709
+ // A click outside of the boundary.
710
+ // @see `is_boundary_reached`.
711
+ return;
712
+ }
713
+ //log path
714
+ console.log( path );
715
+
716
+ advads_picker_overlay.css( {
717
+ top: offset.top,
718
+ left: offset.left,
719
+ width: width,
720
+ height: height
721
+ } ).show();
722
+
723
+ } );
724
+ // save on click
725
+ jQuery( document ).click( function ( e ) {
726
+ var path = jQuery( advads_picker_cur )[fn]();
727
+
728
+ if ( advads.is_boundary_reached( advads_picker_cur ) ) {
729
+ return;
730
+ }
731
+
732
+ localStorage.setItem( 'advads_frontend_element', path );
733
+ window.location = localStorage.getItem( 'advads_prev_url' );
734
+ } );
735
+ }
736
+ ;
737
+ } );
738
+ /*
739
+ derrived from jQuery-GetPath v0.01, by Dave Cardwell. (2007-04-27)
740
+ http://davecardwell.co.uk/javascript/jquery/plugins/jquery-getpath/
741
+ Usage:
742
+ var path = $('#foo').getPath();
743
+ */
744
+
745
+ jQuery.fn.extend( {
746
+ getPath: function ( path, depth ) {
747
+ // The first time this function is called, path won't be defined.
748
+ if ( typeof path === 'undefined' ) {
749
+ path = '';
750
+ }
751
+ if ( typeof depth === 'undefined' ) {
752
+ depth = 0;
753
+ }
754
+
755
+ // If this element is <html> we've reached the end of the path.
756
+ // also end after 2 elements
757
+ if ( this.is( 'html' ) ) {
758
+ return 'html > ' + path;
759
+ } else if ( 3 === depth ) {
760
+ return path;
761
+ }
762
+
763
+ // Add the element name.
764
+ var cur = this.get( 0 ).nodeName.toLowerCase();
765
+
766
+ // Determine the IDs and path.
767
+ var el_id = this.attr( 'id' ),
768
+ el_class = this.attr( 'class' );
769
+
770
+ depth = depth + 1;
771
+
772
+ // Add the #id if there is one. Ignore ID with number.
773
+ if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
774
+ cur += '#' + el_id;
775
+ } else if ( typeof el_class !== 'undefined' ) {
776
+ // Add classes if there is no id.
777
+ el_class = el_class.split( /[\s\n]+/ );
778
+ // Skip classes with numbers.
779
+ el_class = jQuery.grep( el_class, function ( element, index ) {
780
+ return ! /\d/.test( element )
781
+ } );
782
+ // Add 2 classes.
783
+ if ( el_class.length ) {
784
+ cur += '.' + el_class.slice( 0, 2 ).join( '.' );
785
+ }
786
+ }
787
+
788
+ // add index if this element is not unique among its siblings
789
+ if ( this.siblings( cur ).length ) {
790
+ cur += ":eq(" + this.siblings( cur ).addBack().not( '#advads-picker-overlay' ).index( this ) + ")";
791
+ }
792
+
793
+ // Recurse up the DOM.
794
+ if ( path === '' ) {
795
+ return this.parent().getPath( cur, depth );
796
+ } else {
797
+ return this.parent().getPath( cur + ' > ' + path, depth );
798
+ }
799
+ },
800
+
801
+ /**
802
+ * Get XPath.
803
+ */
804
+ getXPath: function ( path, depth ) {
805
+ // The first time this function is called, path won't be defined.
806
+ if ( typeof path === 'undefined' ) {
807
+ path = '';
808
+ }
809
+ if ( typeof depth === 'undefined' ) {
810
+ depth = 0;
811
+ }
812
+
813
+ // If this element is <html> we've reached the end of the path.
814
+ // also end after 2 elements
815
+ if ( this.is( 'body' ) || 3 === depth ) {
816
+ return path;
817
+ }
818
+
819
+ if ( advads.is_boundary_reached( this ) ) {
820
+ return path;
821
+ }
822
+
823
+ // Add the element name.
824
+ var tag = this.get( 0 ).nodeName.toLowerCase();
825
+ var cur = tag;
826
+
827
+ // Determine the IDs and path.
828
+ var el_id = this.attr( 'id' ),
829
+ el_class = this.attr( 'class' );
830
+ var classes = [];
831
+
832
+ // Add the #id if there is one. Ignore ID with number.
833
+ if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
834
+ return cur + '[@id and id="' + el_id + '"]/' + path;
835
+ } else if ( typeof el_class !== 'undefined' ) {
836
+ // Add classes if there is no id.
837
+ el_class = el_class.split( /[\s\n]+/ );
838
+ // Skip classes with numbers.
839
+ el_class = jQuery.grep( el_class, function ( element, index ) {
840
+ return ! /\d/.test( element )
841
+ } );
842
+ // Add 2 classes.
843
+ if ( el_class.length ) {
844
+ depth = depth + 1;
845
+ var classes = el_class.slice( 0, 2 );
846
+
847
+ var xpath_classes = [];
848
+ for ( var i = 0; i < classes.length; i ++ ) {
849
+ xpath_classes.push( '(@class and contains(concat(" ", normalize-space(@class), " "), " ' + classes[i] + ' "))' );
850
+ }
851
+ cur += '[' + xpath_classes.join( ' and ' ) + ']';
852
+ }
853
+ }
854
+
855
+ // Add index if this element is not unique among its siblings.
856
+ if ( classes.length ) {
857
+ var $siblings = this.siblings( tag + '.' + classes.join( '.' ) );
858
+ } else {
859
+ var $siblings = this.siblings( tag );
860
+ }
861
+
862
+ if ( $siblings.length ) {
863
+ var index = $siblings.addBack().not( '#advads-picker-overlay' ).index( this );
864
+ cur += '[' + index + ']';
865
+ }
866
+
867
+ // Recurse up the DOM.
868
+ if ( path === '' ) {
869
+ return this.parent().getXPath( cur, depth );
870
+ } else {
871
+ return this.parent().getXPath( cur + '/' + path, depth );
872
+ }
873
+ }
874
+ } );
public/assets/js/advanced.min.js ADDED
@@ -0,0 +1 @@
 
1
+ advads={supports_localstorage:function(){"use strict";try{return!(!window||void 0===window.localStorage)&&(window.localStorage.setItem("x","x"),window.localStorage.removeItem("x"),!0)}catch(e){return!1}},max_per_session:function(e,t){var a=1;if(void 0!==t&&0!==parseInt(t)||(t=1),this.cookie_exists(e)){if(this.get_cookie(e)>=t)return!0;a+=parseInt(this.get_cookie(e))}return this.set_cookie(e,a),!1},count_up:function(e,t){var a=1;this.cookie_exists(e)&&(a+=parseInt(this.get_cookie(e))),this.set_cookie(e,a)},set_cookie_exists:function(e){return!!get_cookie(e)||(set_cookie(e,"",0),!1)},get_cookie:function(e){var t,a,o,n=document.cookie.split(";");for(t=0;t<n.length;t++)if(a=n[t].substr(0,n[t].indexOf("=")),o=n[t].substr(n[t].indexOf("=")+1),(a=a.replace(/^\s+|\s+$/g,""))===e)return unescape(o)},set_cookie:function(e,t,a,o,n,i){var r=null==a?null:24*a*60*60;this.set_cookie_sec(e,t,r,o,n,i)},set_cookie_sec:function(e,t,a,o,n,i){var r=new Date;r.setSeconds(r.getSeconds()+parseInt(a)),document.cookie=e+"="+escape(t)+(null==a?"":"; expires="+r.toUTCString())+(null==o?"; path=/":"; path="+o)+(null==n?"":"; domain="+n)+(null==i?"":"; secure")},cookie_exists:function(e){var t=this.get_cookie(e);return null!==t&&""!==t&&void 0!==t},move:function(e,t,a){var o=jQuery(e);if(void 0===a&&(a={}),void 0===a.css&&(a.css={}),void 0===a.method&&(a.method="prependTo"),""===t&&void 0!==a.target)switch(a.target){case"wrapper":var n="left";void 0!==a.offset&&(n=a.offset),t=this.find_wrapper(e,n)}switch((t=void 0===a.moveintohidden?jQuery(t).filter(":visible"):jQuery(t)).length>1&&t.length,a.method){case"insertBefore":o.insertBefore(t);break;case"insertAfter":o.insertAfter(t);break;case"appendTo":o.appendTo(t);break;case"prependTo":o.prependTo(t);break;default:o.prependTo(t)}},set_parent_relative:function(e,t){t=void 0!==t?t:{};var a=jQuery(e).parent();t.use_grandparent&&(a=a.parent()),"static"!==a.css("position")&&""!==a.css("position")||a.css("position","relative")},fix_element:function(e,t){t=void 0!==t?t:{};var a=jQuery(e);t.use_grandparent?this.set_parent_relative(a.parent()):this.set_parent_relative(a),t.is_invisible&&a.show();var o=parseInt(a.offset().top),n=parseInt(a.offset().left);if(t.is_invisible&&a.hide(),"left"===t.offset){var i=jQuery(window).width()-n-a.outerWidth();a.css("position","fixed").css("top",o+"px").css("right",i+"px").css("left","")}else a.css("position","fixed").css("top",o+"px").css("left",n+"px").css("right","")},find_wrapper:function(e,t){var a;return jQuery("body").children().each((function(o,n){if(n.id!==e.substring(1)){var i=jQuery(n);if("right"===t&&i.offset().left+jQuery(i).width()<jQuery(window).width()||"left"===t&&i.offset().left>0)return"static"!==i.css("position")&&""!==i.css("position")||i.css("position","relative"),a=n,!1}})),a},center_fixed_element:function(e){var t=jQuery(e),a=jQuery(window).width()/2-parseInt(t.css("width"))/2;t.css("left",a+"px")},center_vertically:function(e){var t=jQuery(e),a=jQuery(window).height()/2-parseInt(t.css("height"))/2;"fixed"!==t.css("position")&&(a-=topoffset=parseInt(t.offset().top)),t.css("top",a+"px")},close:function(e){jQuery(e).remove()},wait_for_images:function(e,t){var a=0,o=[];e.find('img[src][src!=""]').each((function(){o.push(this.src)})),0===o.length&&t.call(e),jQuery.each(o,(function(n,i){var r=new Image;r.src=i;var s="load error";jQuery(r).one(s,(function n(i){if(jQuery(this).off(s,n),++a==o.length)return t.call(e[0]),!1}))}))},privacy:{state:"unknown",state_executed:!1,get_state:function(){if("unknown"!==window.advads_options.privacy.state)return advads.privacy.state_executed||(advads.privacy.state_executed=!0,advads.privacy.dispatch_event(window.advads_options.privacy.state,!1)),advads.privacy.state;if("custom"===window.advads_options.privacy["consent-method"]){var e=new RegExp(window.advads_options.privacy["custom-cookie-name"]+"=.*?"+window.advads_options.privacy["custom-cookie-value"]+"[^;]*");advads.privacy.state_executed||(advads.privacy.state_executed=!0,advads.privacy.dispatch_event(null!==document.cookie.match(e)?"accepted":"unknown",!0))}advads.privacy.state_executed=!0;var t=0,a=setInterval((function(){switch(600==++t&&clearInterval(a),window.advads_options.privacy["consent-method"]){case"custom":null!==document.cookie.match(e)&&(clearInterval(a),"accepted"!==advads.privacy.state&&advads.privacy.dispatch_event("accepted",!0));break;case"iab_tcf_20":if(void 0===window.__tcfapi)return;clearInterval(a),window.__tcfapi("addEventListener",2,(function(e,t){if(t&&("tcloaded"===e.eventStatus||"useractioncomplete"===e.eventStatus||null===e.eventStatus&&void 0!==window.googlefc&&(void 0!==e.purpose||!e.gdprApplies))){var a="useractioncomplete"===e.eventStatus;if(!e.gdprApplies)return void("not_needed"!==advads.privacy.state&&advads.privacy.dispatch_event("not_needed",a));if(e.purpose.consents[1])return void("accepted"!==advads.privacy.state&&advads.privacy.dispatch_event("accepted",a));"rejected"!==advads.privacy.state&&advads.privacy.dispatch_event("rejected",a)}}))}}),100);return advads.privacy.state},is_adsense_npa_enabled:function(){return!window.advads_options||!window.advads_options.privacy||!(!window.advads_options.privacy["show-non-personalized-adsense"]||"custom"!==window.advads_options.privacy["consent-method"])},dispatch_event:function(e,t){var a=advads.privacy.state,o=function(){document.dispatchEvent(new CustomEvent("advanced_ads_privacy",{detail:{state:e,previousState:a,userAction:t}}))};if(advads.privacy.state=e,"loading"!==document.readyState)return o();document.addEventListener("readystatechange",o,{once:!0})},is_ad_decoded:function(e){return null===document.querySelector('script[data-tcf="waiting-for-consent"][data-id="'+e+'"]')},decode_ad:function(e,t){t="boolean"!=typeof t||t;var a=decodeURIComponent(Array.prototype.map.call(atob(e.textContent),(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));if(!t)return a;e.replaceWith(document.createRange().createContextualFragment(a))}}},(window.advanced_ads_ready||jQuery(document).ready).call(null,(function(){advads.privacy.get_state()})),document.addEventListener("advanced_ads_privacy",(function(e){"accepted"!==e.detail.state&&"not_needed"!==e.detail.state||e.detail.userAction||"loading"===document.readyState||document.querySelectorAll('script[type="text/plain"][data-tcf="waiting-for-consent"]').forEach(advads.privacy.decode_ad)})),jQuery(document).ready((function(){if(!(!advads.supports_localstorage()||!localStorage.getItem("advads_frontend_picker")||window.advads_options.blog_id&&localStorage.getItem("advads_frontend_blog_id")&&window.advads_options.blog_id!==localStorage.getItem("advads_frontend_blog_id")||localStorage.getItem("advads_frontend_starttime")&&parseInt(localStorage.getItem("advads_frontend_starttime"),10)<(new Date).getTime()-27e5&&(localStorage.removeItem("advads_frontend_action"),localStorage.removeItem("advads_frontend_element"),localStorage.removeItem("advads_frontend_picker"),localStorage.removeItem("advads_prev_url"),localStorage.removeItem("advads_frontend_pathtype"),localStorage.removeItem("advads_frontend_boundary"),localStorage.removeItem("advads_frontend_blog_id"),localStorage.removeItem("advads_frontend_starttime"),advads.set_cookie("advads_frontend_picker","",-1),1))){var e,t=jQuery("<div id='advads-picker-overlay'>"),a=[document.body,document.documentElement,document];if(t.css({position:"absolute",border:"solid 2px #428bca",backgroundColor:"rgba(66,139,202,0.5)",boxSizing:"border-box",zIndex:1e6,pointerEvents:"none"}).prependTo("body"),"true"===localStorage.getItem("advads_frontend_boundary")&&jQuery("body").css("cursor","not-allowed"),window.advads.is_boundary_reached=function(e){if("true"!==localStorage.getItem("advads_frontend_boundary"))return!1;$advads_picker_cur=jQuery(e);var t=jQuery(".advads-frontend-picker-boundary-helper");return $boundaries=t.parent(),$boundaries.css("cursor","pointer"),$advads_picker_cur.is($boundaries)||!$advads_picker_cur.closest($boundaries).length},"xpath"===localStorage.getItem("advads_frontend_pathtype"))var o="getXPath";else o="getPath";jQuery(document).mousemove((function(n){if(n.target!==e){if(~a.indexOf(n.target))return e=null,void t.hide();var i=jQuery(n.target),r=i.offset(),s=i.outerWidth(),d=i.outerHeight();e=n.target;var c=jQuery(e)[o]();c&&t.css({top:r.top,left:r.left,width:s,height:d}).show()}})),jQuery(document).click((function(t){var a=jQuery(e)[o]();advads.is_boundary_reached(e)||(localStorage.setItem("advads_frontend_element",a),window.location=localStorage.getItem("advads_prev_url"))}))}})),jQuery.fn.extend({getPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("html"))return"html > "+e;if(3===t)return e;var a=this.get(0).nodeName.toLowerCase(),o=this.attr("id"),n=this.attr("class");return t+=1,void 0===o||/\d/.test(o)?void 0!==n&&(n=n.split(/[\s\n]+/),(n=jQuery.grep(n,(function(e,t){return!/\d/.test(e)}))).length&&(a+="."+n.slice(0,2).join("."))):a+="#"+o,this.siblings(a).length&&(a+=":eq("+this.siblings(a).addBack().not("#advads-picker-overlay").index(this)+")"),""===e?this.parent().getPath(a,t):this.parent().getPath(a+" > "+e,t)},getXPath:function(e,t){if(void 0===e&&(e=""),void 0===t&&(t=0),this.is("body")||3===t)return e;if(advads.is_boundary_reached(this))return e;var a=this.get(0).nodeName.toLowerCase(),o=a,n=this.attr("id"),i=this.attr("class"),r=[];if(void 0!==n&&!/\d/.test(n))return o+'[@id and id="'+n+'"]/'+e;if(void 0!==i&&(i=i.split(/[\s\n]+/),(i=jQuery.grep(i,(function(e,t){return!/\d/.test(e)}))).length)){t+=1;r=i.slice(0,2);for(var s=[],d=0;d<r.length;d++)s.push('(@class and contains(concat(" ", normalize-space(@class), " "), " '+r[d]+' "))');o+="["+s.join(" and ")+"]"}if(r.length)var c=this.siblings(a+"."+r.join("."));else c=this.siblings(a);c.length&&(o+="["+c.addBack().not("#advads-picker-overlay").index(this)+"]");return""===e?this.parent().getXPath(o,t):this.parent().getXPath(o+"/"+e,t)}});
public/assets/js/advanced.orig.js DELETED
@@ -1,815 +0,0 @@
1
- /*
2
- * advanced ads functions to be used directly within ad codes
3
- */
4
-
5
- advads = {
6
- /**
7
- * check if localstorage is supported/enabled by client
8
- */
9
- supports_localstorage: function() {
10
- "use strict";
11
- try {
12
- if (!window || window.localStorage === undefined) {
13
- return false;
14
- }
15
- // storage might be full or disabled
16
- window.localStorage.setItem("x", "x");
17
- window.localStorage.removeItem("x");
18
- return true;
19
- } catch(e) {
20
- return false;
21
- }
22
- },
23
- /**
24
- * check if the ad is displayed more than {max} times per session
25
- * every check increases the counter
26
- *
27
- * @param {string} name (no id needed, just any id-formated string)
28
- * @param {type} max number of maximum times the ad can be displayed within the period
29
- * @returns {bool} true if limit is reached
30
- */
31
- max_per_session: function(name, max){
32
- var num = 1;
33
- if(max === undefined || parseInt( max ) === 0) { max = 1; }
34
-
35
- // check if cookie exists and get the value
36
- if(this.cookie_exists( name )){
37
- if(this.get_cookie( name ) >= max) { return true; }
38
- num = num + parseInt( this.get_cookie( name ) );
39
- }
40
- this.set_cookie( name, num );
41
- return false;
42
- },
43
- /**
44
- * increase a cookie with an integer value by 1
45
- *
46
- * @param {str} name of the cookie
47
- * @param {int} exdays days until cookie expires
48
- */
49
- count_up: function( name, exdays ){
50
- var num = 1;
51
-
52
- // check if cookie exists and get the value
53
- if(this.cookie_exists( name )){
54
- num = num + parseInt( this.get_cookie( name ) );
55
- }
56
- this.set_cookie( name, num );
57
- },
58
- /**
59
- * return true, if cookie exists
60
- * return false, if not
61
- * if not exists, create it
62
- * use case: to check if something already happened in this page impression
63
- *
64
- * @param {type} name
65
- * @returns {unresolved}
66
- */
67
- set_cookie_exists: function( name ){
68
- if( get_cookie(name) ){
69
- return true;
70
- }
71
- set_cookie( name, '', 0 );
72
- return false;
73
- },
74
- /**
75
- * get a cookie value
76
- *
77
- * @param {str} name of the cookie
78
- */
79
- get_cookie: function (name) {
80
- var i, x, y, ADVcookies = document.cookie.split( ";" );
81
- for (i = 0; i < ADVcookies.length; i++)
82
- {
83
- x = ADVcookies[i].substr( 0, ADVcookies[i].indexOf( "=" ) );
84
- y = ADVcookies[i].substr( ADVcookies[i].indexOf( "=" ) + 1 );
85
- x = x.replace( /^\s+|\s+$/g, "" );
86
- if (x === name)
87
- {
88
- return unescape( y );
89
- }
90
- }
91
- },
92
- /**
93
- * set a cookie value
94
- *
95
- * @param {str} name of the cookie
96
- * @param {str} value of the cookie
97
- * @param {int} exdays days until cookie expires
98
- * set 0 to expire cookie immidiatelly
99
- * set null to expire cookie in the current session
100
- */
101
- set_cookie: function (name, value, exdays, path, domain, secure) {
102
- // days in seconds
103
- var expiry = ( exdays == null ) ? null : exdays * 24 * 60 * 60;
104
- this.set_cookie_sec( name, value, expiry, path, domain, secure );
105
- },
106
- /**
107
- * set a cookie with expiry given in seconds
108
- *
109
- * @param {str} name of the cookie
110
- * @param {str} value of the cookie
111
- * @param {int} expiry seconds until cookie expires
112
- * set 0 to expire cookie immidiatelly
113
- * set null to expire cookie in the current session
114
- */
115
- set_cookie_sec: function (name, value, expiry, path, domain, secure) {
116
- var exdate = new Date();
117
- exdate.setSeconds( exdate.getSeconds() + parseInt( expiry ) );
118
- document.cookie = name + "=" + escape( value ) +
119
- ((expiry == null) ? "" : "; expires=" + exdate.toUTCString()) +
120
- ((path == null) ? "; path=/" : "; path=" + path) +
121
- ((domain == null) ? "" : "; domain=" + domain) +
122
- ((secure == null) ? "" : "; secure");
123
- },
124
- /**
125
- * check if a cookie is set and contains a value
126
- *
127
- * @param {str} name of the cookie
128
- * @returns {bool} true, if cookie is set
129
- */
130
- cookie_exists: function (name)
131
- {
132
- var c_value = this.get_cookie( name );
133
- if (c_value !== null && c_value !== "" && c_value !== undefined)
134
- {
135
- return true;
136
- }
137
- return false;
138
- },
139
- /**
140
- * move one element into another
141
- *
142
- * @param {str} element selector of the element that should be moved
143
- * @param {str} target selector of the element where to move
144
- * @param {arr} options
145
- */
146
- move: function( element, target, options )
147
- {
148
-
149
- var el = jQuery(element);
150
- var target_string = target;
151
-
152
- if( typeof options === 'undefined' ){
153
- options = {};
154
- }
155
- if( typeof options.css === 'undefined' ){
156
- options.css = {};
157
- }
158
- if( typeof options.method === 'undefined' ){
159
- options.method = 'prependTo';
160
- }
161
-
162
- // search for abstract target element
163
- if( target === '' && typeof options.target !== 'undefined' ){
164
- switch( options.target ){
165
- case 'wrapper' : // wrapper
166
- var offset = 'left';
167
- if( typeof options.offset !== 'undefined' ){
168
- offset = options.offset;
169
- }
170
- target = this.find_wrapper( element, offset );
171
- break;
172
- }
173
- }
174
-
175
- // use only visible elements
176
- if( typeof options.moveintohidden === 'undefined' ){
177
- target = jQuery( target ).filter(':visible');
178
- } else {
179
- target = jQuery( target );
180
- }
181
-
182
- // print warning in console if the element appears multiple times
183
- if( target.length > 1 ){
184
- console.log( "Advanced Ads: element '" + target_string + "' found " + target.length + " times." );
185
- }
186
-
187
- // switch insert method
188
- switch( options.method ){
189
- case 'insertBefore' :
190
- el.insertBefore(target);
191
- break;
192
- case 'insertAfter' :
193
- el.insertAfter(target);
194
- break;
195
- case 'appendTo' :
196
- el.appendTo(target);
197
- break;
198
- case 'prependTo' :
199
- el.prependTo(target);
200
- break;
201
- default :
202
- el.prependTo(target);
203
- }
204
- },
205
-
206
- /**
207
- * Set 'relative' position for a parent element.
208
- *
209
- * @param {str} element selector
210
- */
211
- set_parent_relative: function( element, options ) {
212
- var options = typeof options !== 'undefined' ? options: {};
213
- var el = jQuery(element);
214
- // give "position" style to parent element, if missing
215
- var parent = el.parent();
216
-
217
- if ( options.use_grandparent ) {
218
- parent = parent.parent();
219
- }
220
-
221
- if(parent.css('position') === 'static' || parent.css('position') === ''){
222
- parent.css('position', 'relative');
223
- }
224
- },
225
-
226
- /**
227
- * make an absolute position element fixed at the current position
228
- * hint: use only after DOM is fully loaded in order to fix a wrong position
229
- *
230
- * @param {str} element selector
231
- * @param {obj} options
232
- */
233
- fix_element: function( element, options ){
234
- var options = typeof options !== 'undefined' ? options: {};
235
-
236
- var el = jQuery(element);
237
-
238
- if ( options.use_grandparent ) {
239
- this.set_parent_relative( el.parent() );
240
- } else {
241
- this.set_parent_relative( el );
242
- }
243
-
244
- // fix element at current position
245
- // get position for hidden elements by showing them for a very short time
246
- if ( options.is_invisible ) {
247
- el.show();
248
- }
249
- var topoffset = parseInt(el.offset().top);
250
- var leftoffset = parseInt(el.offset().left);
251
- if ( options.is_invisible ) {
252
- el.hide();
253
- }
254
- if ( 'left' === options.offset ) {
255
- // Allow to scale the nested image down when it has `max-width: 100%` and touches the left edge of the viewport.
256
- var rightoffset = jQuery( window ).width() - leftoffset - el.outerWidth();
257
- el.css( 'position', 'fixed' ).css( 'top', topoffset + 'px' ).css( 'right', rightoffset + 'px' ).css( 'left', '' );
258
- } else {
259
- // reset "right" to prevent conflicts
260
- el.css('position', 'fixed').css('top', topoffset + 'px').css('left', leftoffset + 'px').css('right', '');
261
- }
262
-
263
- },
264
-
265
- /**
266
- * find the main wrapper
267
- * either id or first of its class
268
- *
269
- * @param {str} element selector
270
- * @param {str} offset which position of the offset to check (left or right)
271
- * @return {str} selector
272
- */
273
- find_wrapper: function( element, offset ){
274
- // first margin: auto element after body
275
- var returnValue;
276
- jQuery('body').children().each(function(key, value){
277
- // exclude current element
278
- // TODO exclude <script>
279
- if( value.id !== element.substring(1) ){
280
- // check offset value
281
- var checkedelement = jQuery( value );
282
- // check if there is space left or right of the element
283
- if( ( offset === 'right' && ( checkedelement.offset().left + jQuery(checkedelement).width() < jQuery(window).width() ) ) ||
284
- ( offset === 'left' && checkedelement.offset().left > 0 ) ){
285
- // fix element
286
- if( checkedelement.css('position') === 'static' || checkedelement.css('position') === ''){
287
- checkedelement.css('position', 'relative');
288
- }
289
- // set return value
290
- returnValue = value;
291
- return false;
292
- }
293
- }
294
- });
295
- return returnValue;
296
- },
297
- /**
298
- * center fixed element on the screen
299
- *
300
- * @param {str} element selector
301
- */
302
- center_fixed_element: function( element ){
303
- var el = jQuery(element);
304
- // half window width minus half element width
305
- var left = ( jQuery(window).width() / 2 ) - ( parseInt( el.css('width')) / 2 );
306
- el.css('left', left + 'px');
307
- },
308
- /**
309
- * center element vertically on the screen
310
- *
311
- * @param {str} element selector
312
- */
313
- center_vertically: function( element ){
314
- var el = jQuery(element);
315
- // half window height minus half element height
316
- var left = ( jQuery(window).height() / 2 ) - ( parseInt( el.css('height')) / 2 );
317
-
318
- // Center correctly when the ad is attached to the element that begins lower.
319
- if ( el.css( 'position' ) !== 'fixed' ) {
320
- left -= topoffset = parseInt( el.offset().top );
321
- }
322
- el.css('top', left + 'px');
323
- },
324
- /**
325
- * close an ad and add a cookie
326
- *
327
- * @param {str} element selector
328
- */
329
- close: function( element ){
330
- var wrapper = jQuery(element);
331
- // remove the ad
332
- wrapper.remove();
333
- },
334
- /**
335
- * Wait until images are ready.
336
- *
337
- * @param {obj} $el jQuery object.
338
- * @param {function} ready_callback Ready callback.
339
- * derrived from https://github.com/alexanderdickson/waitForImages/blob/master/dist/jquery.waitforimages.js
340
- */
341
- wait_for_images: function( $el, ready_callback ) {
342
- var loaded_count = 0;
343
- var srcs = [];
344
-
345
- $el.find( 'img[src][src!=""]' ).each( function () {
346
- srcs.push( this.src );
347
- });
348
-
349
- if ( srcs.length === 0 ) {
350
- ready_callback.call( $el );
351
- }
352
-
353
- jQuery.each( srcs, function( i, src ) {
354
- var image = new Image();
355
- image.src = src;
356
- var events = 'load error';
357
-
358
- jQuery( image ).one( events, function me( event ) {
359
- // Remove remaining handler (either 'load' or 'error').
360
- jQuery( this ).off( events, me );
361
- loaded_count++;
362
-
363
- if ( loaded_count == srcs.length ) {
364
- ready_callback.call( $el[0] );
365
- return false;
366
- }
367
- } );
368
- } );
369
- },
370
-
371
- privacy: {
372
- state: 'unknown',
373
- state_executed: false,
374
- /**
375
- * Get consent state.
376
- * IIFE so the events fire only once per event.
377
- *
378
- * @return string
379
- * 'not_needed' - consent is not needed.
380
- * 'accepted' - consent was given.
381
- * 'unknown' - consent was not given yet.
382
- */
383
- get_state: (function () {
384
- return function () {
385
- // if we already have a state, return that.
386
- if (window.advads_options.privacy.state !== 'unknown') {
387
- // make sure this only gets executed once.
388
- if (!advads.privacy.state_executed) {
389
- advads.privacy.state_executed = true;
390
- advads.privacy.dispatch_event(window.advads_options.privacy.state, false);
391
- }
392
- return advads.privacy.state;
393
- }
394
-
395
- // If using the cookie method, fire an initial event, regardless if cookie set or not.
396
- if (window.advads_options.privacy['consent-method'] === 'custom') {
397
- var cookie_regex = new RegExp(window.advads_options.privacy['custom-cookie-name'] + '=.*?' + window.advads_options.privacy['custom-cookie-value'] + '[^;]*');
398
- // Force the event, if we haven't yet fired one.
399
- if (!advads.privacy.state_executed) {
400
- advads.privacy.state_executed = true;
401
- advads.privacy.dispatch_event(document.cookie.match(cookie_regex) !== null ? 'accepted' : 'unknown', true);
402
- }
403
- }
404
-
405
- // make sure this only gets executed once.
406
- advads.privacy.state_executed = true;
407
-
408
- // Run this in an interval (every 0.1s) just in case we are still waiting for consent
409
- var cnt = 0,
410
- consentSetInterval = setInterval(function () {
411
- // Bail if we have not gotten a consent response after 60 seconds.
412
- if (++cnt === 600) {
413
- clearInterval(consentSetInterval);
414
- }
415
- switch (window.advads_options.privacy['consent-method']) {
416
- case 'custom' :
417
- // check if custom cookie is set and matches value.
418
- if (document.cookie.match(cookie_regex) !== null) {
419
- clearInterval(consentSetInterval);
420
- if (advads.privacy.state !== 'accepted') {
421
- advads.privacy.dispatch_event('accepted', true);
422
- }
423
- }
424
- break;
425
-
426
- case 'iab_tcf_20' :
427
- // Check if window.__tcfapi has been set.
428
- if (typeof window.__tcfapi === 'undefined') {
429
- return;
430
- }
431
- clearInterval(consentSetInterval);
432
-
433
- window.__tcfapi('addEventListener', 2, function (TCData, listenerSuccess) {
434
- if (!listenerSuccess) {
435
- return;
436
- }
437
- if (TCData.eventStatus === 'tcloaded' || TCData.eventStatus === 'useractioncomplete') {
438
- var userAction = TCData.eventStatus === 'useractioncomplete';
439
- if (!TCData.gdprApplies) {
440
- if (advads.privacy.state !== 'not_needed') {
441
- advads.privacy.dispatch_event('not_needed', userAction);
442
- }
443
- return;
444
- }
445
-
446
- if (TCData.purpose.consents[1]) {
447
- if (advads.privacy.state !== 'accepted') {
448
- advads.privacy.dispatch_event('accepted', userAction);
449
- }
450
- return;
451
- }
452
-
453
- // fire another event, in case the user revokes the previous consent.
454
- if (advads.privacy.state !== 'rejected') {
455
- advads.privacy.dispatch_event('rejected', userAction);
456
- }
457
- }
458
- }
459
- );
460
- break;
461
- }
462
- }, 100);
463
-
464
- return advads.privacy.state;
465
- }
466
- })(),
467
- /**
468
- * Check if the privacy_method is custom cookie, and non personalized ads are allowed.
469
- *
470
- * @returns {boolean}
471
- */
472
- is_adsense_npa_enabled: function () {
473
- if (!window.advads_options || !window.advads_options.privacy) {
474
- return true;
475
- }
476
- return !!(window.advads_options.privacy['show-non-personalized-adsense'] && window.advads_options.privacy['consent-method'] === 'custom');
477
- },
478
- /**
479
- * Dispatch a custom event whenever the state changes.
480
- *
481
- * @param {String} state The current privacy state.
482
- * @param {boolean} userAction This is result of action by user.
483
- */
484
- dispatch_event: function (state, userAction) {
485
- var previousState = advads.privacy.state,
486
- fire_event = function () {
487
- document.dispatchEvent(new CustomEvent('advanced_ads_privacy', {
488
- detail: {
489
- state: state,
490
- previousState: previousState,
491
- userAction: userAction
492
- }
493
- }));
494
- };
495
-
496
- advads.privacy.state = state;
497
-
498
- console.log({
499
- state: state,
500
- previousState: previousState,
501
- userAction: userAction
502
- });
503
-
504
- // DOM is ready.
505
- if (document.readyState !== 'loading') {
506
- return fire_event();
507
- }
508
-
509
- // If DOM is still loading, wait for it to be interactive/complete.
510
- document.addEventListener('readystatechange', fire_event, {once: true});
511
- },
512
- /**
513
- * Check if ad is decoded.
514
- *
515
- * @param {integer} id
516
- *
517
- * @returns {boolean}
518
- */
519
- is_ad_decoded: function(id) {
520
- return document.querySelector('script[data-tcf="waiting-for-consent"][data-id="' + id + '"]') === null;
521
- },
522
- /**
523
- * Decode ad content.
524
- *
525
- * @param {Element} el
526
- * @param {boolean} inject
527
- */
528
- decode_ad: function (el, inject) {
529
- // this can also be a number if used in a foreach.
530
- inject = typeof inject === 'boolean' ? inject : true;
531
- var string = decodeURIComponent(Array.prototype.map.call(atob(el.textContent), function (c) {
532
- return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
533
- }).join(''));
534
-
535
- if (!inject) {
536
- return string;
537
- }
538
-
539
- el.replaceWith(document.createRange().createContextualFragment(string));
540
- }
541
- }
542
- };
543
-
544
- (window.advanced_ads_ready || jQuery(document).ready).call(null, function () {
545
- advads.privacy.get_state();
546
- });
547
-
548
- document.addEventListener('advanced_ads_privacy', function (event) {
549
- if (
550
- (event.detail.state !== 'accepted' && event.detail.state !== 'not_needed')
551
- || event.detail.userAction
552
- || document.readyState === 'loading'
553
- ) {
554
- return;
555
- }
556
-
557
- // Find all scripts waiting for consent and decode them.
558
- document.querySelectorAll('script[type="text/plain"][data-tcf="waiting-for-consent"]').forEach(advads.privacy.decode_ad);
559
- });
560
-
561
- // highlight elements in frontend, if local storage variable is set
562
- jQuery(document).ready(function(){
563
-
564
- function is_enabled() {
565
- if ( ! advads.supports_localstorage() || ! localStorage.getItem('advads_frontend_picker') ) {
566
- return false;
567
- }
568
-
569
- // Check if the frontend picker was started on the current blog.
570
- if ( window.advads_options.blog_id
571
- && localStorage.getItem( 'advads_frontend_blog_id' )
572
- && window.advads_options.blog_id !== localStorage.getItem( 'advads_frontend_blog_id' ) ) {
573
- return false;
574
- }
575
-
576
-
577
- // Deactivate the frontend picker if it was started more than 45 minutes ago.
578
- if ( localStorage.getItem( 'advads_frontend_starttime' )
579
- && parseInt( localStorage.getItem( 'advads_frontend_starttime' ), 10 ) < ( new Date().getTime() ) - 45 * 60 * 1000 ) {
580
- localStorage.removeItem( 'advads_frontend_action' );
581
- localStorage.removeItem( 'advads_frontend_element' );
582
- localStorage.removeItem( 'advads_frontend_picker' );
583
- localStorage.removeItem( 'advads_prev_url' );
584
- localStorage.removeItem( 'advads_frontend_pathtype' );
585
- localStorage.removeItem( 'advads_frontend_boundary' );
586
- localStorage.removeItem( 'advads_frontend_blog_id' );
587
- localStorage.removeItem( 'advads_frontend_starttime' );
588
- advads.set_cookie( 'advads_frontend_picker', '', -1 );
589
- return false;
590
- }
591
-
592
- return true;
593
- }
594
-
595
- // only trigger if local storage is available
596
- if ( is_enabled() ) {
597
- var advads_picker_cur, advads_picker_overlay = jQuery("<div id='advads-picker-overlay'>"),
598
- advads_picker_no = [document.body, document.documentElement, document];
599
- advads_picker_overlay.css({position: 'absolute', border: 'solid 2px #428bca',
600
- backgroundColor: 'rgba(66,139,202,0.5)', boxSizing: 'border-box',
601
- zIndex: 1000000, pointerEvents: 'none'}).prependTo('body');
602
-
603
- if ( 'true' === localStorage.getItem( 'advads_frontend_boundary' ) ) {
604
- jQuery( 'body' ).css( 'cursor', 'not-allowed' );
605
- }
606
-
607
- /**
608
- * Check if we can traverse up the dom tree.
609
- *
610
- * We cannot use event delegation because:
611
- * - the content can be loaded via AJAX dynamically
612
- * - we cannot wrap the content in a `div` that represents post boundary
613
- * because that may prevent css rules from working
614
- *
615
- * @param HTMLElement The current element.
616
- * return bool
617
- */
618
- window.advads.is_boundary_reached = function( advads_picker_cur ) {
619
- if ( 'true' !== localStorage.getItem( 'advads_frontend_boundary' ) ) {
620
- return false;
621
- }
622
- $advads_picker_cur = jQuery( advads_picker_cur );
623
- // A boundary helper is the `ins` element inside of the post content
624
- // that is used to determine the post boundary (where the content starts and ends).
625
- var $boundary_helpers = jQuery( '.advads-frontend-picker-boundary-helper' );
626
-
627
- $boundaries = $boundary_helpers.parent();
628
- $boundaries.css( 'cursor', 'pointer' );
629
- return $advads_picker_cur.is( $boundaries ) || ! $advads_picker_cur.closest( $boundaries ).length;
630
- }
631
-
632
- if ( 'xpath' === localStorage.getItem( 'advads_frontend_pathtype' ) ) {
633
- var fn = 'getXPath';
634
- } else {
635
- var fn = 'getPath';
636
- }
637
-
638
-
639
- jQuery(document).mousemove(function(e) {
640
- if (e.target === advads_picker_cur) {
641
- return;
642
- }
643
-
644
- if (~advads_picker_no.indexOf(e.target)) {
645
- advads_picker_cur = null;
646
- advads_picker_overlay.hide();
647
- return;
648
- }
649
-
650
- var target = jQuery(e.target),
651
- offset = target.offset(),
652
- width = target.outerWidth(),
653
- height = target.outerHeight();
654
-
655
- advads_picker_cur = e.target;
656
-
657
- var path = jQuery( advads_picker_cur )[fn]();
658
- if ( ! path ) {
659
- // A click outside of the boundary.
660
- // @see `is_boundary_reached`.
661
- return;
662
- }
663
- //log path
664
- console.log( path);
665
-
666
- advads_picker_overlay.css({
667
- top: offset.top,
668
- left: offset.left,
669
- width: width,
670
- height: height
671
- }).show();
672
-
673
- });
674
- // save on click
675
- jQuery(document).click(function(e) {
676
- var path = jQuery( advads_picker_cur )[fn]();
677
-
678
- if ( advads.is_boundary_reached( advads_picker_cur )) {
679
- return;
680
- }
681
-
682
- localStorage.setItem( 'advads_frontend_element', path );
683
- window.location = localStorage.getItem('advads_prev_url');
684
- });
685
- };
686
- });
687
- /*
688
- derrived from jQuery-GetPath v0.01, by Dave Cardwell. (2007-04-27)
689
- http://davecardwell.co.uk/javascript/jquery/plugins/jquery-getpath/
690
- Usage:
691
- var path = $('#foo').getPath();
692
- */
693
-
694
- jQuery.fn.extend({
695
- getPath: function( path, depth ) {
696
- // The first time this function is called, path won't be defined.
697
- if ( typeof path === 'undefined' ) path = '';
698
- if ( typeof depth === 'undefined' ) depth = 0;
699
-
700
- // If this element is <html> we've reached the end of the path.
701
- // also end after 2 elements
702
- if ( this.is('html')){
703
- return 'html > ' + path;
704
- } else if ( 3 === depth ){
705
- return path;
706
- }
707
-
708
- // Add the element name.
709
- var cur = this.get(0).nodeName.toLowerCase();
710
-
711
- // Determine the IDs and path.
712
- var el_id = this.attr('id'),
713
- el_class = this.attr('class');
714
-
715
- depth = depth + 1;
716
-
717
- // Add the #id if there is one. Ignore ID with number.
718
- if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
719
- cur += '#' + el_id;
720
- } else if ( typeof el_class !== 'undefined' ){
721
- // Add classes if there is no id.
722
- el_class = el_class.split( /[\s\n]+/ );
723
- // Skip classes with numbers.
724
- el_class = jQuery.grep( el_class, function( element, index ) {
725
- return ! /\d/.test( element )
726
- });
727
- // Add 2 classes.
728
- if ( el_class.length ) {
729
- cur += '.' + el_class.slice( 0, 2 ).join( '.' );
730
- }
731
- }
732
-
733
- // add index if this element is not unique among its siblings
734
- if( this.siblings( cur ).length ){
735
- cur += ":eq(" + this.siblings( cur ).addBack().not( '#advads-picker-overlay' ).index( this ) + ")";
736
- }
737
-
738
- // Recurse up the DOM.
739
- if( path === '' ){
740
- return this.parent().getPath( cur, depth );
741
- } else {
742
- return this.parent().getPath( cur + ' > ' + path, depth );
743
- }
744
- },
745
-
746
- /**
747
- * Get XPath.
748
- */
749
- getXPath: function( path, depth ) {
750
- // The first time this function is called, path won't be defined.
751
- if ( typeof path === 'undefined' ) path = '';
752
- if ( typeof depth === 'undefined' ) depth = 0;
753
-
754
- // If this element is <html> we've reached the end of the path.
755
- // also end after 2 elements
756
- if ( this.is('body') || 3 === depth){
757
- return path;
758
- }
759
-
760
- if ( advads.is_boundary_reached( this )) {
761
- return path;
762
- }
763
-
764
- // Add the element name.
765
- var tag = this.get(0).nodeName.toLowerCase();
766
- var cur = tag;
767
-
768
- // Determine the IDs and path.
769
- var el_id = this.attr('id'),
770
- el_class = this.attr('class');
771
- var classes = [];
772
-
773
- // Add the #id if there is one. Ignore ID with number.
774
- if ( typeof el_id !== 'undefined' && ! /\d/.test( el_id ) ) {
775
- return cur + '[@id and id="' + el_id + '"]/' + path;
776
- } else if ( typeof el_class !== 'undefined' ){
777
- // Add classes if there is no id.
778
- el_class = el_class.split( /[\s\n]+/ );
779
- // Skip classes with numbers.
780
- el_class = jQuery.grep( el_class, function( element, index ) {
781
- return ! /\d/.test( element )
782
- });
783
- // Add 2 classes.
784
- if ( el_class.length ) {
785
- depth = depth + 1;
786
- var classes = el_class.slice( 0, 2 );
787
-
788
- var xpath_classes = [];
789
- for ( var i = 0; i < classes.length; i++ ) {
790
- xpath_classes.push( '(@class and contains(concat(" ", normalize-space(@class), " "), " ' + classes[ i ] + ' "))');
791
- }
792
- cur += '[' + xpath_classes.join( ' and ' ) + ']';
793
- }
794
- }
795
-
796
- // Add index if this element is not unique among its siblings.
797
- if ( classes.length ) {
798
- var $siblings = this.siblings( tag + '.' + classes.join( '.' ) );
799
- } else {
800
- var $siblings = this.siblings( tag );
801
- }
802
-
803
- if ( $siblings.length ) {
804
- var index = $siblings.addBack().not( '#advads-picker-overlay' ).index( this );
805
- cur += '[' + index + ']';
806
- }
807
-
808
- // Recurse up the DOM.
809
- if( path === '' ){
810
- return this.parent().getXPath( cur, depth );
811
- } else {
812
- return this.parent().getXPath( cur + '/' + path, depth );
813
- }
814
- }
815
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: ads, ad manager, ad rotation, adsense, banner
4
  Requires at least: 4.6
5
  Tested up to: 5.5
6
  Requires PHP: 5.6
7
- Stable tag: 1.20.2
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -317,6 +317,13 @@ Yes. You can use plenty of [hooks](https://wpadvancedads.com/codex/) to customiz
317
 
318
  == Changelog ==
319
 
 
 
 
 
 
 
 
320
  = 1.20.2 =
321
 
322
  - fixed displaying image ads if privacy method is set to custom cookie
4
  Requires at least: 4.6
5
  Tested up to: 5.5
6
  Requires PHP: 5.6
7
+ Stable tag: 1.20.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
317
 
318
  == Changelog ==
319
 
320
+ = 1.20.3 =
321
+
322
+ - whitelist field groups created by Advanced Custom Fields on the ad edit page
323
+ - prevent including AdSense Auto ads code when the Borlabs Cookie is already adding it
324
+ - prevented adding unneeded escape characters to ads.txt file
325
+ - added compatibility with Funding Choices when consent is not needed
326
+
327
  = 1.20.2 =
328
 
329
  - fixed displaying image ads if privacy method is set to custom cookie