PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.24
Advanced Ads – Ad Manager & AdSense v2.0.24
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 1 week 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
1932 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 * SETTINGS PAGE
181 */
182
183 // automatically copy the first entered license key into all other empty fields
184 $('.advads-settings-tab-main-form .advads-license-key').on(
185 'blur',
186 function () {
187 // get number of license fields
188
189 const license_key = $(this).val();
190
191 if ('' === license_key) {
192 return;
193 }
194
195 const license_fields = $(
196 '.advads-settings-tab-main-form .advads-license-key'
197 );
198 const license_fields_without_value = [];
199
200 // count license fields without value
201 license_fields.each(function (i, el) {
202 if ('' === $(el).val()) {
203 license_fields_without_value.push(el);
204 }
205 });
206
207 // if there is only one field filled then take its content (probably a license key) and add it into the other fields
208 if (
209 license_fields.length ===
210 license_fields_without_value.length + 1
211 ) {
212 $.each(license_fields_without_value, function (i, el) {
213 $(el).val(license_key);
214 });
215 }
216 }
217 );
218
219 // activate licenses
220 $('.advads-license-activate').on('click', function () {
221 const button = $(this);
222
223 if (!this.dataset.addon) {
224 return;
225 }
226
227 advads_disable_license_buttons(true);
228
229 const query = {
230 action: 'advads-activate-license',
231 addon: this.dataset.addon,
232 pluginname: this.dataset.pluginname,
233 optionslug: this.dataset.optionslug,
234 license: $(this).parents('td').find('.advads-license-key').val(),
235 security: $('#advads-licenses-ajax-referrer').val(),
236 };
237
238 // show loader
239 $('<span class="spinner advads-spinner"></span>').insertAfter(button);
240
241 // send and close message
242 $.post(ajaxurl, query, function (r) {
243 // remove spinner
244 $('span.spinner').remove();
245 const parent = button.parents('td');
246
247 if (r === '1') {
248 const key = 'advanced-ads-licenses[' + query.addon + ']';
249 advadsTermination.setInitialValue(
250 key,
251 document.querySelector('[name="' + key + '"]')
252 );
253 parent.find('.advads-license-activate-error').remove();
254 parent.find('.advads-license-deactivate').show();
255 button.fadeOut();
256 parent.find('.advads-license-activate-active').fadeIn();
257 parent.find('input').prop('readonly', 'readonly');
258 advads_disable_license_buttons(false);
259 } else if (r === 'ex') {
260 const input = parent.find('input.advads-license-key');
261 const link = parent.find('a.advads-renewal-link');
262 if (input && link) {
263 const license_key = input.val();
264 const href = link.prop('href');
265 link.prop(
266 'href',
267 href.replace('%LICENSE_KEY%', license_key)
268 );
269 }
270 parent.find('.advads-license-activate-error').remove();
271 parent.find('.advads-license-expired-error').show();
272 advads_disable_license_buttons(false);
273 } else {
274 parent.find('.advads-license-activate-error').show().html(r);
275 advads_disable_license_buttons(false);
276 }
277 });
278 });
279
280 // deactivate licenses
281 $('.advads-license-deactivate').on('click', function () {
282 const button = $(this);
283
284 if (!this.dataset.addon) {
285 return;
286 }
287
288 advads_disable_license_buttons(true);
289
290 const query = {
291 action: 'advads-deactivate-license',
292 addon: this.dataset.addon,
293 pluginname: this.dataset.pluginname,
294 optionslug: this.dataset.optionslug,
295 security: $('#advads-licenses-ajax-referrer').val(),
296 };
297
298 // show loader
299 $('<span class="spinner advads-spinner"></span>').insertAfter(button);
300
301 // send and close message
302 $.post(ajaxurl, query, function (r) {
303 // remove spinner
304 $('span.spinner').remove();
305
306 if (r === '1') {
307 button.siblings('.advads-license-activate-error').hide();
308 button.siblings('.advads-license-activate-active').hide();
309 button.siblings('.advads-license-activate').show();
310 button.siblings('input').prop('readonly', false);
311 button.fadeOut();
312 advads_disable_license_buttons(false);
313 } else if (r === 'ex') {
314 button.siblings('.advads-license-activate-error').hide();
315 button.siblings('.advads-license-activate-active').hide();
316 button.siblings('.advads-license-expired-error').show();
317 button.siblings('input').prop('readonly', false);
318 button.fadeOut();
319 advads_disable_license_buttons(false);
320 } else {
321 console.log(r);
322 button
323 .siblings('.advads-license-activate-error')
324 .show()
325 .html(r);
326 button.siblings('.advads-license-activate-active').hide();
327 advads_disable_license_buttons(false);
328 }
329 });
330 });
331
332 // toggle license buttons – disable or not
333 function advads_disable_license_buttons(disable = true) {
334 const buttons = $(
335 'button.advads-license-activate, button.advads-license-deactivate'
336 ); // all activation buttons
337 // disable all buttons to prevent issues when users try to enable multiple licenses at the same time
338 if (disable) {
339 buttons.attr('disabled', 'disabled');
340 } else {
341 buttons.removeAttr('disabled');
342 }
343 }
344
345 /**
346 * There are two formats of URL supported:
347 * admin.php?page=advanced-ads-settings#top#tab_id go to the `tab_id`
348 * admin.php?page=advanced-ads-settings#tab_id__anchor go to the `tab_id`, scroll to the `anchor`
349 */
350
351 /**
352 * Extract the active tab and anchor from the URL hash.
353 *
354 * @param hash
355 * @member {string} hash The URL hash.
356 *
357 * @return {{tab: string, anchor: string}}
358 */
359 function advads_extract_tab(hash) {
360 const hash_parts = hash
361 .replace(/^#top(#|%23)/, '')
362 .replace(/(#|%23)/, '')
363 .split('__');
364
365 return {
366 tab: hash_parts[0] || jQuery('.advads-tab').attr('id'),
367 anchor: hash_parts[1],
368 };
369 }
370
371 /**
372 * Set the active tab and optionally scroll to the anchor.
373 * @param tab
374 */
375 function advads_set_tab(tab) {
376 jQuery('#advads-tabs').find('a').removeClass('nav-tab-active');
377 jQuery('.advads-tab').removeClass('active');
378
379 jQuery('#' + tab.tab).addClass('active');
380 jQuery('#' + tab.tab + '-tab').addClass('nav-tab-active');
381
382 if (tab.anchor) {
383 const anchor_offset = document
384 .getElementById(tab.anchor)
385 .getBoundingClientRect().top;
386 const admin_bar = 48;
387 window.scrollTo(0, anchor_offset + window.scrollY - admin_bar);
388 }
389 }
390
391 // While user is already on the Settings page, find links (in admin menu,
392 // in the Checks at the top, in the notices at the top) to particular setting tabs and open them on click.
393 jQuery(document).on(
394 'click',
395 'a[href*="page=advanced-ads-settings"]:not(.nav-tab)',
396 function () {
397 // Already on the Settings page, so set the new tab.
398 // Extract the tab id from the url.
399 const url = jQuery(this)
400 .attr('href')
401 .split('advanced-ads-settings')[1];
402 const tab = advads_extract_tab(url);
403 advads_set_tab(tab);
404 }
405 );
406
407 /**
408 * Handle the hashchange event, this enables back/forward navigation in the settings page.
409 */
410 window.addEventListener('hashchange', (event) => {
411 const hash = advads_extract_tab(new URL(event.newURL).hash);
412 try {
413 document
414 .getElementById(hash.tab + '-tab')
415 .dispatchEvent(new Event('click'));
416 } catch (e) {
417 // fail silently if element does not exist.
418 }
419 });
420
421 // activate specific or first tab
422
423 const active_tab = advads_extract_tab(window.location.hash);
424 advads_set_tab(active_tab);
425
426 // set all tab urls
427 advads_set_tab_hashes();
428
429 // dynamically generate the sub-menu
430 jQuery('.advads-tab-sub-menu').each(function (key, e) {
431 // abort if scrollIntoView is not supported; we can’t use anchors because they are used for tabs already
432 if (typeof e.scrollIntoView !== 'function') {
433 return;
434 }
435 // get all h2 headlines
436 advads_settings_parent_tab = jQuery(e).parent('.advads-tab');
437 const headlines = advads_settings_parent_tab.find('h2');
438 // create list
439 if (headlines.length > 1) {
440 advads_submenu_list = jQuery('<ul>');
441 headlines.each(function (key, h) {
442 // create anchor for this headline
443 const headline_id =
444 'advads-tab-headline-' +
445 advads_settings_parent_tab.attr('id') +
446 key;
447 jQuery(h).attr('id', headline_id);
448 // place the link in the top menu
449 var text = (text = h.textContent || h.innerText);
450 jQuery(
451 '<li><a onclick="document.getElementById(\'' +
452 headline_id +
453 '\').scrollIntoView()">' +
454 text +
455 '</a></li>'
456 ).appendTo(advads_submenu_list);
457 });
458 // place the menu
459 advads_submenu_list.appendTo(e);
460 }
461 });
462
463 // AD OVERVIEW LIST
464
465 // show the bulk actions sticky, when some lines are selected
466 $('.post-type-advanced_ads .check-column input[type="checkbox"]').on(
467 'change',
468 function () {
469 $(
470 '.post-type-advanced_ads .tablenav.bottom .bulkactions'
471 ).toggleClass(
472 'fixed',
473 0 <
474 $(
475 '.post-type-advanced_ads .check-column input[type="checkbox"]:checked'
476 ).length
477 );
478 }
479 );
480
481 /**
482 * PLACEMENTS
483 */
484 const set_touched_placement = function () {
485 const tr = $(this).closest('tr.advanced-ads-placement-row');
486 if (tr) {
487 tr.data('touched', true);
488 }
489 };
490
491 // keep track of placements that were changed
492 $(
493 'form#advanced-ads-placements-form input, #advanced-ads-placements-form select'
494 ).on('change', set_touched_placement);
495 $('form#advanced-ads-placements-form button').on(
496 'click',
497 set_touched_placement
498 );
499
500 // some special form elements overwrite the jquery listeners (or render them unusable in some strange way)
501 // to counter that and make it more robust in general, we now listen for mouseover events, that will
502 // only occur, when the settings of a placement are expanded (let's just assume this means editing)
503 $('form#advanced-ads-placements-form .advads-modal').on(
504 'mouseover',
505 set_touched_placement
506 );
507
508 // if the modal is canceled, remove the "touched" data again, since the user discarded any changes.
509 $(document).on('advads-modal-canceled', (event) => {
510 const $placementRow = $('#' + event.detail.modal_id).parents(
511 '.advanced-ads-placement-row'
512 );
513 if (!$placementRow.length) {
514 return;
515 }
516 $placementRow.data('touched', false);
517 });
518
519 // on submit remove placements that were untouched
520 $('form#advanced-ads-placements-form').on('submit', function () {
521 const grouprows = jQuery(
522 'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
523 );
524 jQuery(
525 'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
526 ).each(function (k, v) {
527 v = jQuery(v);
528 if (!v.data('touched')) {
529 v.find('input, select').each(function (k2, v2) {
530 v2 = jQuery(v2);
531 v2.prop('disabled', true);
532 });
533 }
534 });
535 });
536
537 // show input field for custom xpath rule when "custom" option is selected for Content placement
538 // iterate through all tag options of all placements
539 $('.advads-placements-content-tag').each(function () {
540 advads_show_placement_content_xpath_field(this);
541 });
542 // update xpath field when tag option changes
543 $('.advads-placements-content-tag').on('change', function () {
544 advads_show_placement_content_xpath_field(this);
545 });
546 /**
547 * show / hide input field for xpath rule
548 *
549 * @param tag field
550 * @param tag_field
551 */
552 function advads_show_placement_content_xpath_field(tag_field) {
553 // get the value of the content tag option
554 const tag = $(tag_field).find('option:selected').val();
555 // show or hide the next following custom xpath option
556 if ('custom' === tag) {
557 $(tag_field).next('.advads-placements-content-custom-xpath').show();
558 } else {
559 $(tag_field).next('.advads-placements-content-custom-xpath').hide();
560 }
561 }
562
563 // show tooltips for group type or placement type in forms
564 $('.advads-form-type').advads_tooltip({
565 content() {
566 return jQuery(this).find('.advads-form-description').html();
567 },
568 parent: ($target) => {
569 const modal = $target.parents('.advads-modal');
570
571 return modal.length ? '#' + modal[0].id : 'body';
572 },
573 });
574
575 /**
576 * On the placements and ad edit page, check if the form values have changed on beforeunload.
577 * On the settings page, additionally check for a tab change.
578 */
579 const advadsTermination = (() => {
580 let termination,
581 form,
582 submitted = false;
583 if (
584 window.advadstxt.admin_page ===
585 'advanced-ads_page_advanced-ads-placements'
586 ) {
587 form = document.getElementById('advanced-ads-placements-form');
588 if (form !== null) {
589 termination = new Advads_Termination(form);
590 }
591 }
592
593 if (window.advadstxt.admin_page === 'advanced_ads') {
594 // prevent errors on back/forward navigation
595 form = document.getElementById('post');
596 if (form !== null) {
597 termination = new Advads_Termination(form);
598 }
599 }
600
601 if (
602 window.advadstxt.admin_page ===
603 'advanced-ads_page_advanced-ads-settings'
604 ) {
605 form = document.querySelector('.advads-tab.active > form');
606 if (form !== null) {
607 termination = new Advads_Termination(form);
608 }
609 [...document.getElementsByClassName('nav-tab')].forEach((tab) => {
610 tab.addEventListener('click', (event) => {
611 if (!termination.terminationNotice()) {
612 event.preventDefault();
613 return termination;
614 }
615
616 advads_set_tab(
617 advads_extract_tab(new URL(event.target.href).hash)
618 );
619
620 form = document.querySelector('.advads-tab.active > form');
621 if (form !== null) {
622 termination = new Advads_Termination(form);
623 termination.collectValues();
624 // if the form is submitted, don't fire the beforeunload handler.
625 form.addEventListener('submit', () => {
626 submitted = true;
627 });
628 }
629 });
630 });
631 }
632
633 if (typeof termination !== 'undefined') {
634 termination.collectValues();
635 const beforeUnloadHandler = (event) => {
636 if (!submitted && !termination.terminationNotice()) {
637 event.preventDefault();
638 event.returnValue = 'string';
639 return termination;
640 }
641 };
642
643 window.addEventListener('beforeunload', beforeUnloadHandler);
644
645 // if the form is submitted, don't fire the beforeunload handler.
646 form.addEventListener('submit', () => {
647 submitted = true;
648 });
649 }
650 return termination;
651 })();
652
653 advancedAds.termination = advadsTermination;
654
655 /**
656 * Image ad uploader
657 */
658 $('body').on('click', '.advads_image_upload', function (e) {
659 e.preventDefault();
660
661 const button = $(this);
662
663 // If the media frame already exists, reopen it.
664 if (file_frame) {
665 // file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
666 file_frame.open();
667 return;
668 }
669
670 // Create the media frame.
671 file_frame = wp.media.frames.file_frame = wp.media({
672 id: 'advads_type_image_wp_media',
673 title: button.data('uploaderTitle'),
674 button: {
675 text: button.data('uploaderButtonText'),
676 },
677 library: {
678 type: 'image',
679 },
680 multiple: false, // only allow one file to be selected
681 });
682
683 // When an image is selected, run a callback.
684 file_frame.on('select', function () {
685 const selection = file_frame.state().get('selection');
686 selection.each(function (attachment, index) {
687 attachment = attachment.toJSON();
688 if (0 === index) {
689 // place first attachment in field
690 $('#advads-image-id').val(attachment.id);
691 $(
692 '#advanced-ads-ad-parameters-size input[name="advanced_ad[width]"]'
693 ).val(attachment.width);
694 $(
695 '#advanced-ads-ad-parameters-size input[name="advanced_ad[height]"]'
696 ).val(attachment.height);
697 // update image preview
698 const new_image =
699 '<img width="' +
700 attachment.width +
701 '" height="' +
702 attachment.height +
703 '" title="' +
704 attachment.title +
705 '" alt="' +
706 attachment.alt +
707 '" src="' +
708 attachment.url +
709 '"/>';
710 $('#advads-image-preview').html(new_image);
711 $('#advads-image-edit-link').attr(
712 'href',
713 attachment.editLink
714 );
715 $('#advads-image-edit-link').removeClass('hidden');
716 // process "reserve this space" checkbox
717 $(
718 '#advanced-ads-ad-parameters-size input[type=number]:first'
719 ).trigger('change');
720 }
721 });
722 });
723
724 // Finally, open the modal
725 file_frame.open();
726 });
727
728 // WP 3.5+ uploader
729 let file_frame;
730 window.formfield = '';
731
732 // adblocker related code
733 $('#advanced-ads-use-adblocker').on('change', function () {
734 advads_toggle_box(this, '#advads-adblocker-wrapper');
735 });
736
737 // processing of the rebuild asset form and the FTP/SSH credentials form
738 let $advads_adblocker_wrapper = $('#advads-adblocker-wrapper'),
739 $advads_adblocker_rebuild_button = $('#advads-adblocker-rebuild');
740
741 $advads_adblocker_rebuild_button.prop('disabled', false);
742
743 $(document).on('click', '#advads-adblocker-rebuild', function (event) {
744 event.preventDefault();
745 const $form = $('#advanced-ads-rebuild-assets-form');
746 $form.prev('.error').remove();
747 $advads_adblocker_rebuild_button
748 .prop('disabled', true)
749 .after('<span class="spinner advads-spinner"></span>');
750
751 const args = {
752 data: {
753 action: 'advads-adblock-rebuild-assets',
754 nonce: advadsglobal.ajax_nonce,
755 },
756 done(data) {
757 $advads_adblocker_wrapper.html(data);
758 $advads_adblocker_rebuild_button = $(
759 '#advads-adblocker-rebuild'
760 );
761 },
762 fail(jqXHR, textStatus, errorThrown) {
763 $form.before(
764 '<div class="error"><p>' +
765 textStatus +
766 ': ' +
767 errorThrown +
768 '</p></div>'
769 );
770 $advads_adblocker_rebuild_button
771 .prop('disabled', false)
772 .next('.advads-spinner')
773 .remove();
774 },
775 on_modal_close() {
776 $advads_adblocker_rebuild_button
777 .prop('disabled', false)
778 .next('.advads-spinner')
779 .remove();
780 },
781 };
782
783 if ($('[name="advads_ab_assign_new_folder"]').is(':checked')) {
784 args.data.advads_ab_assign_new_folder = true;
785 }
786
787 advanced_ads_admin.filesystem.ajax(args);
788 });
789
790 // process "reserve this space" checkbox
791 $('#advanced-ads-ad-parameters').on(
792 'change',
793 '#advanced-ads-ad-parameters-size input[type=number]',
794 function () {
795 // Check if width and/or height is set.
796 if (
797 $('#advanced-ads-ad-parameters-size input[type=number]').filter(
798 function () {
799 return parseInt(this.value, 10) > 0;
800 }
801 ).length >= 1
802 ) {
803 $('#advads-wrapper-add-sizes').prop('disabled', false);
804 } else {
805 $('#advads-wrapper-add-sizes')
806 .prop('disabled', true)
807 .prop('checked', false);
808 }
809 }
810 );
811 // process "reserve this space" checkbox - ad type changed
812 $('#advanced-ads-ad-parameters').on('paramloaded', function () {
813 $('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
814 'change'
815 );
816 });
817 // process "reserve this space" checkbox - on load
818 $('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
819 'change'
820 );
821
822 // move meta box markup to hndle headline
823 $('.advads-hndlelinks').each(function () {
824 $(this).appendTo($(this).parents('.postbox').find('h2.hndle'));
825 $(this).removeClass('hidden');
826 });
827 // Open tutorial link when clicked on it in targeting metabox.
828 $('.advads-video-link').on('click', function (event) {
829 event.preventDefault();
830 const parent = $(event.target).closest('.postbox');
831 parent.removeClass('closed');
832 const videoContainer = parent.find('.advads-video-link-container');
833 videoContainer.html(videoContainer.data('videolink'));
834 });
835
836 // Find Adsense Auto Ads inside ad content.
837 const ad_content =
838 jQuery('textarea[name=advanced_ad\\[content\\]]').text() || '';
839 if (
840 ad_content.indexOf('enable_page_level_ads') !== -1 ||
841 /script[^>]+(?:data-ad-client=|adsbygoogle\.js\?client=)/.test(
842 ad_content
843 )
844 ) {
845 advads_show_adsense_auto_ads_warning();
846 }
847
848 advads_ads_txt_find_issues();
849
850 jQuery('.advanced-ads-adsense-dashboard').each(function (key, elm) {
851 if (Advanced_Ads_Adsense_Report_Helper) {
852 Advanced_Ads_Adsense_Report_Helper.init(elm);
853 }
854 });
855 });
856
857 function modal_submit_form(event, ID, modalID, validation = '') {
858 if (validation !== '' && !window[validation](modalID)) {
859 event.preventDefault();
860 return;
861 }
862 document.getElementById(ID).submit();
863 }
864
865 /**
866 * Store the action hash in settings form action
867 * thanks for Yoast SEO for this idea
868 */
869 function advads_set_tab_hashes() {
870 // iterate through forms
871 jQuery('#advads-tabs')
872 .find('a')
873 .each(function () {
874 const id = jQuery(this).attr('id').replace('-tab', '');
875 const optiontab = jQuery('#' + id);
876
877 const form = optiontab.children('.advads-settings-tab-main-form');
878 if (form.length) {
879 const currentUrl = form.attr('action').split('#')[0];
880 form.attr('action', currentUrl + jQuery(this).attr('href'));
881 }
882 });
883 }
884
885 /**
886 * Scroll to position in backend minus admin bar height
887 *
888 * @param selector jQuery selector
889 */
890 function advads_scroll_to_element(selector) {
891 const height_of_admin_bar = jQuery('#wpadminbar').height();
892 jQuery('html, body').animate(
893 {
894 scrollTop: jQuery(selector).offset().top - height_of_admin_bar,
895 },
896 1000
897 );
898 }
899
900 /**
901 * toggle content elements (hide/show)
902 *
903 * @param selector jquery selector
904 */
905 function advads_toggle(selector) {
906 jQuery(selector).slideToggle();
907 }
908
909 /**
910 * toggle content elements with a checkbox (hide/show)
911 *
912 * @param e
913 * @param selector jquery selector
914 */
915 function advads_toggle_box(e, selector) {
916 if (jQuery(e).is(':checked')) {
917 jQuery(selector).slideDown();
918 } else {
919 jQuery(selector).slideUp();
920 }
921 }
922
923 /**
924 * disable content of one box when selecting another
925 * only grey/disable it, don’t hide it
926 *
927 * @param e
928 * @param selector jquery selector
929 */
930 function advads_toggle_box_enable(e, selector) {
931 if (jQuery(e).is(':checked')) {
932 jQuery(selector).find('input').removeAttr('disabled', '');
933 } else {
934 jQuery(selector).find('input').attr('disabled', 'disabled');
935 }
936 }
937
938 /**
939 * Validate the form that creates a new group or placement.
940 * @param modalID
941 */
942 function advads_validate_new_form(modalID) {
943 // Check if type was selected
944 if (!jQuery('.advads-form-type input:checked').length) {
945 jQuery('.advads-form-type-error').show();
946 return false;
947 }
948 jQuery('.advads-form-type-error').hide();
949
950 // Check if name was entered
951 if (jQuery('.advads-form-name').val() == '') {
952 jQuery('.advads-form-name-error').show();
953 return false;
954 }
955 jQuery('.advads-form-name-error').hide();
956
957 return true;
958 }
959
960 /**
961 * Submit only the current group. Submitting the form with all groups could otherwise cause a server timeout or PHP limit error.
962 *
963 * @param {string} modalID
964 * @return {boolean}
965 */
966 function advads_group_edit_submit(modalID) {
967 jQuery('.advads-ad-group-form')
968 .filter((i, element) => !jQuery(element).parents(modalID).length)
969 .remove();
970
971 return true;
972 }
973
974 /**
975 * replace textarea with TinyMCE editor for Rich Content ad type
976 * @param ad_type
977 */
978 function advads_maybe_textarea_to_tinymce(ad_type) {
979 let textarea = jQuery('#advads-ad-content-plain'),
980 textarea_html = textarea.val(),
981 tinymce_id = 'advanced-ads-tinymce',
982 tinymce_id_ws = jQuery('#' + tinymce_id),
983 tinymce_wrapper_div = jQuery('#advanced-ads-tinymce-wrapper');
984
985 if (ad_type !== 'content') {
986 tinymce_id_ws.prop('name', tinymce_id);
987 tinymce_wrapper_div.hide();
988 return false;
989 }
990
991 if (typeof tinyMCE === 'object' && tinyMCE.get(tinymce_id) !== null) {
992 // visual mode
993 if (textarea_html) {
994 // see BeforeSetContent in the wp-includes\js\tinymce\plugins\wordpress\plugin.js
995 const wp = window.wp,
996 hasWpautop =
997 wp &&
998 wp.editor &&
999 wp.editor.autop &&
1000 tinyMCE.get(tinymce_id).getParam('wpautop', true);
1001 if (hasWpautop) {
1002 textarea_html = wp.editor.autop(textarea_html);
1003 }
1004 tinyMCE.get(tinymce_id).setContent(textarea_html);
1005 }
1006 textarea.remove();
1007 tinymce_id_ws.prop('name', textarea.prop('name'));
1008 tinymce_wrapper_div.show();
1009 } else if (tinymce_id_ws.length) {
1010 // text mode
1011 tinymce_id_ws.val(textarea_html);
1012 textarea.remove();
1013 tinymce_id_ws.prop('name', textarea.prop('name'));
1014 tinymce_wrapper_div.show();
1015 }
1016 }
1017
1018 /**
1019 * Show a message depending on whether Adsense Auto ads are enabled.
1020 */
1021 function advads_show_adsense_auto_ads_warning() {
1022 $msg = jQuery('.advads-auto-ad-in-ad-content').show();
1023 $msg.on('click', 'button', function () {
1024 $msg.hide();
1025 jQuery
1026 .ajax({
1027 type: 'POST',
1028 url: ajaxurl,
1029 data: {
1030 action: 'advads-adsense-enable-pla',
1031 nonce: advadsglobal.ajax_nonce,
1032 },
1033 })
1034 .done(function (data) {
1035 $msg.show().html(advadstxt.page_level_ads_enabled);
1036 })
1037 .fail(function (jqXHR, textStatus) {
1038 $msg.show();
1039 });
1040 });
1041 }
1042
1043 /**
1044 * Check if a third-party ads.txt file exists.
1045 */
1046 function advads_ads_txt_find_issues() {
1047 const $wrapper = jQuery('#advads-ads-txt-notice-wrapper');
1048 const $refresh = jQuery('#advads-ads-txt-notice-refresh');
1049 const $actions = jQuery('.advads-ads-txt-action');
1050
1051 /**
1052 * Toggle the visibility of the spinner.
1053 *
1054 * @param {Bool} state True to show, False to hide.
1055 */
1056 function set_loading(state) {
1057 $actions.toggle(!state);
1058 if (state) {
1059 $wrapper.html('<span class="spinner advads-spinner"></span>');
1060 }
1061 }
1062
1063 if (!$wrapper.length) {
1064 return;
1065 }
1066
1067 if (!$wrapper.find('ul').length) {
1068 // There are no notices. Fetch them using ajax.
1069 load('get_notices');
1070 }
1071
1072 $refresh.on('click', function () {
1073 load('get_notices');
1074 });
1075
1076 function done(response) {
1077 $wrapper.html(response.notices);
1078 set_loading(false);
1079 }
1080
1081 function fail(jqXHR) {
1082 $wrapper.html(
1083 '<p class="advads-notice-inline advads-error">' +
1084 jQuery('#advads-ads-txt-notice-error')
1085 .text()
1086 .replace('%s', parseInt(jqXHR.status, 10)),
1087 +'</p>'
1088 );
1089 set_loading(false);
1090 }
1091
1092 function load(type) {
1093 set_loading(true);
1094
1095 jQuery
1096 .ajax({
1097 type: 'POST',
1098 url: ajaxurl,
1099 data: {
1100 action: 'advads-ads-txt',
1101 nonce: advadsglobal.ajax_nonce,
1102 type,
1103 },
1104 })
1105 .done(done)
1106 .fail(fail);
1107 }
1108
1109 jQuery(document).on(
1110 'click',
1111 '#advads-ads-txt-remove-real',
1112 function (event) {
1113 event.preventDefault();
1114
1115 const args = {
1116 data: {
1117 action: 'advads-ads-txt',
1118 nonce: advadsglobal.ajax_nonce,
1119 type: 'remove_real_file',
1120 },
1121 done(response) {
1122 if (response.additional_content) {
1123 jQuery('#advads-ads-txt-additional-content').val(
1124 response.additional_content
1125 );
1126 }
1127 done(response);
1128 },
1129 fail,
1130 before_send() {
1131 set_loading(true);
1132 },
1133 };
1134
1135 advanced_ads_admin.filesystem.ajax(args);
1136 }
1137 );
1138
1139 jQuery(document).on(
1140 'click',
1141 '#advads-ads-txt-create-real',
1142 function (event) {
1143 event.preventDefault();
1144
1145 const args = {
1146 data: {
1147 action: 'advads-ads-txt',
1148 nonce: advadsglobal.ajax_nonce,
1149 type: 'create_real_file',
1150 },
1151 done,
1152 fail,
1153 before_send() {
1154 set_loading(true);
1155 },
1156 };
1157
1158 advanced_ads_admin.filesystem.ajax(args);
1159 }
1160 );
1161
1162 document.addEventListener('click', function (event) {
1163 if ( ! event.target.matches('#advads-ads-txt-toggle-adsense') ) {
1164 return;
1165 }
1166 event.preventDefault();
1167 set_loading(true);
1168 fetch(advancedAds.endpoints.ajaxUrl, {
1169 method: 'POST',
1170 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1171 body: new URLSearchParams({
1172 action: 'advads-ads-txt',
1173 nonce: advancedAds.security.ajaxNonce,
1174 type: 'toggle_adsense',
1175 }),
1176 })
1177 .then((r) => r.json())
1178 .then(function (response) {
1179 const btn = document.getElementById('advads-ads-txt-toggle-adsense');
1180 const notice = document.getElementById('advads-ads-txt-adsense-notice');
1181 if (response.adsense_disabled) {
1182 btn.textContent = btn.dataset.enableLabel;
1183 notice.textContent = notice.dataset.disabledText;
1184 } else {
1185 btn.textContent = btn.dataset.disableLabel;
1186 notice.innerHTML = notice.dataset.enabledText + '<br><code>' + response.adsense_line + '</code>';
1187 }
1188 done(response);
1189 })
1190 .catch(fail);
1191 });
1192 }
1193
1194 window.advanced_ads_admin = window.advanced_ads_admin || {};
1195 advanced_ads_admin.filesystem = {
1196 /**
1197 * Holds the current job while the user writes data in the 'Connection Information' modal.
1198 *
1199 * @type {obj}
1200 */
1201 _locked_job: false,
1202
1203 /**
1204 * Toggle the 'Connection Information' modal.
1205 */
1206 _requestForCredentialsModalToggle() {
1207 this.$filesystemModal.toggle();
1208 jQuery('body').toggleClass('modal-open');
1209 },
1210
1211 _init() {
1212 this._init = function () {};
1213 const self = this;
1214
1215 self.$filesystemModal = jQuery('#advanced-ads-rfc-dialog');
1216 /**
1217 * Sends saved job.
1218 */
1219 self.$filesystemModal.on('submit', 'form', function (event) {
1220 event.preventDefault();
1221
1222 self.ajax(self._locked_job, true);
1223 self._requestForCredentialsModalToggle();
1224 });
1225
1226 /**
1227 * Closes the request credentials modal when clicking the 'Cancel' button.
1228 */
1229 self.$filesystemModal.on(
1230 'click',
1231 '[data-js-action="close"]',
1232 function () {
1233 if (
1234 jQuery.isPlainObject(self._locked_job) &&
1235 self._locked_job.on_modal_close
1236 ) {
1237 self._locked_job.on_modal_close();
1238 }
1239
1240 self._locked_job = false;
1241 self._requestForCredentialsModalToggle();
1242 }
1243 );
1244 },
1245
1246 /**
1247 * Sends AJAX request. Shows 'Connection Information' modal if needed.
1248 *
1249 * @param {Object} args
1250 * @param {bool} skip_modal
1251 */
1252 ajax(args, skip_modal) {
1253 this._init();
1254
1255 if (!skip_modal && this.$filesystemModal.length > 0) {
1256 this._requestForCredentialsModalToggle();
1257 this.$filesystemModal.find('input:enabled:first').focus();
1258
1259 // Do not send request.
1260 this._locked_job = args;
1261 return;
1262 }
1263
1264 const options = {
1265 method: 'POST',
1266 url: window.ajaxurl,
1267 data: {
1268 username: jQuery('#username').val(),
1269 password: jQuery('#password').val(),
1270 hostname: jQuery('#hostname').val(),
1271 connection_type: jQuery(
1272 'input[name="connection_type"]:checked'
1273 ).val(),
1274 public_key: jQuery('#public_key').val(),
1275 private_key: jQuery('#private_key').val(),
1276 _fs_nonce: jQuery('#_fs_nonce').val(),
1277 },
1278 };
1279
1280 if (args.before_send) {
1281 args.before_send();
1282 }
1283
1284 options.data = jQuery.extend(options.data, args.data);
1285 const request = jQuery.ajax(options);
1286
1287 if (args.done) {
1288 request.done(args.done);
1289 }
1290
1291 if (args.fail) {
1292 request.fail(args.fail);
1293 }
1294 },
1295 };
1296
1297 window.Advanced_Ads_Admin = window.Advanced_Ads_Admin || {
1298 /**
1299 * Change the user id to the current user and save the post.
1300 *
1301 * @param {int} user_id
1302 */
1303 reassign_ad(user_id) {
1304 let $authorBox = jQuery('#post_author_override');
1305 if (!$authorBox.length) {
1306 $authorBox = jQuery('#post_author');
1307 }
1308
1309 $authorBox.val(user_id).queue(() => {
1310 jQuery('#post').submit();
1311 });
1312 },
1313
1314 /**
1315 * Toggle placement advanced options.
1316 *
1317 * @param elm
1318 * @param state
1319 * @deprecated. Used only by add-ons when the base plugin version < 1.19.
1320 */
1321 toggle_placements_visibility(elm, state) {
1322 const advadsplacementformrow = jQuery(elm).next(
1323 '.advads-placements-advanced-options'
1324 );
1325
1326 const hide =
1327 typeof state !== 'undefined'
1328 ? !state
1329 : advadsplacementformrow.is(':visible');
1330 if (hide) {
1331 advadsplacementformrow.hide();
1332 // clear last edited id
1333 jQuery('#advads-last-edited-placement').val('');
1334 } else {
1335 const placement_id = jQuery(elm)
1336 .parents('.advads-placements-table-options')
1337 .find('.advads-placement-id')
1338 .val();
1339 advadsplacementformrow.show();
1340 jQuery('#advads-last-edited-placement').val(placement_id);
1341 // Some special elements (color picker) may not be detected with jquery.
1342 const tr = jQuery(elm).closest('tr.advanced-ads-placement-row');
1343 if (tr) {
1344 tr.data('touched', true);
1345 }
1346 }
1347 },
1348
1349 /**
1350 * get a cookie value
1351 *
1352 * @param {str} name of the cookie
1353 */
1354 get_cookie(name) {
1355 let i,
1356 x,
1357 y,
1358 ADVcookies = document.cookie.split(';');
1359 for (i = 0; i < ADVcookies.length; i++) {
1360 x = ADVcookies[i].substr(0, ADVcookies[i].indexOf('='));
1361 y = ADVcookies[i].substr(ADVcookies[i].indexOf('=') + 1);
1362 x = x.replace(/^\s+|\s+$/g, '');
1363 if (x === name) {
1364 return unescape(y);
1365 }
1366 }
1367 },
1368
1369 /**
1370 * set a cookie value
1371 *
1372 * @param {str} name of the cookie
1373 * @param {str} value of the cookie
1374 * @param {int} exdays days until cookie expires
1375 * set 0 to expire cookie immidiatelly
1376 * set null to expire cookie in the current session
1377 * @param path
1378 * @param domain
1379 * @param secure
1380 */
1381 set_cookie(name, value, exdays, path, domain, secure) {
1382 // days in seconds
1383 const expiry = exdays == null ? null : exdays * 24 * 60 * 60;
1384 this.set_cookie_sec(name, value, expiry, path, domain, secure);
1385 },
1386 /**
1387 * set a cookie with expiry given in seconds
1388 *
1389 * @param {str} name of the cookie
1390 * @param {str} value of the cookie
1391 * @param {int} expiry seconds until cookie expires
1392 * set 0 to expire cookie immidiatelly
1393 * set null to expire cookie in the current session
1394 * @param path
1395 * @param domain
1396 * @param secure
1397 */
1398 set_cookie_sec(name, value, expiry, path, domain, secure) {
1399 const exdate = new Date();
1400 exdate.setSeconds(exdate.getSeconds() + parseInt(expiry));
1401 document.cookie =
1402 name +
1403 '=' +
1404 escape(value) +
1405 (expiry == null ? '' : '; expires=' + exdate.toUTCString()) +
1406 (path == null ? '; path=/' : '; path=' + path) +
1407 (domain == null ? '' : '; domain=' + domain) +
1408 (secure == null ? '' : '; secure');
1409 },
1410 };
1411
1412 if (!window.AdvancedAdsAdmin) window.AdvancedAdsAdmin = {};
1413 if (!window.AdvancedAdsAdmin.AdImporter)
1414 window.AdvancedAdsAdmin.AdImporter = {
1415 /**
1416 * will highlight the currently selected ads in the list
1417 * @param hideInactive when true will hide inactive ad units
1418 * @return the selector of the selected row or false if no row was selected.
1419 */
1420 highlightSelectedRowInExternalAdsList(hideInactive) {
1421 if (typeof hideInactive === 'undefined')
1422 hideInactive = AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
1423 const tbody = jQuery('#mapi-table-wrap tbody');
1424 const btn = jQuery('#mapi-toggle-idle');
1425
1426 // count the ad units to determine if there's a need for the overflow class (scrolling)
1427 const nbUnits = hideInactive
1428 ? jQuery('#mapi-table-wrap tbody tr[data-active=1]').length
1429 : jQuery('#mapi-table-wrap tbody tr').length;
1430 if (nbUnits > 8) jQuery('#mapi-table-wrap').addClass('overflow');
1431 else jQuery('#mapi-table-wrap').removeClass('overflow');
1432
1433 const selectedRow = AdvancedAdsAdmin.AdImporter.getSelectedRow();
1434 tbody.find('tr').removeClass('selected error');
1435 if (selectedRow) {
1436 //make sure, it is visible before applying the zebra stripes
1437 selectedRow.show();
1438 }
1439
1440 // make the table's rows striped.
1441 const visible = tbody.find('tr:visible');
1442 visible.filter(':odd').css('background-color', '#FFFFFF');
1443 visible.filter(':even').css('background-color', '#F9F9F9');
1444
1445 // highlight the selected row
1446 if (selectedRow) {
1447 // highlight the selected row
1448 selectedRow.css('background-color', '');
1449 selectedRow.addClass('selected');
1450
1451 this.scrollToSelectedRow(selectedRow);
1452 }
1453
1454 return selectedRow || false;
1455 },
1456
1457 scrollToSelectedRow($selectedRow) {
1458 const $wrap = jQuery('#mapi-table-wrap'),
1459 wrapHeight = $wrap.height(),
1460 wrapScrolled = $wrap.scrollTop();
1461
1462 // just in case this does not get passed a selected row, scroll to top of the table
1463 if (!$selectedRow) {
1464 $wrap.animate({ scrollTop: 0 }, 200);
1465 return;
1466 }
1467
1468 // get the position of the selectedRow within the table wrap
1469 let scroll = $selectedRow.position().top,
1470 bottom = +scroll + $selectedRow.height();
1471 // if the (top of the) element is not yet visible scroll to it
1472 if (
1473 scroll < wrapScrolled ||
1474 bottom > wrapScrolled ||
1475 scroll > wrapScrolled + wrapHeight
1476 ) {
1477 // scrolled element is below current scroll position, i.e. we need to scroll past it not to top
1478 if (bottom > $wrap.children('table').height() - wrapHeight) {
1479 scroll = bottom;
1480 }
1481
1482 // if the selected element is on the "first page" let's scroll all the way to the top
1483 if (scroll < wrapHeight) {
1484 scroll = 0;
1485 }
1486
1487 $wrap.animate({ scrollTop: scroll }, 200);
1488 }
1489 },
1490
1491 getSelectedRow() {
1492 const selectedId =
1493 AdvancedAdsAdmin.AdImporter.adNetwork.getSelectedId();
1494 const tbody = jQuery('#mapi-table-wrap tbody');
1495
1496 if (selectedId) {
1497 const selectedRows = tbody.find(
1498 'tr[data-slotid="' + selectedId + '"]'
1499 );
1500 if (selectedRows.length) {
1501 return selectedRows;
1502 }
1503 }
1504 return null;
1505 },
1506 openExternalAdsList() {
1507 const network = AdvancedAdsAdmin.AdImporter.adNetwork;
1508 network.openSelector();
1509
1510 jQuery('.mapi-insert-code').css('display', 'inline');
1511 jQuery('.mapi-open-selector').css('display', 'none');
1512 jQuery('.mapi-close-selector-link').css('display', 'inline');
1513 jQuery('.advads-adsense-code').css('display', 'none');
1514 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1515
1516 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
1517 network.hideIdle
1518 );
1519
1520 const SNT = network.getCustomInputs();
1521 SNT.css('display', 'none');
1522
1523 jQuery('#mapi-wrap').css('display', 'block');
1524
1525 if (!network.fetchedExternalAds) {
1526 network.fetchedExternalAds = true;
1527 const nbUnits = jQuery(
1528 '#mapi-table-wrap tbody tr[data-slotid]'
1529 ).length;
1530 if (nbUnits == 0) {
1531 //usually we start with a preloaded list.
1532 //only reload, when the count is zero (true for new accounts).
1533 AdvancedAdsAdmin.AdImporter.refreshAds();
1534 }
1535 }
1536 jQuery('#wpwrap').trigger('advads-mapi-adlist-opened');
1537 },
1538 /**
1539 * will be called every time the ad type is changed.
1540 * required for onBlur detection
1541 */
1542 onChangedAdType() {
1543 if (AdvancedAdsAdmin.AdImporter.adNetwork) {
1544 AdvancedAdsAdmin.AdImporter.adNetwork.onBlur();
1545 AdvancedAdsAdmin.AdImporter.adNetwork = null;
1546 }
1547 },
1548 setup(adNetwork) {
1549 AdvancedAdsAdmin.AdImporter.adNetwork = adNetwork;
1550 adNetwork.onSelected();
1551 if (AdvancedAdsAdmin.AdImporter.isSetup) {
1552 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList();
1553 return;
1554 }
1555 AdvancedAdsAdmin.AdImporter.isSetup = true;
1556
1557 jQuery(document).on('click', '.prevent-default', function (ev) {
1558 ev.preventDefault();
1559 });
1560
1561 // handle clicks for the "insert new ... code" anchor
1562 jQuery(document).on('click', '.mapi-insert-code', function (e) {
1563 e.preventDefault();
1564 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1565 jQuery('.advads-adsense-code').show();
1566 jQuery('.mapi-open-selector').css('display', 'inline');
1567 jQuery('.mapi-close-selector-link').css('display', 'inline');
1568 jQuery('.mapi-insert-code').css('display', 'none');
1569 jQuery('#mapi-wrap').css('display', 'none');
1570 const SNT =
1571 AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1572 SNT.css('display', 'none');
1573 });
1574
1575 // handle clicks for the "get ad code from your linked account" anchor
1576 jQuery(document).on('click', '.mapi-open-selector a', function () {
1577 AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1578 });
1579
1580 // the close button of the ad unit list
1581 jQuery(document).on(
1582 'click',
1583 '#mapi-close-selector,.mapi-close-selector-link',
1584 function () {
1585 jQuery('#remote-ad-unsupported-ad-type').css(
1586 'display',
1587 'none'
1588 );
1589 AdvancedAdsAdmin.AdImporter.manualSetup();
1590 }
1591 );
1592
1593 //the individual rows of the ad units may contain elements with the mapiaction class
1594 jQuery(document).on('click', '.mapiaction', function (ev) {
1595 const action = jQuery(this).attr('data-mapiaction');
1596 switch (action) {
1597 case 'updateList':
1598 AdvancedAdsAdmin.AdImporter.refreshAds();
1599 break;
1600 case 'getCode':
1601 if (jQuery(this).hasClass('disabled')) {
1602 break;
1603 }
1604 var slotId = jQuery(this).attr('data-slotid');
1605 AdvancedAdsAdmin.AdImporter.adNetwork.selectAdFromList(
1606 slotId
1607 );
1608 break;
1609 case 'updateCode':
1610 var slotId = jQuery(this).attr('data-slotid');
1611 AdvancedAdsAdmin.AdImporter.adNetwork.updateAdFromList(
1612 slotId
1613 );
1614 break;
1615 case 'toggleidle':
1616 if (
1617 'undefined' !==
1618 typeof AdvancedAdsAdmin.AdImporter.adNetwork
1619 .getMapiAction &&
1620 'function' ===
1621 typeof AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
1622 'toggleidle'
1623 )
1624 ) {
1625 AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
1626 'toggleidle'
1627 )(ev, this);
1628 } else {
1629 AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle =
1630 !AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
1631 AdvancedAdsAdmin.AdImporter.toggleIdleAds(
1632 AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle
1633 );
1634 const $inactiveNotice = jQuery(
1635 '#mapi-notice-inactive'
1636 );
1637 if ($inactiveNotice.length) {
1638 $inactiveNotice.toggle(
1639 AdvancedAdsAdmin.AdImporter.adNetwork
1640 .hideIdle
1641 );
1642 }
1643 break;
1644 }
1645 default:
1646 }
1647 });
1648
1649 AdvancedAdsAdmin.AdImporter.adNetwork.onDomReady();
1650 // AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1651 },
1652
1653 /**
1654 * call this method to display the manual setup (if available for the current ad network)
1655 * this method is an equivalent to the close ad list button.
1656 */
1657 manualSetup() {
1658 jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
1659 'display',
1660 'inline'
1661 );
1662 jQuery('.mapi-insert-code').css('display', 'inline');
1663 jQuery('.mapi-close-selector-link').css('display', 'none');
1664 jQuery('#mapi-wrap').css('display', 'none');
1665
1666 const SNT = AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1667 SNT.css('display', 'block');
1668 // hide custom layout key if type is not in-feed
1669 if (jQuery('#unit-type').val() !== 'in-feed') {
1670 jQuery('.advads-adsense-layout-key')
1671 .css('display', 'none')
1672 .next('div')
1673 .css('display', 'none');
1674 }
1675 AdvancedAdsAdmin.AdImporter.adNetwork.onManualSetup();
1676 },
1677
1678 setRemoteErrorMessage(msg) {
1679 if (!msg) jQuery('#remote-ad-code-msg').empty();
1680 else jQuery('#remote-ad-code-msg').html(msg);
1681 },
1682
1683 /**
1684 * legacy method
1685 */
1686 closeAdSelector() {
1687 // close the ad unit selector
1688 setTimeout(function () {
1689 jQuery('#mapi-wrap').animate({ height: 0 }, 360, function () {
1690 jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
1691 'display',
1692 'inline'
1693 );
1694 jQuery('.mapi-close-selector-link').css('display', 'none');
1695 jQuery('#mapi-wrap').css({
1696 display: 'none',
1697 height: 'auto',
1698 });
1699 const SNT =
1700 AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
1701 SNT.css('display', 'block');
1702 });
1703 }, 80);
1704 },
1705
1706 /**
1707 * legacy method
1708 * updates the UI, (call if the selected unit is supported)
1709 * @param slotID
1710 */
1711 unitIsNotSupported(slotID) {
1712 jQuery('#remote-ad-unsupported-ad-type').css('display', 'block');
1713 AdsenseMAPI.unsupportedUnits[slotID] = 1;
1714 jQuery('#unit-code').val('');
1715 jQuery('#unit-type').val('normal');
1716 jQuery('#ad-layout-key').val('');
1717 jQuery('tr[data-slotid^="ca-"]').removeClass('selected error');
1718 const $selectedRow = jQuery('tr[data-slotid="' + slotID + '"]');
1719 $selectedRow.addClass('selected error').css('background-color', '');
1720 this.scrollToSelectedRow($selectedRow);
1721 },
1722
1723 /**
1724 * legacy method
1725 * updates the UI, (call if the selected unit is NOT supported)
1726 * @param slotID
1727 */
1728 unitIsSupported(slotID) {
1729 jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
1730 if ('undefined' !== typeof AdsenseMAPI.unsupportedUnits[slotID]) {
1731 delete AdsenseMAPI.unsupportedUnits[slotID];
1732 }
1733 jQuery(
1734 'i[data-mapiaction="getCode"][data-slotid="' + slotID + '"]'
1735 ).removeClass('disabled');
1736 if (jQuery('tr[data-slotid="' + slotID + '"] .unittype a').length) {
1737 var td = jQuery('tr[data-slotid="' + slotID + '"] .unittype');
1738 var content = jQuery(
1739 'tr[data-slotid="' + slotID + '"] .unittype a'
1740 ).attr('data-type');
1741 td.text(content);
1742 }
1743 if (jQuery('tr[data-slotid="' + slotID + '"] .unitsize a').length) {
1744 var td = jQuery('tr[data-slotid="' + slotID + '"] .unitsize');
1745 var content = jQuery(
1746 'tr[data-slotid="' + slotID + '"] .unitsize a'
1747 ).attr('data-size');
1748 td.text(content);
1749 }
1750 },
1751
1752 /**
1753 * legacy method
1754 * updates the UI, (call if the selected unit is NOT supported)
1755 * @param msg
1756 */
1757 emptyMapiSelector(msg) {
1758 const nag =
1759 '<div class="advads-notice-inline advads-error"><p>' +
1760 msg +
1761 '</p></div>';
1762 jQuery('#mapi-loading-overlay').css('display', 'none');
1763 jQuery('#mapi-wrap').html(jQuery(nag));
1764 },
1765
1766 /**
1767 * legacy method
1768 */
1769 refreshAds() {
1770 const adNetwork = AdvancedAdsAdmin.AdImporter.adNetwork;
1771 jQuery('#mapi-loading-overlay').css('display', 'block');
1772 jQuery.ajax({
1773 type: 'post',
1774 url: ajaxurl,
1775 data: adNetwork.getRefreshAdsParameters(),
1776 success(response, status, XHR) {
1777 if ('undefined' !== typeof response.html) {
1778 jQuery('#mapi-wrap').replaceWith(jQuery(response.html));
1779 AdvancedAdsAdmin.AdImporter.openExternalAdsList();
1780 } else if ('undefined' !== typeof response.msg) {
1781 AdvancedAdsAdmin.AdImporter.emptyMapiSelector(
1782 response.msg
1783 );
1784 }
1785 if ('undefined' !== typeof response.raw) {
1786 console.log(response.raw);
1787 }
1788 jQuery('#mapi-loading-overlay').css('display', 'none');
1789 },
1790 error(request, status, err) {
1791 jQuery('#mapi-loading-overlay').css('display', 'none');
1792 },
1793 });
1794 },
1795
1796 toggleIdleAds(hide) {
1797 if ('undefined' === typeof hide) {
1798 hide = true;
1799 }
1800 AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
1801 hide
1802 );
1803 },
1804 };
1805
1806 /**
1807 * The "abstract" base class for handling external ad units
1808 * Every ad unit will provide you with a set of methods to control the GUI and trigger requests to the server
1809 * while editing an ad that is backed by this network. The main logic takes place in admin/assets/admin.js,
1810 * and the methods in this class are the ones that needed abstraction, depending on the ad network. When you
1811 * need new network-dependant features in the frontend, this is the place to add new methods.
1812 *
1813 * An AdvancedAdsAdNetwork uses these fields:
1814 * id string The identifier, that is used for this network. Must match with the one used in the PHP code of Advanced Ads
1815 * units array Holds the ad units of this network.
1816 * vars map These are the variables that were transmitted from the underlying PHP class (method: append_javascript_data)
1817 * hideIdle Remembers, wheter idle ads should be displayed in the list;
1818 * fetchedExternalAds Remembers if the external ads list has already been loaded to prevent unneccesary requests
1819 */
1820 class AdvancedAdsAdNetwork {
1821 /**
1822 * @param id string representing the id of this network. has to match the identifier of the PHP class
1823 */
1824 constructor(id) {
1825 this.id = id;
1826 this.units = [];
1827 this.vars = window[id + 'AdvancedAdsJS'];
1828 this.hideIdle = true;
1829 this.fetchedExternalAds = false;
1830 }
1831
1832 /**
1833 * will be called when an ad network is selected (ad type in edit ad)
1834 */
1835 onSelected() {
1836 console.error('Please override onSelected.');
1837 }
1838
1839 /**
1840 * will be called when an ad network deselected (ad type in edit ad)
1841 */
1842 onBlur() {
1843 console.error('Please override onBlur.');
1844 }
1845
1846 /**
1847 * opens the selector list containing the external ad units
1848 */
1849 openSelector() {
1850 console.error('Please override openSelector.');
1851 }
1852
1853 /**
1854 * returns the network specific id of the currently selected ad unit
1855 */
1856 getSelectedId() {
1857 console.error('Please override getSelectedId.');
1858 }
1859
1860 /**
1861 * will be called when an external ad unit has been selected from the selector list
1862 * @param slotId string the external ad unit id
1863 */
1864 selectAdFromList(slotId) {
1865 console.error('Please override selectAdFromList.');
1866 }
1867
1868 /**
1869 * will be called when an the update button of an external ad unit has been clicked
1870 * TODO: decide wheter to remove this method. not required anymore - the button was removed.
1871 * @param slotId string the external ad unit id
1872 */
1873 updateAdFromList(slotId) {
1874 console.error('Please override updateAdFromList.');
1875 }
1876
1877 /**
1878 * return the POST params that you want to send to the server when requesting a refresh of the external ad units
1879 * (like nonce and action and everything else that is required)
1880 */
1881 getRefreshAdsParameters() {
1882 console.error('Please override getRefreshAdsParameters.');
1883 }
1884
1885 /**
1886 * return the jquery objects for all the custom html elements of this ad type
1887 */
1888 getCustomInputs() {
1889 console.error('Please override getCustomInputs.');
1890 }
1891
1892 /**
1893 * what to do when the DOM is ready
1894 */
1895 onDomReady() {
1896 console.error('Please override onDomReady.');
1897 }
1898
1899 /**
1900 * when you need custom behaviour for ad networks that support manual setup of ad units, override this method
1901 */
1902 onManualSetup() {
1903 //no console logging. this is optional
1904 }
1905 }
1906
1907 class AdvancedAdsExternalAdUnit {}
1908
1909 /**
1910 * todo: this looks like something we could use in general, but where to put it?
1911 */
1912 jQuery(document).ready(function () {
1913 // delete an existing row by removing the parent tr tag
1914 // todo: this could be moved to a general file
1915 jQuery(document).on('click', '.advads-tr-remove', function () {
1916 jQuery(this).closest('tr').remove();
1917 });
1918 });
1919
1920 /**
1921 * If the jQuery function `escapeSelector` does not exist (add in jQuery 3.0) then add it.
1922 */
1923 if (typeof jQuery.escapeSelector === 'undefined') {
1924 jQuery.escapeSelector = function (selector) {
1925 return selector.replace(
1926 // 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
1927 /([$%&()*+,./:;<=>?@\[\\\]^{|}~])/g,
1928 '\\$1'
1929 );
1930 };
1931 }
1932