PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.25
Advanced Ads – Ad Manager & AdSense v2.0.25
2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / admin / assets / js / admin.js
advanced-ads / admin / assets / js Last commit date
adblocker-image-data.js 1 year ago admin-global.js 1 year ago admin.js 2 days ago advertisement.js 3 months ago conditions.js 1 year ago dialog-advads-modal.js 1 year ago termination.js 1 year ago ui.js 3 years ago
admin.js
1766 lines
1 /* eslint-disable */
2 jQuery(document).ready(function ($) {
3 $(document).on('click', '#switch-to-adsense-type', function (ev) {
4 ev.preventDefault();
5 AdvancedAdsAdmin.AdImporter.adsenseCode =
6 Advanced_Ads_Admin.get_ad_source_editor_text();
7 $('#advanced-ad-type-adsense').trigger('click');
8 $(this).closest('li').addClass('hidden');
9 });
10
11 // activate general buttons
12 $('.advads-buttonset').advads_buttonset();
13 // activate accordions
14 if ($.fn.accordion) {
15 $('.advads-accordion').accordion({
16 active: false,
17 collapsible: true,
18 });
19 }
20
21 // AD OVERVIEW PAGE
22
23 $('.advads-ad-list-tooltip').advads_tooltip({
24 content() {
25 return jQuery(this).find('.advads-ad-list-tooltip-content').html();
26 },
27 });
28
29 /**
30 * Logic for placement list
31 */
32 (() => {
33 let selectedValue = '0';
34 let searchTerm = '';
35 const placementRows = jQuery('.advads-placements-table tbody tr');
36 const showHidePlacementRow = (callback) => {
37 placementRows.each((index, element) => {
38 const $row = jQuery(element);
39 const rowData = $row.data('order');
40
41 if (
42 typeof rowData === 'undefined' ||
43 typeof rowData.type === 'undefined' ||
44 typeof rowData.name === 'undefined'
45 ) {
46 $row.show();
47 return;
48 }
49
50 $row.toggle(
51 (selectedValue === '0' || rowData.type === selectedValue) &&
52 (searchTerm === '' ||
53 rowData.name
54 .toLowerCase()
55 .indexOf(searchTerm.toLowerCase()) !== -1)
56 );
57 });
58 };
59 // filter placement by type
60 jQuery('.advads_filter_placement_type').on('change', function () {
61 selectedValue = jQuery(this).val();
62 showHidePlacementRow();
63 });
64
65 // search placement by name
66 jQuery('.advads_search_placement_name').on('keyup', function () {
67 searchTerm = this.value;
68 showHidePlacementRow();
69 });
70 })();
71
72 /**
73 * Filter ad/ad group selection in new placement form.
74 */
75 (() => {
76 const placementTypeRadios = document.querySelectorAll(
77 '[name="advads[placement][type]"]'
78 );
79
80 placementTypeRadios.forEach((radio) => {
81 radio.addEventListener('input', (event) => {
82 jQuery('[name="advads[placement][item]"]').attr(
83 'disabled',
84 true
85 );
86
87 wp.ajax
88 .post(window.advadstxt.placements_allowed_ads.action, {
89 _ajax_nonce:
90 window.advadstxt.placements_allowed_ads.nonce,
91 placement_type: event.target.value,
92 })
93 .done((response) => {
94 jQuery('[name="advads[placement][item]"]').replaceWith(
95 wp.template('advads-placement-ad-select')({
96 items: Object.values(response.items),
97 })
98 );
99 });
100 });
101 });
102 })();
103
104 // sort placement by type order or name
105 jQuery('.advads-sort').on('click', function (e) {
106 const sort = jQuery(this);
107 const orderBy = sort.data('orderby');
108 const table = jQuery('.advads-placements-table');
109 const rows = jQuery('> tbody > tr', table);
110 const links = jQuery('> thead th > a', table);
111 links.each(function () {
112 jQuery(this).removeClass('advads-placement-sorted');
113 });
114 sort.addClass('advads-placement-sorted');
115 rows.sort(function (a, b) {
116 const orderA = jQuery(a).data('order');
117 const orderB = jQuery(b).data('order');
118
119 if (orderBy === 'type') {
120 if (
121 orderA['words-between-repeats'] !==
122 orderB['words-between-repeats']
123 ) {
124 return orderA['words-between-repeats'] ? 1 : -1;
125 }
126
127 if (orderA.order === orderB.order) {
128 // Sort by index.
129 if (
130 orderA['post-content-index'] &&
131 orderB['post-content-index'] &&
132 orderA['post-content-index'] !==
133 orderB['post-content-index']
134 ) {
135 return orderA['post-content-index'] <
136 orderB['post-content-index']
137 ? -1
138 : 1;
139 }
140 // Sort by name.
141 return orderA.name.localeCompare(orderB.name, undefined, {
142 numeric: true,
143 });
144 }
145 return orderA.order - orderB.order;
146 }
147
148 return orderA.name.localeCompare(orderB.name, undefined, {
149 numeric: true,
150 });
151 });
152 jQuery.each(rows, function (index, row) {
153 table.append(row);
154 });
155 let url = window.location.pathname + window.location.search;
156
157 if (url.indexOf('orderby=') !== -1) {
158 url = url.replace(
159 /\borderby=[0-9a-zA-Z_@.#+-]{1,50}\b/,
160 'orderby=' + orderBy
161 );
162 } else {
163 url += '&orderby=' + orderBy;
164 }
165 window.history.replaceState({ orderby: orderBy }, document.title, url);
166 e.preventDefault();
167 });
168
169 // show warning if Container ID option contains invalid characters
170 $('#advads-output-wrapper-id').on('keyup', function () {
171 const id_value = $(this).val();
172 if (/^[a-z-0-9]*$/.test(id_value)) {
173 $('.advads-output-wrapper-id-error').addClass('hidden');
174 } else {
175 $('.advads-output-wrapper-id-error').removeClass('hidden');
176 }
177 });
178
179 /**
180 * There are two formats of URL supported:
181 * admin.php?page=advanced-ads-settings#top#tab_id go to the `tab_id`
182 * admin.php?page=advanced-ads-settings#tab_id__anchor go to the `tab_id`, scroll to the `anchor`
183 */
184
185 /**
186 * Extract the active tab and anchor from the URL hash.
187 *
188 * @param hash
189 * @member {string} hash The URL hash.
190 *
191 * @return {{tab: string, anchor: string}}
192 */
193 function advads_extract_tab(hash) {
194 const hash_parts = hash
195 .replace(/^#top(#|%23)/, '')
196 .replace(/(#|%23)/, '')
197 .split('__');
198
199 return {
200 tab: hash_parts[0] || jQuery('.advads-tab').attr('id'),
201 anchor: hash_parts[1],
202 };
203 }
204
205 /**
206 * Set the active tab and optionally scroll to the anchor.
207 * @param tab
208 */
209 function advads_set_tab(tab) {
210 jQuery('#advads-tabs').find('a').removeClass('nav-tab-active');
211 jQuery('.advads-tab').removeClass('active');
212
213 jQuery('#' + tab.tab).addClass('active');
214 jQuery('#' + tab.tab + '-tab').addClass('nav-tab-active');
215
216 if (tab.anchor) {
217 const anchor_offset = document
218 .getElementById(tab.anchor)
219 .getBoundingClientRect().top;
220 const admin_bar = 48;
221 window.scrollTo(0, anchor_offset + window.scrollY - admin_bar);
222 }
223 }
224
225 // While user is already on the Settings page, find links (in admin menu,
226 // in the Checks at the top, in the notices at the top) to particular setting tabs and open them on click.
227 jQuery(document).on(
228 'click',
229 'a[href*="page=advanced-ads-settings"]:not(.nav-tab)',
230 function () {
231 // Already on the Settings page, so set the new tab.
232 // Extract the tab id from the url.
233 const url = jQuery(this)
234 .attr('href')
235 .split('advanced-ads-settings')[1];
236 const tab = advads_extract_tab(url);
237 advads_set_tab(tab);
238 }
239 );
240
241 /**
242 * Handle the hashchange event, this enables back/forward navigation in the settings page.
243 */
244 window.addEventListener('hashchange', (event) => {
245 const hash = advads_extract_tab(new URL(event.newURL).hash);
246 try {
247 document
248 .getElementById(hash.tab + '-tab')
249 .dispatchEvent(new Event('click'));
250 } catch (e) {
251 // fail silently if element does not exist.
252 }
253 });
254
255 // activate specific or first tab
256
257 const active_tab = advads_extract_tab(window.location.hash);
258 advads_set_tab(active_tab);
259
260 // set all tab urls
261 advads_set_tab_hashes();
262
263 // dynamically generate the sub-menu
264 jQuery('.advads-tab-sub-menu').each(function (key, e) {
265 // abort if scrollIntoView is not supported; we can’t use anchors because they are used for tabs already
266 if (typeof e.scrollIntoView !== 'function') {
267 return;
268 }
269 // get all h2 headlines
270 advads_settings_parent_tab = jQuery(e).parent('.advads-tab');
271 const headlines = advads_settings_parent_tab.find('h2');
272 // create list
273 if (headlines.length > 1) {
274 advads_submenu_list = jQuery('<ul>');
275 headlines.each(function (key, h) {
276 // create anchor for this headline
277 const headline_id =
278 'advads-tab-headline-' +
279 advads_settings_parent_tab.attr('id') +
280 key;
281 jQuery(h).attr('id', headline_id);
282 // place the link in the top menu
283 var text = (text = h.textContent || h.innerText);
284 jQuery(
285 '<li><a onclick="document.getElementById(\'' +
286 headline_id +
287 '\').scrollIntoView()">' +
288 text +
289 '</a></li>'
290 ).appendTo(advads_submenu_list);
291 });
292 // place the menu
293 advads_submenu_list.appendTo(e);
294 }
295 });
296
297 // AD OVERVIEW LIST
298
299 // show the bulk actions sticky, when some lines are selected
300 $('.post-type-advanced_ads .check-column input[type="checkbox"]').on(
301 'change',
302 function () {
303 $(
304 '.post-type-advanced_ads .tablenav.bottom .bulkactions'
305 ).toggleClass(
306 'fixed',
307 0 <
308 $(
309 '.post-type-advanced_ads .check-column input[type="checkbox"]:checked'
310 ).length
311 );
312 }
313 );
314
315 /**
316 * PLACEMENTS
317 */
318 const set_touched_placement = function () {
319 const tr = $(this).closest('tr.advanced-ads-placement-row');
320 if (tr) {
321 tr.data('touched', true);
322 }
323 };
324
325 // keep track of placements that were changed
326 $(
327 'form#advanced-ads-placements-form input, #advanced-ads-placements-form select'
328 ).on('change', set_touched_placement);
329 $('form#advanced-ads-placements-form button').on(
330 'click',
331 set_touched_placement
332 );
333
334 // some special form elements overwrite the jquery listeners (or render them unusable in some strange way)
335 // to counter that and make it more robust in general, we now listen for mouseover events, that will
336 // only occur, when the settings of a placement are expanded (let's just assume this means editing)
337 $('form#advanced-ads-placements-form .advads-modal').on(
338 'mouseover',
339 set_touched_placement
340 );
341
342 // if the modal is canceled, remove the "touched" data again, since the user discarded any changes.
343 $(document).on('advads-modal-canceled', (event) => {
344 const $placementRow = $('#' + event.detail.modal_id).parents(
345 '.advanced-ads-placement-row'
346 );
347 if (!$placementRow.length) {
348 return;
349 }
350 $placementRow.data('touched', false);
351 });
352
353 // on submit remove placements that were untouched
354 $('form#advanced-ads-placements-form').on('submit', function () {
355 const grouprows = jQuery(
356 'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
357 );
358 jQuery(
359 'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
360 ).each(function (k, v) {
361 v = jQuery(v);
362 if (!v.data('touched')) {
363 v.find('input, select').each(function (k2, v2) {
364 v2 = jQuery(v2);
365 v2.prop('disabled', true);
366 });
367 }
368 });
369 });
370
371 // show input field for custom xpath rule when "custom" option is selected for Content placement
372 // iterate through all tag options of all placements
373 $('.advads-placements-content-tag').each(function () {
374 advads_show_placement_content_xpath_field(this);
375 });
376 // update xpath field when tag option changes
377 $('.advads-placements-content-tag').on('change', function () {
378 advads_show_placement_content_xpath_field(this);
379 });
380 /**
381 * show / hide input field for xpath rule
382 *
383 * @param tag field
384 * @param tag_field
385 */
386 function advads_show_placement_content_xpath_field(tag_field) {
387 // get the value of the content tag option
388 const tag = $(tag_field).find('option:selected').val();
389 // show or hide the next following custom xpath option
390 if ('custom' === tag) {
391 $(tag_field).next('.advads-placements-content-custom-xpath').show();
392 } else {
393 $(tag_field).next('.advads-placements-content-custom-xpath').hide();
394 }
395 }
396
397 // show tooltips for group type or placement type in forms
398 $('.advads-form-type').advads_tooltip({
399 content() {
400 return jQuery(this).find('.advads-form-description').html();
401 },
402 parent: ($target) => {
403 const modal = $target.parents('.advads-modal');
404
405 return modal.length ? '#' + modal[0].id : 'body';
406 },
407 });
408
409 /**
410 * On the placements and ad edit page, check if the form values have changed on beforeunload.
411 * On the settings page, additionally check for a tab change.
412 */
413 const advadsTermination = (() => {
414 let termination,
415 form,
416 submitted = false;
417 if (
418 window.advadstxt.admin_page ===
419 'advanced-ads_page_advanced-ads-placements'
420 ) {
421 form = document.getElementById('advanced-ads-placements-form');
422 if (form !== null) {
423 termination = new Advads_Termination(form);
424 }
425 }
426
427 if (window.advadstxt.admin_page === 'advanced_ads') {
428 // prevent errors on back/forward navigation
429 form = document.getElementById('post');
430 if (form !== null) {
431 termination = new Advads_Termination(form);
432 }
433 }
434
435 if (
436 window.advadstxt.admin_page ===
437 'advanced-ads_page_advanced-ads-settings'
438 ) {
439 form = document.querySelector('.advads-tab.active > form');
440 if (form !== null) {
441 termination = new Advads_Termination(form);
442 }
443 [...document.getElementsByClassName('nav-tab')].forEach((tab) => {
444 tab.addEventListener('click', (event) => {
445 if (!termination.terminationNotice()) {
446 event.preventDefault();
447 return termination;
448 }
449
450 advads_set_tab(
451 advads_extract_tab(new URL(event.target.href).hash)
452 );
453
454 form = document.querySelector('.advads-tab.active > form');
455 if (form !== null) {
456 termination = new Advads_Termination(form);
457 termination.collectValues();
458 // if the form is submitted, don't fire the beforeunload handler.
459 form.addEventListener('submit', () => {
460 submitted = true;
461 });
462 }
463 });
464 });
465 }
466
467 if (typeof termination !== 'undefined') {
468 termination.collectValues();
469 const beforeUnloadHandler = (event) => {
470 if (!submitted && !termination.terminationNotice()) {
471 event.preventDefault();
472 event.returnValue = 'string';
473 return termination;
474 }
475 };
476
477 window.addEventListener('beforeunload', beforeUnloadHandler);
478
479 // if the form is submitted, don't fire the beforeunload handler.
480 form.addEventListener('submit', () => {
481 submitted = true;
482 });
483 }
484 return termination;
485 })();
486
487 advancedAds.termination = advadsTermination;
488
489 /**
490 * Image ad uploader
491 */
492 $('body').on('click', '.advads_image_upload', function (e) {
493 e.preventDefault();
494
495 const button = $(this);
496
497 // If the media frame already exists, reopen it.
498 if (file_frame) {
499 // file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
500 file_frame.open();
501 return;
502 }
503
504 // Create the media frame.
505 file_frame = wp.media.frames.file_frame = wp.media({
506 id: 'advads_type_image_wp_media',
507 title: button.data('uploaderTitle'),
508 button: {
509 text: button.data('uploaderButtonText'),
510 },
511 library: {
512 type: 'image',
513 },
514 multiple: false, // only allow one file to be selected
515 });
516
517 // When an image is selected, run a callback.
518 file_frame.on('select', function () {
519 const selection = file_frame.state().get('selection');
520 selection.each(function (attachment, index) {
521 attachment = attachment.toJSON();
522 if (0 === index) {
523 // place first attachment in field
524 $('#advads-image-id').val(attachment.id);
525 $(
526 '#advanced-ads-ad-parameters-size input[name="advanced_ad[width]"]'
527 ).val(attachment.width);
528 $(
529 '#advanced-ads-ad-parameters-size input[name="advanced_ad[height]"]'
530 ).val(attachment.height);
531 // update image preview
532 const new_image =
533 '<img width="' +
534 attachment.width +
535 '" height="' +
536 attachment.height +
537 '" title="' +
538 attachment.title +
539 '" alt="' +
540 attachment.alt +
541 '" src="' +
542 attachment.url +
543 '"/>';
544 $('#advads-image-preview').html(new_image);
545 $('#advads-image-edit-link').attr(
546 'href',
547 attachment.editLink
548 );
549 $('#advads-image-edit-link').removeClass('hidden');
550 // process "reserve this space" checkbox
551 $(
552 '#advanced-ads-ad-parameters-size input[type=number]:first'
553 ).trigger('change');
554 }
555 });
556 });
557
558 // Finally, open the modal
559 file_frame.open();
560 });
561
562 // WP 3.5+ uploader
563 let file_frame;
564 window.formfield = '';
565
566 // adblocker related code
567 $('#advanced-ads-use-adblocker').on('change', function () {
568 advads_toggle_box(this, '#advads-adblocker-wrapper');
569 });
570
571 // processing of the rebuild asset form and the FTP/SSH credentials form
572 let $advads_adblocker_wrapper = $('#advads-adblocker-wrapper'),
573 $advads_adblocker_rebuild_button = $('#advads-adblocker-rebuild');
574
575 $advads_adblocker_rebuild_button.prop('disabled', false);
576
577 $(document).on('click', '#advads-adblocker-rebuild', function (event) {
578 event.preventDefault();
579 const $form = $('#advanced-ads-rebuild-assets-form');
580 $form.prev('.error').remove();
581 $advads_adblocker_rebuild_button
582 .prop('disabled', true)
583 .after('<span class="spinner advads-spinner"></span>');
584
585 const args = {
586 data: {
587 action: 'advads-adblock-rebuild-assets',
588 nonce: advadsglobal.ajax_nonce,
589 },
590 done(data) {
591 $advads_adblocker_wrapper.html(data);
592 $advads_adblocker_rebuild_button = $(
593 '#advads-adblocker-rebuild'
594 );
595 },
596 fail(jqXHR, textStatus, errorThrown) {
597 $form.before(
598 '<div class="error"><p>' +
599 textStatus +
600 ': ' +
601 errorThrown +
602 '</p></div>'
603 );
604 $advads_adblocker_rebuild_button
605 .prop('disabled', false)
606 .next('.advads-spinner')
607 .remove();
608 },
609 on_modal_close() {
610 $advads_adblocker_rebuild_button
611 .prop('disabled', false)
612 .next('.advads-spinner')
613 .remove();
614 },
615 };
616
617 if ($('[name="advads_ab_assign_new_folder"]').is(':checked')) {
618 args.data.advads_ab_assign_new_folder = true;
619 }
620
621 advanced_ads_admin.filesystem.ajax(args);
622 });
623
624 // process "reserve this space" checkbox
625 $('#advanced-ads-ad-parameters').on(
626 'change',
627 '#advanced-ads-ad-parameters-size input[type=number]',
628 function () {
629 // Check if width and/or height is set.
630 if (
631 $('#advanced-ads-ad-parameters-size input[type=number]').filter(
632 function () {
633 return parseInt(this.value, 10) > 0;
634 }
635 ).length >= 1
636 ) {
637 $('#advads-wrapper-add-sizes').prop('disabled', false);
638 } else {
639 $('#advads-wrapper-add-sizes')
640 .prop('disabled', true)
641 .prop('checked', false);
642 }
643 }
644 );
645 // process "reserve this space" checkbox - ad type changed
646 $('#advanced-ads-ad-parameters').on('paramloaded', function () {
647 $('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
648 'change'
649 );
650 });
651 // process "reserve this space" checkbox - on load
652 $('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
653 'change'
654 );
655
656 // move meta box markup to hndle headline
657 $('.advads-hndlelinks').each(function () {
658 $(this).appendTo($(this).parents('.postbox').find('h2.hndle'));
659 $(this).removeClass('hidden');
660 });
661 // Open tutorial link when clicked on it in targeting metabox.
662 $('.advads-video-link').on('click', function (event) {
663 event.preventDefault();
664 const parent = $(event.target).closest('.postbox');
665 parent.removeClass('closed');
666 const videoContainer = parent.find('.advads-video-link-container');
667 videoContainer.html(videoContainer.data('videolink'));
668 });
669
670 // Find Adsense Auto Ads inside ad content.
671 const ad_content =
672 jQuery('textarea[name=advanced_ad\\[content\\]]').text() || '';
673 if (
674 ad_content.indexOf('enable_page_level_ads') !== -1 ||
675 /script[^>]+(?:data-ad-client=|adsbygoogle\.js\?client=)/.test(
676 ad_content
677 )
678 ) {
679 advads_show_adsense_auto_ads_warning();
680 }
681
682 advads_ads_txt_find_issues();
683
684 jQuery('.advanced-ads-adsense-dashboard').each(function (key, elm) {
685 if (Advanced_Ads_Adsense_Report_Helper) {
686 Advanced_Ads_Adsense_Report_Helper.init(elm);
687 }
688 });
689 });
690
691 function modal_submit_form(event, ID, modalID, validation = '') {
692 if (validation !== '' && !window[validation](modalID)) {
693 event.preventDefault();
694 return;
695 }
696 document.getElementById(ID).submit();
697 }
698
699 /**
700 * Store the action hash in settings form action
701 * thanks for Yoast SEO for this idea
702 */
703 function advads_set_tab_hashes() {
704 // iterate through forms
705 jQuery('#advads-tabs')
706 .find('a')
707 .each(function () {
708 const id = jQuery(this).attr('id').replace('-tab', '');
709 const optiontab = jQuery('#' + id);
710
711 const form = optiontab.children('.advads-settings-tab-main-form');
712 if (form.length) {
713 const currentUrl = form.attr('action').split('#')[0];
714 form.attr('action', currentUrl + jQuery(this).attr('href'));
715 }
716 });
717 }
718
719 /**
720 * Scroll to position in backend minus admin bar height
721 *
722 * @param selector jQuery selector
723 */
724 function advads_scroll_to_element(selector) {
725 const height_of_admin_bar = jQuery('#wpadminbar').height();
726 jQuery('html, body').animate(
727 {
728 scrollTop: jQuery(selector).offset().top - height_of_admin_bar,
729 },
730 1000
731 );
732 }
733
734 /**
735 * toggle content elements (hide/show)
736 *
737 * @param selector jquery selector
738 */
739 function advads_toggle(selector) {
740 jQuery(selector).slideToggle();
741 }
742
743 /**
744 * toggle content elements with a checkbox (hide/show)
745 *
746 * @param e
747 * @param selector jquery selector
748 */
749 function advads_toggle_box(e, selector) {
750 if (jQuery(e).is(':checked')) {
751 jQuery(selector).slideDown();
752 } else {
753 jQuery(selector).slideUp();
754 }
755 }
756
757 /**
758 * disable content of one box when selecting another
759 * only grey/disable it, don’t hide it
760 *
761 * @param e
762 * @param selector jquery selector
763 */
764 function advads_toggle_box_enable(e, selector) {
765 if (jQuery(e).is(':checked')) {
766 jQuery(selector).find('input').removeAttr('disabled', '');
767 } else {
768 jQuery(selector).find('input').attr('disabled', 'disabled');
769 }
770 }
771
772 /**
773 * Validate the form that creates a new group or placement.
774 * @param modalID
775 */
776 function advads_validate_new_form(modalID) {
777 // Check if type was selected
778 if (!jQuery('.advads-form-type input:checked').length) {
779 jQuery('.advads-form-type-error').show();
780 return false;
781 }
782 jQuery('.advads-form-type-error').hide();
783
784 // Check if name was entered
785 if (jQuery('.advads-form-name').val() == '') {
786 jQuery('.advads-form-name-error').show();
787 return false;
788 }
789 jQuery('.advads-form-name-error').hide();
790
791 return true;
792 }
793
794 /**
795 * Submit only the current group. Submitting the form with all groups could otherwise cause a server timeout or PHP limit error.
796 *
797 * @param {string} modalID
798 * @return {boolean}
799 */
800 function advads_group_edit_submit(modalID) {
801 jQuery('.advads-ad-group-form')
802 .filter((i, element) => !jQuery(element).parents(modalID).length)
803 .remove();
804
805 return true;
806 }
807
808 /**
809 * replace textarea with TinyMCE editor for Rich Content ad type
810 * @param ad_type
811 */
812 function advads_maybe_textarea_to_tinymce(ad_type) {
813 let textarea = jQuery('#advads-ad-content-plain'),
814 textarea_html = textarea.val(),
815 tinymce_id = 'advanced-ads-tinymce',
816 tinymce_id_ws = jQuery('#' + tinymce_id),
817 tinymce_wrapper_div = jQuery('#advanced-ads-tinymce-wrapper');
818
819 if (ad_type !== 'content') {
820 tinymce_id_ws.prop('name', tinymce_id);
821 tinymce_wrapper_div.hide();
822 return false;
823 }
824
825 if (typeof tinyMCE === 'object' && tinyMCE.get(tinymce_id) !== null) {
826 // visual mode
827 if (textarea_html) {
828 // see BeforeSetContent in the wp-includes\js\tinymce\plugins\wordpress\plugin.js
829 const wp = window.wp,
830 hasWpautop =
831 wp &&
832 wp.editor &&
833 wp.editor.autop &&
834 tinyMCE.get(tinymce_id).getParam('wpautop', true);
835 if (hasWpautop) {
836 textarea_html = wp.editor.autop(textarea_html);
837 }
838 tinyMCE.get(tinymce_id).setContent(textarea_html);
839 }
840 textarea.remove();
841 tinymce_id_ws.prop('name', textarea.prop('name'));
842 tinymce_wrapper_div.show();
843 } else if (tinymce_id_ws.length) {
844 // text mode
845 tinymce_id_ws.val(textarea_html);
846 textarea.remove();
847 tinymce_id_ws.prop('name', textarea.prop('name'));
848 tinymce_wrapper_div.show();
849 }
850 }
851
852 /**
853 * Show a message depending on whether Adsense Auto ads are enabled.
854 */
855 function advads_show_adsense_auto_ads_warning() {
856 $msg = jQuery('.advads-auto-ad-in-ad-content').show();
857 $msg.on('click', 'button', function () {
858 $msg.hide();
859 jQuery
860 .ajax({
861 type: 'POST',
862 url: ajaxurl,
863 data: {
864 action: 'advads-adsense-enable-pla',
865 nonce: advadsglobal.ajax_nonce,
866 },
867 })
868 .done(function (data) {
869 $msg.show().html(advadstxt.page_level_ads_enabled);
870 })
871 .fail(function (jqXHR, textStatus) {
872 $msg.show();
873 });
874 });
875 }
876
877 /**
878 * Check if a third-party ads.txt file exists.
879 */
880 function advads_ads_txt_find_issues() {
881 const $wrapper = jQuery('#advads-ads-txt-notice-wrapper');
882 const $refresh = jQuery('#advads-ads-txt-notice-refresh');
883 const $actions = jQuery('.advads-ads-txt-action');
884
885 /**
886 * Toggle the visibility of the spinner.
887 *
888 * @param {Bool} state True to show, False to hide.
889 */
890 function set_loading(state) {
891 $actions.toggle(!state);
892 if (state) {
893 $wrapper.html('<span class="spinner advads-spinner"></span>');
894 }
895 }
896
897 if (!$wrapper.length) {
898 return;
899 }
900
901 if (!$wrapper.find('ul').length) {
902 // There are no notices. Fetch them using ajax.
903 load('get_notices');
904 }
905
906 $refresh.on('click', function () {
907 load('get_notices');
908 });
909
910 function done(response) {
911 $wrapper.html(response.notices);
912 set_loading(false);
913 }
914
915 function fail(jqXHR) {
916 $wrapper.html(
917 '<p class="advads-notice-inline advads-error">' +
918 jQuery('#advads-ads-txt-notice-error')
919 .text()
920 .replace('%s', parseInt(jqXHR.status, 10)),
921 +'</p>'
922 );
923 set_loading(false);
924 }
925
926 function load(type) {
927 set_loading(true);
928
929 jQuery
930 .ajax({
931 type: 'POST',
932 url: ajaxurl,
933 data: {
934 action: 'advads-ads-txt',
935 nonce: advadsglobal.ajax_nonce,
936 type,
937 },
938 })
939 .done(done)
940 .fail(fail);
941 }
942
943 jQuery(document).on(
944 'click',
945 '#advads-ads-txt-remove-real',
946 function (event) {
947 event.preventDefault();
948
949 const args = {
950 data: {
951 action: 'advads-ads-txt',
952 nonce: advadsglobal.ajax_nonce,
953 type: 'remove_real_file',
954 },
955 done(response) {
956 if (response.additional_content) {
957 jQuery('#advads-ads-txt-additional-content').val(
958 response.additional_content
959 );
960 }
961 done(response);
962 },
963 fail,
964 before_send() {
965 set_loading(true);
966 },
967 };
968
969 advanced_ads_admin.filesystem.ajax(args);
970 }
971 );
972
973 jQuery(document).on(
974 'click',
975 '#advads-ads-txt-create-real',
976 function (event) {
977 event.preventDefault();
978
979 const args = {
980 data: {
981 action: 'advads-ads-txt',
982 nonce: advadsglobal.ajax_nonce,
983 type: 'create_real_file',
984 },
985 done,
986 fail,
987 before_send() {
988 set_loading(true);
989 },
990 };
991
992 advanced_ads_admin.filesystem.ajax(args);
993 }
994 );
995
996 document.addEventListener('click', function (event) {
997 if ( ! event.target.matches('#advads-ads-txt-toggle-adsense') ) {
998 return;
999 }
1000 event.preventDefault();
1001 set_loading(true);
1002 fetch(advancedAds.endpoints.ajaxUrl, {
1003 method: 'POST',
1004 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1005 body: new URLSearchParams({
1006 action: 'advads-ads-txt',
1007 nonce: advancedAds.security.ajaxNonce,
1008 type: 'toggle_adsense',
1009 }),
1010 })
1011 .then((r) => r.json())
1012 .then(function (response) {
1013 const btn = document.getElementById('advads-ads-txt-toggle-adsense');
1014 const notice = document.getElementById('advads-ads-txt-adsense-notice');
1015 if (response.adsense_disabled) {
1016 btn.textContent = btn.dataset.enableLabel;
1017 notice.textContent = notice.dataset.disabledText;
1018 } else {
1019 btn.textContent = btn.dataset.disableLabel;
1020 notice.innerHTML = notice.dataset.enabledText + '<br><code>' + response.adsense_line + '</code>';
1021 }
1022 done(response);
1023 })
1024 .catch(fail);
1025 });
1026 }
1027
1028 window.advanced_ads_admin = window.advanced_ads_admin || {};
1029 advanced_ads_admin.filesystem = {
1030 /**
1031 * Holds the current job while the user writes data in the 'Connection Information' modal.
1032 *
1033 * @type {obj}
1034 */
1035 _locked_job: false,
1036
1037 /**
1038 * Toggle the 'Connection Information' modal.
1039 */
1040 _requestForCredentialsModalToggle() {
1041 this.$filesystemModal.toggle();
1042 jQuery('body').toggleClass('modal-open');
1043 },
1044
1045 _init() {
1046 this._init = function () {};
1047 const self = this;
1048
1049 self.$filesystemModal = jQuery('#advanced-ads-rfc-dialog');
1050 /**
1051 * Sends saved job.
1052 */
1053 self.$filesystemModal.on('submit', 'form', function (event) {
1054 event.preventDefault();
1055
1056 self.ajax(self._locked_job, true);
1057 self._requestForCredentialsModalToggle();
1058 });
1059
1060 /**
1061 * Closes the request credentials modal when clicking the 'Cancel' button.
1062 */
1063 self.$filesystemModal.on(
1064 'click',
1065 '[data-js-action="close"]',
1066 function () {
1067 if (
1068 jQuery.isPlainObject(self._locked_job) &&
1069 self._locked_job.on_modal_close
1070 ) {
1071 self._locked_job.on_modal_close();
1072 }
1073
1074 self._locked_job = false;
1075 self._requestForCredentialsModalToggle();
1076 }
1077 );
1078 },
1079
1080 /**
1081 * Sends AJAX request. Shows 'Connection Information' modal if needed.
1082 *
1083 * @param {Object} args
1084 * @param {bool} skip_modal
1085 */
1086 ajax(args, skip_modal) {
1087 this._init();
1088
1089 if (!skip_modal && this.$filesystemModal.length > 0) {
1090 this._requestForCredentialsModalToggle();
1091 this.$filesystemModal.find('input:enabled:first').focus();
1092
1093 // Do not send request.
1094 this._locked_job = args;
1095 return;
1096 }
1097
1098 const options = {
1099 method: 'POST',
1100 url: window.ajaxurl,
1101 data: {
1102 username: jQuery('#username').val(),
1103 password: jQuery('#password').val(),
1104 hostname: jQuery('#hostname').val(),
1105 connection_type: jQuery(
1106 'input[name="connection_type"]:checked'
1107 ).val(),
1108 public_key: jQuery('#public_key').val(),
1109 private_key: jQuery('#private_key').val(),
1110 _fs_nonce: jQuery('#_fs_nonce').val(),
1111 },
1112 };
1113
1114 if (args.before_send) {
1115 args.before_send();
1116 }
1117
1118 options.data = jQuery.extend(options.data, args.data);
1119 const request = jQuery.ajax(options);
1120
1121 if (args.done) {
1122 request.done(args.done);
1123 }
1124
1125 if (args.fail) {
1126 request.fail(args.fail);
1127 }
1128 },
1129 };
1130
1131 window.Advanced_Ads_Admin = window.Advanced_Ads_Admin || {
1132 /**
1133 * Change the user id to the current user and save the post.
1134 *
1135 * @param {int} user_id
1136 */
1137 reassign_ad(user_id) {
1138 let $authorBox = jQuery('#post_author_override');
1139 if (!$authorBox.length) {
1140 $authorBox = jQuery('#post_author');
1141 }
1142
1143 $authorBox.val(user_id).queue(() => {
1144 jQuery('#post').submit();
1145 });
1146 },
1147
1148 /**
1149 * Toggle placement advanced options.
1150 *
1151 * @param elm
1152 * @param state
1153 * @deprecated. Used only by add-ons when the base plugin version < 1.19.
1154 */
1155 toggle_placements_visibility(elm, state) {
1156 const advadsplacementformrow = jQuery(elm).next(
1157 '.advads-placements-advanced-options'
1158 );
1159
1160 const hide =
1161 typeof state !== 'undefined'
1162 ? !state
1163 : advadsplacementformrow.is(':visible');
1164 if (hide) {
1165 advadsplacementformrow.hide();
1166 // clear last edited id
1167 jQuery('#advads-last-edited-placement').val('');
1168 } else {
1169 const placement_id = jQuery(elm)
1170 .parents('.advads-placements-table-options')
1171 .find('.advads-placement-id')
1172 .val();
1173 advadsplacementformrow.show();
1174 jQuery('#advads-last-edited-placement').val(placement_id);
1175 // Some special elements (color picker) may not be detected with jquery.
1176 const tr = jQuery(elm).closest('tr.advanced-ads-placement-row');
1177 if (tr) {
1178 tr.data('touched', true);
1179 }
1180 }
1181 },
1182
1183 /**
1184 * get a cookie value
1185 *
1186 * @param {str} name of the cookie
1187 */
1188 get_cookie(name) {
1189 let i,
1190 x,
1191 y,
1192 ADVcookies = document.cookie.split(';');
1193 for (i = 0; i < ADVcookies.length; i++) {
1194 x = ADVcookies[i].substr(0, ADVcookies[i].indexOf('='));
1195 y = ADVcookies[i].substr(ADVcookies[i].indexOf('=') + 1);
1196 x = x.replace(/^\s+|\s+$/g, '');
1197 if (x === name) {
1198 return unescape(y);
1199 }
1200 }
1201 },
1202
1203 /**
1204 * set a cookie value
1205 *
1206 * @param {str} name of the cookie
1207 * @param {str} value of the cookie
1208 * @param {int} exdays days until cookie expires
1209 * set 0 to expire cookie immidiatelly
1210 * set null to expire cookie in the current session
1211 * @param path
1212 * @param domain
1213 * @param secure
1214 */
1215 set_cookie(name, value, exdays, path, domain, secure) {
1216 // days in seconds
1217 const expiry = exdays == null ? null : exdays * 24 * 60 * 60;
1218 this.set_cookie_sec(name, value, expiry, path, domain, secure);
1219 },
1220 /**
1221 * set a cookie with expiry given in seconds
1222 *
1223 * @param {str} name of the cookie
1224 * @param {str} value of the cookie
1225 * @param {int} expiry seconds until cookie expires
1226 * set 0 to expire cookie immidiatelly
1227 * set null to expire cookie in the current session
1228 * @param path
1229 * @param domain
1230 * @param secure
1231 */
1232 set_cookie_sec(name, value, expiry, path, domain, secure) {
1233 const exdate = new Date();
1234 exdate.setSeconds(exdate.getSeconds() + parseInt(expiry));
1235 document.cookie =
1236 name +
1237 '=' +
1238 escape(value) +
1239 (expiry == null ? '' : '; expires=' + exdate.toUTCString()) +
1240 (path == null ? '; path=/' : '; path=' + path) +
1241 (domain == null ? '' : '; domain=' + domain) +
1242 (secure == null ? '' : '; secure');
1243 },
1244 };
1245
1246 if (!window.AdvancedAdsAdmin) window.AdvancedAdsAdmin = {};
1247 if (!window.AdvancedAdsAdmin.AdImporter)
1248 window.AdvancedAdsAdmin.AdImporter = {
1249 /**
1250 * will highlight the currently selected ads in the list
1251 * @param hideInactive when true will hide inactive ad units
1252 * @return the selector of the selected row or false if no row was selected.
1253 */
1254 highlightSelectedRowInExternalAdsList(hideInactive) {
1255 if (typeof hideInactive === 'undefined')
1256 hideInactive = AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
1257 const tbody = jQuery('#mapi-table-wrap tbody');
1258 const btn = jQuery('#mapi-toggle-idle');
1259
1260 // count the ad units to determine if there's a need for the overflow class (scrolling)
1261 const nbUnits = hideInactive
1262 ? jQuery('#mapi-table-wrap tbody tr[data-active=1]').length
1263 : jQuery('#mapi-table-wrap tbody tr').length;
1264 if (nbUnits > 8) jQuery('#mapi-table-wrap').addClass('overflow');
1265 else jQuery('#mapi-table-wrap').removeClass('overflow');
1266
1267 const selectedRow = AdvancedAdsAdmin.AdImporter.getSelectedRow();
1268 tbody.find('tr').removeClass('selected error');
1269 if (selectedRow) {
1270 //make sure, it is visible before applying the zebra stripes
1271 selectedRow.show();
1272 }
1273
1274 // make the table's rows striped.
1275 const visible = tbody.find('tr:visible');
1276 visible.filter(':odd').css('background-color', '#FFFFFF');
1277 visible.filter(':even').css('background-color', '#F9F9F9');
1278
1279 // highlight the selected row
1280 if (selectedRow) {
1281 // highlight the selected row
1282 selectedRow.css('background-color', '');
1283 selectedRow.addClass('selected');
1284
1285 this.scrollToSelectedRow(selectedRow);
1286 }
1287
1288 return selectedRow || false;
1289 },
1290
1291 scrollToSelectedRow($selectedRow) {
1292 const $wrap = jQuery('#mapi-table-wrap'),
1293 wrapHeight = $wrap.height(),
1294 wrapScrolled = $wrap.scrollTop();
1295
1296 // just in case this does not get passed a selected row, scroll to top of the table
1297 if (!$selectedRow) {
1298 $wrap.animate({ scrollTop: 0 }, 200);
1299 return;
1300 }
1301
1302 // get the position of the selectedRow within the table wrap
1303 let scroll = $selectedRow.position().top,
1304 bottom = +scroll + $selectedRow.height();
1305 // if the (top of the) element is not yet visible scroll to it
1306 if (
1307 scroll < wrapScrolled ||
1308 bottom > wrapScrolled ||
1309 scroll > wrapScrolled + wrapHeight
1310 ) {
1311 // scrolled element is below current scroll position, i.e. we need to scroll past it not to top
1312 if (bottom > $wrap.children('table').height() - wrapHeight) {
1313 scroll = bottom;
1314 }
1315
1316 // if the selected element is on the "first page" let's scroll all the way to the top
1317 if (scroll < wrapHeight) {
1318 scroll = 0;
1319 }
1320
1321 $wrap.animate({ scrollTop: scroll }, 200);
1322 }
1323 },
1324
1325 getSelectedRow() {
1326 const selectedId =
1327 AdvancedAdsAdmin.AdImporter.adNetwork.getSelectedId();
1328 const tbody = jQuery('#mapi-table-wrap tbody');
1329
1330 if (selectedId) {
1331 const selectedRows = tbody.find(
1332 'tr[data-slotid="' + selectedId + '"]'
1333 );
1334 if (selectedRows.length) {
1335 return selectedRows;
1336 }
1337 }
1338 return null;
1339 },
1340 openExternalAdsList() {
1341 const network = AdvancedAdsAdmin.AdImporter.adNetwork;
1342 network.openSelector();
1343
1344 jQuery('.mapi-insert-code').css('display', 'inline');
1345 jQuery('.mapi-open-selector').css('display', 'none');
1346 jQuery('.mapi-close-selector-link').css('display', 'inline');
1347 jQuery('.advads-adsense-code').css('display', 'none');
1348 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1349
1350 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
1351 network.hideIdle
1352 );
1353
1354 const SNT = network.getCustomInputs();
1355 SNT.css('display', 'none');
1356
1357 jQuery('#mapi-wrap').css('display', 'block');
1358
1359 if (!network.fetchedExternalAds) {
1360 network.fetchedExternalAds = true;
1361 const nbUnits = jQuery(
1362 '#mapi-table-wrap tbody tr[data-slotid]'
1363 ).length;
1364 if (nbUnits == 0) {
1365 //usually we start with a preloaded list.
1366 //only reload, when the count is zero (true for new accounts).
1367 AdvancedAdsAdmin.AdImporter.refreshAds();
1368 }
1369 }
1370 jQuery('#wpwrap').trigger('advads-mapi-adlist-opened');
1371 },
1372 /**
1373 * will be called every time the ad type is changed.
1374 * required for onBlur detection
1375 */
1376 onChangedAdType() {
1377 if (AdvancedAdsAdmin.AdImporter.adNetwork) {
1378 AdvancedAdsAdmin.AdImporter.adNetwork.onBlur();
1379 AdvancedAdsAdmin.AdImporter.adNetwork = null;
1380 }
1381 },
1382 setup(adNetwork) {
1383 AdvancedAdsAdmin.AdImporter.adNetwork = adNetwork;
1384 adNetwork.onSelected();
1385 if (AdvancedAdsAdmin.AdImporter.isSetup) {
1386 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList();
1387 return;
1388 }
1389 AdvancedAdsAdmin.AdImporter.isSetup = true;
1390
1391 jQuery(document).on('click', '.prevent-default', function (ev) {
1392 ev.preventDefault();
1393 });
1394
1395 // handle clicks for the "insert new ... code" anchor
1396 jQuery(document).on('click', '.mapi-insert-code', function (e) {
1397 e.preventDefault();
1398 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1399 jQuery('.advads-adsense-code').show();
1400 jQuery('.mapi-open-selector').css('display', 'inline');
1401 jQuery('.mapi-close-selector-link').css('display', 'inline');
1402 jQuery('.mapi-insert-code').css('display', 'none');
1403 jQuery('#mapi-wrap').css('display', 'none');
1404 const SNT =
1405 AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1406 SNT.css('display', 'none');
1407 });
1408
1409 // handle clicks for the "get ad code from your linked account" anchor
1410 jQuery(document).on('click', '.mapi-open-selector a', function () {
1411 AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1412 });
1413
1414 // the close button of the ad unit list
1415 jQuery(document).on(
1416 'click',
1417 '#mapi-close-selector,.mapi-close-selector-link',
1418 function () {
1419 jQuery('#remote-ad-unsupported-ad-type').css(
1420 'display',
1421 'none'
1422 );
1423 AdvancedAdsAdmin.AdImporter.manualSetup();
1424 }
1425 );
1426
1427 //the individual rows of the ad units may contain elements with the mapiaction class
1428 jQuery(document).on('click', '.mapiaction', function (ev) {
1429 const action = jQuery(this).attr('data-mapiaction');
1430 switch (action) {
1431 case 'updateList':
1432 AdvancedAdsAdmin.AdImporter.refreshAds();
1433 break;
1434 case 'getCode':
1435 if (jQuery(this).hasClass('disabled')) {
1436 break;
1437 }
1438 var slotId = jQuery(this).attr('data-slotid');
1439 AdvancedAdsAdmin.AdImporter.adNetwork.selectAdFromList(
1440 slotId
1441 );
1442 break;
1443 case 'updateCode':
1444 var slotId = jQuery(this).attr('data-slotid');
1445 AdvancedAdsAdmin.AdImporter.adNetwork.updateAdFromList(
1446 slotId
1447 );
1448 break;
1449 case 'toggleidle':
1450 if (
1451 'undefined' !==
1452 typeof AdvancedAdsAdmin.AdImporter.adNetwork
1453 .getMapiAction &&
1454 'function' ===
1455 typeof AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
1456 'toggleidle'
1457 )
1458 ) {
1459 AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
1460 'toggleidle'
1461 )(ev, this);
1462 } else {
1463 AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle =
1464 !AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
1465 AdvancedAdsAdmin.AdImporter.toggleIdleAds(
1466 AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle
1467 );
1468 const $inactiveNotice = jQuery(
1469 '#mapi-notice-inactive'
1470 );
1471 if ($inactiveNotice.length) {
1472 $inactiveNotice.toggle(
1473 AdvancedAdsAdmin.AdImporter.adNetwork
1474 .hideIdle
1475 );
1476 }
1477 break;
1478 }
1479 default:
1480 }
1481 });
1482
1483 AdvancedAdsAdmin.AdImporter.adNetwork.onDomReady();
1484 // AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1485 },
1486
1487 /**
1488 * call this method to display the manual setup (if available for the current ad network)
1489 * this method is an equivalent to the close ad list button.
1490 */
1491 manualSetup() {
1492 jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
1493 'display',
1494 'inline'
1495 );
1496 jQuery('.mapi-insert-code').css('display', 'inline');
1497 jQuery('.mapi-close-selector-link').css('display', 'none');
1498 jQuery('#mapi-wrap').css('display', 'none');
1499
1500 const SNT = AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1501 SNT.css('display', 'block');
1502 // hide custom layout key if type is not in-feed
1503 if (jQuery('#unit-type').val() !== 'in-feed') {
1504 jQuery('.advads-adsense-layout-key')
1505 .css('display', 'none')
1506 .next('div')
1507 .css('display', 'none');
1508 }
1509 AdvancedAdsAdmin.AdImporter.adNetwork.onManualSetup();
1510 },
1511
1512 setRemoteErrorMessage(msg) {
1513 if (!msg) jQuery('#remote-ad-code-msg').empty();
1514 else jQuery('#remote-ad-code-msg').html(msg);
1515 },
1516
1517 /**
1518 * legacy method
1519 */
1520 closeAdSelector() {
1521 // close the ad unit selector
1522 setTimeout(function () {
1523 jQuery('#mapi-wrap').animate({ height: 0 }, 360, function () {
1524 jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
1525 'display',
1526 'inline'
1527 );
1528 jQuery('.mapi-close-selector-link').css('display', 'none');
1529 jQuery('#mapi-wrap').css({
1530 display: 'none',
1531 height: 'auto',
1532 });
1533 const SNT =
1534 AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1535 SNT.css('display', 'block');
1536 });
1537 }, 80);
1538 },
1539
1540 /**
1541 * legacy method
1542 * updates the UI, (call if the selected unit is supported)
1543 * @param slotID
1544 */
1545 unitIsNotSupported(slotID) {
1546 jQuery('#remote-ad-unsupported-ad-type').css('display', 'block');
1547 AdsenseMAPI.unsupportedUnits[slotID] = 1;
1548 jQuery('#unit-code').val('');
1549 jQuery('#unit-type').val('normal');
1550 jQuery('#ad-layout-key').val('');
1551 jQuery('tr[data-slotid^="ca-"]').removeClass('selected error');
1552 const $selectedRow = jQuery('tr[data-slotid="' + slotID + '"]');
1553 $selectedRow.addClass('selected error').css('background-color', '');
1554 this.scrollToSelectedRow($selectedRow);
1555 },
1556
1557 /**
1558 * legacy method
1559 * updates the UI, (call if the selected unit is NOT supported)
1560 * @param slotID
1561 */
1562 unitIsSupported(slotID) {
1563 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1564 if ('undefined' !== typeof AdsenseMAPI.unsupportedUnits[slotID]) {
1565 delete AdsenseMAPI.unsupportedUnits[slotID];
1566 }
1567 jQuery(
1568 'i[data-mapiaction="getCode"][data-slotid="' + slotID + '"]'
1569 ).removeClass('disabled');
1570 if (jQuery('tr[data-slotid="' + slotID + '"] .unittype a').length) {
1571 var td = jQuery('tr[data-slotid="' + slotID + '"] .unittype');
1572 var content = jQuery(
1573 'tr[data-slotid="' + slotID + '"] .unittype a'
1574 ).attr('data-type');
1575 td.text(content);
1576 }
1577 if (jQuery('tr[data-slotid="' + slotID + '"] .unitsize a').length) {
1578 var td = jQuery('tr[data-slotid="' + slotID + '"] .unitsize');
1579 var content = jQuery(
1580 'tr[data-slotid="' + slotID + '"] .unitsize a'
1581 ).attr('data-size');
1582 td.text(content);
1583 }
1584 },
1585
1586 /**
1587 * legacy method
1588 * updates the UI, (call if the selected unit is NOT supported)
1589 * @param msg
1590 */
1591 emptyMapiSelector(msg) {
1592 const nag =
1593 '<div class="advads-notice-inline advads-error"><p>' +
1594 msg +
1595 '</p></div>';
1596 jQuery('#mapi-loading-overlay').css('display', 'none');
1597 jQuery('#mapi-wrap').html(jQuery(nag));
1598 },
1599
1600 /**
1601 * legacy method
1602 */
1603 refreshAds() {
1604 const adNetwork = AdvancedAdsAdmin.AdImporter.adNetwork;
1605 jQuery('#mapi-loading-overlay').css('display', 'block');
1606 jQuery.ajax({
1607 type: 'post',
1608 url: ajaxurl,
1609 data: adNetwork.getRefreshAdsParameters(),
1610 success(response, status, XHR) {
1611 if ('undefined' !== typeof response.html) {
1612 jQuery('#mapi-wrap').replaceWith(jQuery(response.html));
1613 AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1614 } else if ('undefined' !== typeof response.msg) {
1615 AdvancedAdsAdmin.AdImporter.emptyMapiSelector(
1616 response.msg
1617 );
1618 }
1619 if ('undefined' !== typeof response.raw) {
1620 console.log(response.raw);
1621 }
1622 jQuery('#mapi-loading-overlay').css('display', 'none');
1623 },
1624 error(request, status, err) {
1625 jQuery('#mapi-loading-overlay').css('display', 'none');
1626 },
1627 });
1628 },
1629
1630 toggleIdleAds(hide) {
1631 if ('undefined' === typeof hide) {
1632 hide = true;
1633 }
1634 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
1635 hide
1636 );
1637 },
1638 };
1639
1640 /**
1641 * The "abstract" base class for handling external ad units
1642 * Every ad unit will provide you with a set of methods to control the GUI and trigger requests to the server
1643 * while editing an ad that is backed by this network. The main logic takes place in admin/assets/admin.js,
1644 * and the methods in this class are the ones that needed abstraction, depending on the ad network. When you
1645 * need new network-dependant features in the frontend, this is the place to add new methods.
1646 *
1647 * An AdvancedAdsAdNetwork uses these fields:
1648 * id string The identifier, that is used for this network. Must match with the one used in the PHP code of Advanced Ads
1649 * units array Holds the ad units of this network.
1650 * vars map These are the variables that were transmitted from the underlying PHP class (method: append_javascript_data)
1651 * hideIdle Remembers, wheter idle ads should be displayed in the list;
1652 * fetchedExternalAds Remembers if the external ads list has already been loaded to prevent unneccesary requests
1653 */
1654 class AdvancedAdsAdNetwork {
1655 /**
1656 * @param id string representing the id of this network. has to match the identifier of the PHP class
1657 */
1658 constructor(id) {
1659 this.id = id;
1660 this.units = [];
1661 this.vars = window[id + 'AdvancedAdsJS'];
1662 this.hideIdle = true;
1663 this.fetchedExternalAds = false;
1664 }
1665
1666 /**
1667 * will be called when an ad network is selected (ad type in edit ad)
1668 */
1669 onSelected() {
1670 console.error('Please override onSelected.');
1671 }
1672
1673 /**
1674 * will be called when an ad network deselected (ad type in edit ad)
1675 */
1676 onBlur() {
1677 console.error('Please override onBlur.');
1678 }
1679
1680 /**
1681 * opens the selector list containing the external ad units
1682 */
1683 openSelector() {
1684 console.error('Please override openSelector.');
1685 }
1686
1687 /**
1688 * returns the network specific id of the currently selected ad unit
1689 */
1690 getSelectedId() {
1691 console.error('Please override getSelectedId.');
1692 }
1693
1694 /**
1695 * will be called when an external ad unit has been selected from the selector list
1696 * @param slotId string the external ad unit id
1697 */
1698 selectAdFromList(slotId) {
1699 console.error('Please override selectAdFromList.');
1700 }
1701
1702 /**
1703 * will be called when an the update button of an external ad unit has been clicked
1704 * TODO: decide wheter to remove this method. not required anymore - the button was removed.
1705 * @param slotId string the external ad unit id
1706 */
1707 updateAdFromList(slotId) {
1708 console.error('Please override updateAdFromList.');
1709 }
1710
1711 /**
1712 * return the POST params that you want to send to the server when requesting a refresh of the external ad units
1713 * (like nonce and action and everything else that is required)
1714 */
1715 getRefreshAdsParameters() {
1716 console.error('Please override getRefreshAdsParameters.');
1717 }
1718
1719 /**
1720 * return the jquery objects for all the custom html elements of this ad type
1721 */
1722 getCustomInputs() {
1723 console.error('Please override getCustomInputs.');
1724 }
1725
1726 /**
1727 * what to do when the DOM is ready
1728 */
1729 onDomReady() {
1730 console.error('Please override onDomReady.');
1731 }
1732
1733 /**
1734 * when you need custom behaviour for ad networks that support manual setup of ad units, override this method
1735 */
1736 onManualSetup() {
1737 //no console logging. this is optional
1738 }
1739 }
1740
1741 class AdvancedAdsExternalAdUnit {}
1742
1743 /**
1744 * todo: this looks like something we could use in general, but where to put it?
1745 */
1746 jQuery(document).ready(function () {
1747 // delete an existing row by removing the parent tr tag
1748 // todo: this could be moved to a general file
1749 jQuery(document).on('click', '.advads-tr-remove', function () {
1750 jQuery(this).closest('tr').remove();
1751 });
1752 });
1753
1754 /**
1755 * If the jQuery function `escapeSelector` does not exist (add in jQuery 3.0) then add it.
1756 */
1757 if (typeof jQuery.escapeSelector === 'undefined') {
1758 jQuery.escapeSelector = function (selector) {
1759 return selector.replace(
1760 // phpcs:ignore WordPress.WhiteSpace.OperatorSpacing.NoSpaceBefore,WordPress.WhiteSpace.OperatorSpacing.NoSpaceAfter,WordPress.WhiteSpace.OperatorSpacing.NoSpaceBeforeAmp,WordPress.WhiteSpace.OperatorSpacing.NoSpaceAfterAmp -- PHPCS incorrectly reports whitespace errors for this regex
1761 /([$%&()*+,./:;<=>?@\[\\\]^{|}~])/g,
1762 '\\$1'
1763 );
1764 };
1765 }
1766