/* eslint-disable */
jQuery(document).ready(function ($) {
	$(document).on('click', '#switch-to-adsense-type', function (ev) {
		ev.preventDefault();
		AdvancedAdsAdmin.AdImporter.adsenseCode =
			Advanced_Ads_Admin.get_ad_source_editor_text();
		$('#advanced-ad-type-adsense').trigger('click');
		$(this).closest('li').addClass('hidden');
	});

	// activate general buttons
	$('.advads-buttonset').advads_buttonset();
	// activate accordions
	if ($.fn.accordion) {
		$('.advads-accordion').accordion({
			active: false,
			collapsible: true,
		});
	}

	// AD OVERVIEW PAGE

	$('.advads-ad-list-tooltip').advads_tooltip({
		content() {
			return jQuery(this).find('.advads-ad-list-tooltip-content').html();
		},
	});

	/**
	 * Logic for placement list
	 */
	(() => {
		let selectedValue = '0';
		let searchTerm = '';
		const placementRows = jQuery('.advads-placements-table tbody tr');
		const showHidePlacementRow = (callback) => {
			placementRows.each((index, element) => {
				const $row = jQuery(element);
				const rowData = $row.data('order');

				if (
					typeof rowData === 'undefined' ||
					typeof rowData.type === 'undefined' ||
					typeof rowData.name === 'undefined'
				) {
					$row.show();
					return;
				}

				$row.toggle(
					(selectedValue === '0' || rowData.type === selectedValue) &&
						(searchTerm === '' ||
							rowData.name
								.toLowerCase()
								.indexOf(searchTerm.toLowerCase()) !== -1)
				);
			});
		};
		// filter placement by type
		jQuery('.advads_filter_placement_type').on('change', function () {
			selectedValue = jQuery(this).val();
			showHidePlacementRow();
		});

		// search placement by name
		jQuery('.advads_search_placement_name').on('keyup', function () {
			searchTerm = this.value;
			showHidePlacementRow();
		});
	})();

	/**
	 * Filter ad/ad group selection in new placement form.
	 */
	(() => {
		const placementTypeRadios = document.querySelectorAll(
			'[name="advads[placement][type]"]'
		);

		placementTypeRadios.forEach((radio) => {
			radio.addEventListener('input', (event) => {
				jQuery('[name="advads[placement][item]"]').attr(
					'disabled',
					true
				);

				wp.ajax
					.post(window.advadstxt.placements_allowed_ads.action, {
						_ajax_nonce:
							window.advadstxt.placements_allowed_ads.nonce,
						placement_type: event.target.value,
					})
					.done((response) => {
						jQuery('[name="advads[placement][item]"]').replaceWith(
							wp.template('advads-placement-ad-select')({
								items: Object.values(response.items),
							})
						);
					});
			});
		});
	})();

	// sort placement by type order or name
	jQuery('.advads-sort').on('click', function (e) {
		const sort = jQuery(this);
		const orderBy = sort.data('orderby');
		const table = jQuery('.advads-placements-table');
		const rows = jQuery('> tbody > tr', table);
		const links = jQuery('> thead th > a', table);
		links.each(function () {
			jQuery(this).removeClass('advads-placement-sorted');
		});
		sort.addClass('advads-placement-sorted');
		rows.sort(function (a, b) {
			const orderA = jQuery(a).data('order');
			const orderB = jQuery(b).data('order');

			if (orderBy === 'type') {
				if (
					orderA['words-between-repeats'] !==
					orderB['words-between-repeats']
				) {
					return orderA['words-between-repeats'] ? 1 : -1;
				}

				if (orderA.order === orderB.order) {
					// Sort by index.
					if (
						orderA['post-content-index'] &&
						orderB['post-content-index'] &&
						orderA['post-content-index'] !==
							orderB['post-content-index']
					) {
						return orderA['post-content-index'] <
							orderB['post-content-index']
							? -1
							: 1;
					}
					// Sort by name.
					return orderA.name.localeCompare(orderB.name, undefined, {
						numeric: true,
					});
				}
				return orderA.order - orderB.order;
			}

			return orderA.name.localeCompare(orderB.name, undefined, {
				numeric: true,
			});
		});
		jQuery.each(rows, function (index, row) {
			table.append(row);
		});
		let url = window.location.pathname + window.location.search;

		if (url.indexOf('orderby=') !== -1) {
			url = url.replace(
				/\borderby=[0-9a-zA-Z_@.#+-]{1,50}\b/,
				'orderby=' + orderBy
			);
		} else {
			url += '&orderby=' + orderBy;
		}
		window.history.replaceState({ orderby: orderBy }, document.title, url);
		e.preventDefault();
	});

	// show warning if Container ID option contains invalid characters
	$('#advads-output-wrapper-id').on('keyup', function () {
		const id_value = $(this).val();
		if (/^[a-z-0-9]*$/.test(id_value)) {
			$('.advads-output-wrapper-id-error').addClass('hidden');
		} else {
			$('.advads-output-wrapper-id-error').removeClass('hidden');
		}
	});

	/**
	 * SETTINGS PAGE
	 */

	// automatically copy the first entered license key into all other empty fields
	$('.advads-settings-tab-main-form .advads-license-key').on(
		'blur',
		function () {
			// get number of license fields

			const license_key = $(this).val();

			if ('' === license_key) {
				return;
			}

			const license_fields = $(
				'.advads-settings-tab-main-form .advads-license-key'
			);
			const license_fields_without_value = [];

			// count license fields without value
			license_fields.each(function (i, el) {
				if ('' === $(el).val()) {
					license_fields_without_value.push(el);
				}
			});

			// if there is only one field filled then take its content (probably a license key) and add it into the other fields
			if (
				license_fields.length ===
				license_fields_without_value.length + 1
			) {
				$.each(license_fields_without_value, function (i, el) {
					$(el).val(license_key);
				});
			}
		}
	);

	// activate licenses
	$('.advads-license-activate').on('click', function () {
		const button = $(this);

		if (!this.dataset.addon) {
			return;
		}

		advads_disable_license_buttons(true);

		const query = {
			action: 'advads-activate-license',
			addon: this.dataset.addon,
			pluginname: this.dataset.pluginname,
			optionslug: this.dataset.optionslug,
			license: $(this).parents('td').find('.advads-license-key').val(),
			security: $('#advads-licenses-ajax-referrer').val(),
		};

		// show loader
		$('<span class="spinner advads-spinner"></span>').insertAfter(button);

		// send and close message
		$.post(ajaxurl, query, function (r) {
			// remove spinner
			$('span.spinner').remove();
			const parent = button.parents('td');

			if (r === '1') {
				const key = 'advanced-ads-licenses[' + query.addon + ']';
				advadsTermination.setInitialValue(
					key,
					document.querySelector('[name="' + key + '"]')
				);
				parent.find('.advads-license-activate-error').remove();
				parent.find('.advads-license-deactivate').show();
				button.fadeOut();
				parent.find('.advads-license-activate-active').fadeIn();
				parent.find('input').prop('readonly', 'readonly');
				advads_disable_license_buttons(false);
			} else if (r === 'ex') {
				const input = parent.find('input.advads-license-key');
				const link = parent.find('a.advads-renewal-link');
				if (input && link) {
					const license_key = input.val();
					const href = link.prop('href');
					link.prop(
						'href',
						href.replace('%LICENSE_KEY%', license_key)
					);
				}
				parent.find('.advads-license-activate-error').remove();
				parent.find('.advads-license-expired-error').show();
				advads_disable_license_buttons(false);
			} else {
				parent.find('.advads-license-activate-error').show().html(r);
				advads_disable_license_buttons(false);
			}
		});
	});

	// deactivate licenses
	$('.advads-license-deactivate').on('click', function () {
		const button = $(this);

		if (!this.dataset.addon) {
			return;
		}

		advads_disable_license_buttons(true);

		const query = {
			action: 'advads-deactivate-license',
			addon: this.dataset.addon,
			pluginname: this.dataset.pluginname,
			optionslug: this.dataset.optionslug,
			security: $('#advads-licenses-ajax-referrer').val(),
		};

		// show loader
		$('<span class="spinner advads-spinner"></span>').insertAfter(button);

		// send and close message
		$.post(ajaxurl, query, function (r) {
			// remove spinner
			$('span.spinner').remove();

			if (r === '1') {
				button.siblings('.advads-license-activate-error').hide();
				button.siblings('.advads-license-activate-active').hide();
				button.siblings('.advads-license-activate').show();
				button.siblings('input').prop('readonly', false);
				button.fadeOut();
				advads_disable_license_buttons(false);
			} else if (r === 'ex') {
				button.siblings('.advads-license-activate-error').hide();
				button.siblings('.advads-license-activate-active').hide();
				button.siblings('.advads-license-expired-error').show();
				button.siblings('input').prop('readonly', false);
				button.fadeOut();
				advads_disable_license_buttons(false);
			} else {
				console.log(r);
				button
					.siblings('.advads-license-activate-error')
					.show()
					.html(r);
				button.siblings('.advads-license-activate-active').hide();
				advads_disable_license_buttons(false);
			}
		});
	});

	// toggle license buttons – disable or not
	function advads_disable_license_buttons(disable = true) {
		const buttons = $(
			'button.advads-license-activate, button.advads-license-deactivate'
		); // all activation buttons
		// disable all buttons to prevent issues when users try to enable multiple licenses at the same time
		if (disable) {
			buttons.attr('disabled', 'disabled');
		} else {
			buttons.removeAttr('disabled');
		}
	}

	/**
	 * There are two formats of URL supported:
	 * admin.php?page=advanced-ads-settings#top#tab_id     go to the `tab_id`
	 * admin.php?page=advanced-ads-settings#tab_id__anchor go to the `tab_id`, scroll to the `anchor`
	 */

	/**
	 * Extract the active tab and anchor from the URL hash.
	 *
	 * @param  hash
	 * @member {string} hash The URL hash.
	 *
	 * @return {{tab: string, anchor: string}}
	 */
	function advads_extract_tab(hash) {
		const hash_parts = hash
			.replace(/^#top(#|%23)/, '')
			.replace(/(#|%23)/, '')
			.split('__');

		return {
			tab: hash_parts[0] || jQuery('.advads-tab').attr('id'),
			anchor: hash_parts[1],
		};
	}

	/**
	 * Set the active tab and optionally scroll to the anchor.
	 * @param tab
	 */
	function advads_set_tab(tab) {
		jQuery('#advads-tabs').find('a').removeClass('nav-tab-active');
		jQuery('.advads-tab').removeClass('active');

		jQuery('#' + tab.tab).addClass('active');
		jQuery('#' + tab.tab + '-tab').addClass('nav-tab-active');

		if (tab.anchor) {
			const anchor_offset = document
				.getElementById(tab.anchor)
				.getBoundingClientRect().top;
			const admin_bar = 48;
			window.scrollTo(0, anchor_offset + window.scrollY - admin_bar);
		}
	}

	// While user is already on the Settings page, find links (in admin menu,
	// in the Checks at the top, in the notices at the top) to particular setting tabs and open them on click.
	jQuery(document).on(
		'click',
		'a[href*="page=advanced-ads-settings"]:not(.nav-tab)',
		function () {
			// Already on the Settings page, so set the new tab.
			// Extract the tab id from the url.
			const url = jQuery(this)
				.attr('href')
				.split('advanced-ads-settings')[1];
			const tab = advads_extract_tab(url);
			advads_set_tab(tab);
		}
	);

	/**
	 * Handle the hashchange event, this enables back/forward navigation in the settings page.
	 */
	window.addEventListener('hashchange', (event) => {
		const hash = advads_extract_tab(new URL(event.newURL).hash);
		try {
			document
				.getElementById(hash.tab + '-tab')
				.dispatchEvent(new Event('click'));
		} catch (e) {
			// fail silently if element does not exist.
		}
	});

	// activate specific or first tab

	const active_tab = advads_extract_tab(window.location.hash);
	advads_set_tab(active_tab);

	// set all tab urls
	advads_set_tab_hashes();

	// dynamically generate the sub-menu
	jQuery('.advads-tab-sub-menu').each(function (key, e) {
		// abort if scrollIntoView is not supported; we can’t use anchors because they are used for tabs already
		if (typeof e.scrollIntoView !== 'function') {
			return;
		}
		// get all h2 headlines
		advads_settings_parent_tab = jQuery(e).parent('.advads-tab');
		const headlines = advads_settings_parent_tab.find('h2');
		// create list
		if (headlines.length > 1) {
			advads_submenu_list = jQuery('<ul>');
			headlines.each(function (key, h) {
				// create anchor for this headline
				const headline_id =
					'advads-tab-headline-' +
					advads_settings_parent_tab.attr('id') +
					key;
				jQuery(h).attr('id', headline_id);
				// place the link in the top menu
				var text = (text = h.textContent || h.innerText);
				jQuery(
					'<li><a onclick="document.getElementById(\'' +
						headline_id +
						'\').scrollIntoView()">' +
						text +
						'</a></li>'
				).appendTo(advads_submenu_list);
			});
			// place the menu
			advads_submenu_list.appendTo(e);
		}
	});

	// AD OVERVIEW LIST

	// show the bulk actions sticky, when some lines are selected
	$('.post-type-advanced_ads .check-column input[type="checkbox"]').on(
		'change',
		function () {
			$(
				'.post-type-advanced_ads .tablenav.bottom .bulkactions'
			).toggleClass(
				'fixed',
				0 <
					$(
						'.post-type-advanced_ads .check-column input[type="checkbox"]:checked'
					).length
			);
		}
	);

	/**
	 * PLACEMENTS
	 */
	const set_touched_placement = function () {
		const tr = $(this).closest('tr.advanced-ads-placement-row');
		if (tr) {
			tr.data('touched', true);
		}
	};

	//  keep track of placements that were changed
	$(
		'form#advanced-ads-placements-form input, #advanced-ads-placements-form select'
	).on('change', set_touched_placement);
	$('form#advanced-ads-placements-form button').on(
		'click',
		set_touched_placement
	);

	//  some special form elements overwrite the jquery listeners (or render them unusable in some strange way)
	//  to counter that and make it more robust in general, we now listen for mouseover events, that will
	//  only occur, when the settings of a placement are expanded (let's just assume this means editing)
	$('form#advanced-ads-placements-form .advads-modal').on(
		'mouseover',
		set_touched_placement
	);

	// if the modal is canceled, remove the "touched" data again, since the user discarded any changes.
	$(document).on('advads-modal-canceled', (event) => {
		const $placementRow = $('#' + event.detail.modal_id).parents(
			'.advanced-ads-placement-row'
		);
		if (!$placementRow.length) {
			return;
		}
		$placementRow.data('touched', false);
	});

	//  on submit remove placements that were untouched
	$('form#advanced-ads-placements-form').on('submit', function () {
		const grouprows = jQuery(
			'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
		);
		jQuery(
			'form#advanced-ads-placements-form tr.advanced-ads-placement-row'
		).each(function (k, v) {
			v = jQuery(v);
			if (!v.data('touched')) {
				v.find('input, select').each(function (k2, v2) {
					v2 = jQuery(v2);
					v2.prop('disabled', true);
				});
			}
		});
	});

	// show input field for custom xpath rule when "custom" option is selected for Content placement
	// iterate through all tag options of all placements
	$('.advads-placements-content-tag').each(function () {
		advads_show_placement_content_xpath_field(this);
	});
	// update xpath field when tag option changes
	$('.advads-placements-content-tag').on('change', function () {
		advads_show_placement_content_xpath_field(this);
	});
	/**
	 * show / hide input field for xpath rule
	 *
	 * @param tag       field
	 * @param tag_field
	 */
	function advads_show_placement_content_xpath_field(tag_field) {
		// get the value of the content tag option
		const tag = $(tag_field).find('option:selected').val();
		// show or hide the next following custom xpath option
		if ('custom' === tag) {
			$(tag_field).next('.advads-placements-content-custom-xpath').show();
		} else {
			$(tag_field).next('.advads-placements-content-custom-xpath').hide();
		}
	}

	// show tooltips for group type or placement type in forms
	$('.advads-form-type').advads_tooltip({
		content() {
			return jQuery(this).find('.advads-form-description').html();
		},
		parent: ($target) => {
			const modal = $target.parents('.advads-modal');

			return modal.length ? '#' + modal[0].id : 'body';
		},
	});

	/**
	 * On the placements and ad edit page, check if the form values have changed on beforeunload.
	 * On the settings page, additionally check for a tab change.
	 */
	const advadsTermination = (() => {
		let termination,
			form,
			submitted = false;
		if (
			window.advadstxt.admin_page ===
			'advanced-ads_page_advanced-ads-placements'
		) {
			form = document.getElementById('advanced-ads-placements-form');
			if (form !== null) {
				termination = new Advads_Termination(form);
			}
		}

		if (window.advadstxt.admin_page === 'advanced_ads') {
			// prevent errors on back/forward navigation
			form = document.getElementById('post');
			if (form !== null) {
				termination = new Advads_Termination(form);
			}
		}

		if (
			window.advadstxt.admin_page ===
			'advanced-ads_page_advanced-ads-settings'
		) {
			form = document.querySelector('.advads-tab.active > form');
			if (form !== null) {
				termination = new Advads_Termination(form);
			}
			[...document.getElementsByClassName('nav-tab')].forEach((tab) => {
				tab.addEventListener('click', (event) => {
					if (!termination.terminationNotice()) {
						event.preventDefault();
						return termination;
					}

					advads_set_tab(
						advads_extract_tab(new URL(event.target.href).hash)
					);

					form = document.querySelector('.advads-tab.active > form');
					if (form !== null) {
						termination = new Advads_Termination(form);
						termination.collectValues();
						// if the form is submitted, don't fire the beforeunload handler.
						form.addEventListener('submit', () => {
							submitted = true;
						});
					}
				});
			});
		}

		if (typeof termination !== 'undefined') {
			termination.collectValues();
			const beforeUnloadHandler = (event) => {
				if (!submitted && !termination.terminationNotice()) {
					event.preventDefault();
					event.returnValue = 'string';
					return termination;
				}
			};

			window.addEventListener('beforeunload', beforeUnloadHandler);

			// if the form is submitted, don't fire the beforeunload handler.
			form.addEventListener('submit', () => {
				submitted = true;
			});
		}
		return termination;
	})();

	advancedAds.termination = advadsTermination;

	/**
	 * Image ad uploader
	 */
	$('body').on('click', '.advads_image_upload', function (e) {
		e.preventDefault();

		const button = $(this);

		// If the media frame already exists, reopen it.
		if (file_frame) {
			// file_frame.uploader.uploader.param( 'post_id', set_to_post_id );
			file_frame.open();
			return;
		}

		// Create the media frame.
		file_frame = wp.media.frames.file_frame = wp.media({
			id: 'advads_type_image_wp_media',
			title: button.data('uploaderTitle'),
			button: {
				text: button.data('uploaderButtonText'),
			},
			library: {
				type: 'image',
			},
			multiple: false, // only allow one file to be selected
		});

		// When an image is selected, run a callback.
		file_frame.on('select', function () {
			const selection = file_frame.state().get('selection');
			selection.each(function (attachment, index) {
				attachment = attachment.toJSON();
				if (0 === index) {
					// place first attachment in field
					$('#advads-image-id').val(attachment.id);
					$(
						'#advanced-ads-ad-parameters-size input[name="advanced_ad[width]"]'
					).val(attachment.width);
					$(
						'#advanced-ads-ad-parameters-size input[name="advanced_ad[height]"]'
					).val(attachment.height);
					// update image preview
					const new_image =
						'<img width="' +
						attachment.width +
						'" height="' +
						attachment.height +
						'" title="' +
						attachment.title +
						'" alt="' +
						attachment.alt +
						'" src="' +
						attachment.url +
						'"/>';
					$('#advads-image-preview').html(new_image);
					$('#advads-image-edit-link').attr(
						'href',
						attachment.editLink
					);
					$('#advads-image-edit-link').removeClass('hidden');
					// process "reserve this space" checkbox
					$(
						'#advanced-ads-ad-parameters-size input[type=number]:first'
					).trigger('change');
				}
			});
		});

		// Finally, open the modal
		file_frame.open();
	});

	// WP 3.5+ uploader
	let file_frame;
	window.formfield = '';

	// adblocker related code
	$('#advanced-ads-use-adblocker').on('change', function () {
		advads_toggle_box(this, '#advads-adblocker-wrapper');
	});

	// processing of the rebuild asset form and the FTP/SSH credentials form
	let $advads_adblocker_wrapper = $('#advads-adblocker-wrapper'),
		$advads_adblocker_rebuild_button = $('#advads-adblocker-rebuild');

	$advads_adblocker_rebuild_button.prop('disabled', false);

	$(document).on('click', '#advads-adblocker-rebuild', function (event) {
		event.preventDefault();
		const $form = $('#advanced-ads-rebuild-assets-form');
		$form.prev('.error').remove();
		$advads_adblocker_rebuild_button
			.prop('disabled', true)
			.after('<span class="spinner advads-spinner"></span>');

		const args = {
			data: {
				action: 'advads-adblock-rebuild-assets',
				nonce: advadsglobal.ajax_nonce,
			},
			done(data) {
				$advads_adblocker_wrapper.html(data);
				$advads_adblocker_rebuild_button = $(
					'#advads-adblocker-rebuild'
				);
			},
			fail(jqXHR, textStatus, errorThrown) {
				$form.before(
					'<div class="error"><p>' +
						textStatus +
						': ' +
						errorThrown +
						'</p></div>'
				);
				$advads_adblocker_rebuild_button
					.prop('disabled', false)
					.next('.advads-spinner')
					.remove();
			},
			on_modal_close() {
				$advads_adblocker_rebuild_button
					.prop('disabled', false)
					.next('.advads-spinner')
					.remove();
			},
		};

		if ($('[name="advads_ab_assign_new_folder"]').is(':checked')) {
			args.data.advads_ab_assign_new_folder = true;
		}

		advanced_ads_admin.filesystem.ajax(args);
	});

	// process "reserve this space" checkbox
	$('#advanced-ads-ad-parameters').on(
		'change',
		'#advanced-ads-ad-parameters-size input[type=number]',
		function () {
			// Check if width and/or height is set.
			if (
				$('#advanced-ads-ad-parameters-size input[type=number]').filter(
					function () {
						return parseInt(this.value, 10) > 0;
					}
				).length >= 1
			) {
				$('#advads-wrapper-add-sizes').prop('disabled', false);
			} else {
				$('#advads-wrapper-add-sizes')
					.prop('disabled', true)
					.prop('checked', false);
			}
		}
	);
	// process "reserve this space" checkbox - ad type changed
	$('#advanced-ads-ad-parameters').on('paramloaded', function () {
		$('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
			'change'
		);
	});
	// process "reserve this space" checkbox - on load
	$('#advanced-ads-ad-parameters-size input[type=number]:first').trigger(
		'change'
	);

	// move meta box markup to hndle headline
	$('.advads-hndlelinks').each(function () {
		$(this).appendTo($(this).parents('.postbox').find('h2.hndle'));
		$(this).removeClass('hidden');
	});
	// Open tutorial link when clicked on it in targeting metabox.
	$('.advads-video-link').on('click', function (event) {
		event.preventDefault();
		const parent = $(event.target).closest('.postbox');
		parent.removeClass('closed');
		const videoContainer = parent.find('.advads-video-link-container');
		videoContainer.html(videoContainer.data('videolink'));
	});

	// Find Adsense Auto Ads inside ad content.
	const ad_content =
		jQuery('textarea[name=advanced_ad\\[content\\]]').text() || '';
	if (
		ad_content.indexOf('enable_page_level_ads') !== -1 ||
		/script[^>]+(?:data-ad-client=|adsbygoogle\.js\?client=)/.test(
			ad_content
		)
	) {
		advads_show_adsense_auto_ads_warning();
	}

	advads_ads_txt_find_issues();

	jQuery('.advanced-ads-adsense-dashboard').each(function (key, elm) {
		if (Advanced_Ads_Adsense_Report_Helper) {
			Advanced_Ads_Adsense_Report_Helper.init(elm);
		}
	});
});

function modal_submit_form(event, ID, modalID, validation = '') {
	if (validation !== '' && !window[validation](modalID)) {
		event.preventDefault();
		return;
	}
	document.getElementById(ID).submit();
}

/**
 * Store the action hash in settings form action
 * thanks for Yoast SEO for this idea
 */
function advads_set_tab_hashes() {
	// iterate through forms
	jQuery('#advads-tabs')
		.find('a')
		.each(function () {
			const id = jQuery(this).attr('id').replace('-tab', '');
			const optiontab = jQuery('#' + id);

			const form = optiontab.children('.advads-settings-tab-main-form');
			if (form.length) {
				const currentUrl = form.attr('action').split('#')[0];
				form.attr('action', currentUrl + jQuery(this).attr('href'));
			}
		});
}

/**
 * Scroll to position in backend minus admin bar height
 *
 * @param selector jQuery selector
 */
function advads_scroll_to_element(selector) {
	const height_of_admin_bar = jQuery('#wpadminbar').height();
	jQuery('html, body').animate(
		{
			scrollTop: jQuery(selector).offset().top - height_of_admin_bar,
		},
		1000
	);
}

/**
 * toggle content elements (hide/show)
 *
 * @param selector jquery selector
 */
function advads_toggle(selector) {
	jQuery(selector).slideToggle();
}

/**
 * toggle content elements with a checkbox (hide/show)
 *
 * @param e
 * @param selector jquery selector
 */
function advads_toggle_box(e, selector) {
	if (jQuery(e).is(':checked')) {
		jQuery(selector).slideDown();
	} else {
		jQuery(selector).slideUp();
	}
}

/**
 * disable content of one box when selecting another
 *  only grey/disable it, don’t hide it
 *
 * @param e
 * @param selector jquery selector
 */
function advads_toggle_box_enable(e, selector) {
	if (jQuery(e).is(':checked')) {
		jQuery(selector).find('input').removeAttr('disabled', '');
	} else {
		jQuery(selector).find('input').attr('disabled', 'disabled');
	}
}

/**
 * Validate the form that creates a new group or placement.
 * @param modalID
 */
function advads_validate_new_form(modalID) {
	// Check if type was selected
	if (!jQuery('.advads-form-type input:checked').length) {
		jQuery('.advads-form-type-error').show();
		return false;
	}
	jQuery('.advads-form-type-error').hide();

	// Check if name was entered
	if (jQuery('.advads-form-name').val() == '') {
		jQuery('.advads-form-name-error').show();
		return false;
	}
	jQuery('.advads-form-name-error').hide();

	return true;
}

/**
 * Submit only the current group. Submitting the form with all groups could otherwise cause a server timeout or PHP limit error.
 *
 * @param {string} modalID
 * @return {boolean}
 */
function advads_group_edit_submit(modalID) {
	jQuery('.advads-ad-group-form')
		.filter((i, element) => !jQuery(element).parents(modalID).length)
		.remove();

	return true;
}

/**
 * replace textarea with TinyMCE editor for Rich Content ad type
 * @param ad_type
 */
function advads_maybe_textarea_to_tinymce(ad_type) {
	let textarea = jQuery('#advads-ad-content-plain'),
		textarea_html = textarea.val(),
		tinymce_id = 'advanced-ads-tinymce',
		tinymce_id_ws = jQuery('#' + tinymce_id),
		tinymce_wrapper_div = jQuery('#advanced-ads-tinymce-wrapper');

	if (ad_type !== 'content') {
		tinymce_id_ws.prop('name', tinymce_id);
		tinymce_wrapper_div.hide();
		return false;
	}

	if (typeof tinyMCE === 'object' && tinyMCE.get(tinymce_id) !== null) {
		// visual mode
		if (textarea_html) {
			// see BeforeSetContent in the wp-includes\js\tinymce\plugins\wordpress\plugin.js
			const wp = window.wp,
				hasWpautop =
					wp &&
					wp.editor &&
					wp.editor.autop &&
					tinyMCE.get(tinymce_id).getParam('wpautop', true);
			if (hasWpautop) {
				textarea_html = wp.editor.autop(textarea_html);
			}
			tinyMCE.get(tinymce_id).setContent(textarea_html);
		}
		textarea.remove();
		tinymce_id_ws.prop('name', textarea.prop('name'));
		tinymce_wrapper_div.show();
	} else if (tinymce_id_ws.length) {
		// text mode
		tinymce_id_ws.val(textarea_html);
		textarea.remove();
		tinymce_id_ws.prop('name', textarea.prop('name'));
		tinymce_wrapper_div.show();
	}
}

/**
 * Show a message depending on whether Adsense Auto ads are enabled.
 */
function advads_show_adsense_auto_ads_warning() {
	$msg = jQuery('.advads-auto-ad-in-ad-content').show();
	$msg.on('click', 'button', function () {
		$msg.hide();
		jQuery
			.ajax({
				type: 'POST',
				url: ajaxurl,
				data: {
					action: 'advads-adsense-enable-pla',
					nonce: advadsglobal.ajax_nonce,
				},
			})
			.done(function (data) {
				$msg.show().html(advadstxt.page_level_ads_enabled);
			})
			.fail(function (jqXHR, textStatus) {
				$msg.show();
			});
	});
}

/**
 * Check if a third-party ads.txt file exists.
 */
function advads_ads_txt_find_issues() {
	const $wrapper = jQuery('#advads-ads-txt-notice-wrapper');
	const $refresh = jQuery('#advads-ads-txt-notice-refresh');
	const $actions = jQuery('.advads-ads-txt-action');

	/**
	 * Toggle the visibility of the spinner.
	 *
	 * @param {Bool} state True to show, False to hide.
	 */
	function set_loading(state) {
		$actions.toggle(!state);
		if (state) {
			$wrapper.html('<span class="spinner advads-spinner"></span>');
		}
	}

	if (!$wrapper.length) {
		return;
	}

	if (!$wrapper.find('ul').length) {
		// There are no notices. Fetch them using ajax.
		load('get_notices');
	}

	$refresh.on('click', function () {
		load('get_notices');
	});

	function done(response) {
		$wrapper.html(response.notices);
		set_loading(false);
	}

	function fail(jqXHR) {
		$wrapper.html(
			'<p class="advads-notice-inline advads-error">' +
				jQuery('#advads-ads-txt-notice-error')
					.text()
					.replace('%s', parseInt(jqXHR.status, 10)),
			+'</p>'
		);
		set_loading(false);
	}

	function load(type) {
		set_loading(true);

		jQuery
			.ajax({
				type: 'POST',
				url: ajaxurl,
				data: {
					action: 'advads-ads-txt',
					nonce: advadsglobal.ajax_nonce,
					type,
				},
			})
			.done(done)
			.fail(fail);
	}

	jQuery(document).on(
		'click',
		'#advads-ads-txt-remove-real',
		function (event) {
			event.preventDefault();

			const args = {
				data: {
					action: 'advads-ads-txt',
					nonce: advadsglobal.ajax_nonce,
					type: 'remove_real_file',
				},
				done(response) {
					if (response.additional_content) {
						jQuery('#advads-ads-txt-additional-content').val(
							response.additional_content
						);
					}
					done(response);
				},
				fail,
				before_send() {
					set_loading(true);
				},
			};

			advanced_ads_admin.filesystem.ajax(args);
		}
	);

	jQuery(document).on(
		'click',
		'#advads-ads-txt-create-real',
		function (event) {
			event.preventDefault();

			const args = {
				data: {
					action: 'advads-ads-txt',
					nonce: advadsglobal.ajax_nonce,
					type: 'create_real_file',
				},
				done,
				fail,
				before_send() {
					set_loading(true);
				},
			};

			advanced_ads_admin.filesystem.ajax(args);
		}
	);
}

window.advanced_ads_admin = window.advanced_ads_admin || {};
advanced_ads_admin.filesystem = {
	/**
	 * Holds the current job while the user writes data in the 'Connection Information' modal.
	 *
	 * @type {obj}
	 */
	_locked_job: false,

	/**
	 * Toggle the 'Connection Information' modal.
	 */
	_requestForCredentialsModalToggle() {
		this.$filesystemModal.toggle();
		jQuery('body').toggleClass('modal-open');
	},

	_init() {
		this._init = function () {};
		const self = this;

		self.$filesystemModal = jQuery('#advanced-ads-rfc-dialog');
		/**
		 * Sends saved job.
		 */
		self.$filesystemModal.on('submit', 'form', function (event) {
			event.preventDefault();

			self.ajax(self._locked_job, true);
			self._requestForCredentialsModalToggle();
		});

		/**
		 * Closes the request credentials modal when clicking the 'Cancel' button.
		 */
		self.$filesystemModal.on(
			'click',
			'[data-js-action="close"]',
			function () {
				if (
					jQuery.isPlainObject(self._locked_job) &&
					self._locked_job.on_modal_close
				) {
					self._locked_job.on_modal_close();
				}

				self._locked_job = false;
				self._requestForCredentialsModalToggle();
			}
		);
	},

	/**
	 * Sends AJAX request. Shows 'Connection Information' modal if needed.
	 *
	 * @param {Object} args
	 * @param {bool}   skip_modal
	 */
	ajax(args, skip_modal) {
		this._init();

		if (!skip_modal && this.$filesystemModal.length > 0) {
			this._requestForCredentialsModalToggle();
			this.$filesystemModal.find('input:enabled:first').focus();

			// Do not send request.
			this._locked_job = args;
			return;
		}

		const options = {
			method: 'POST',
			url: window.ajaxurl,
			data: {
				username: jQuery('#username').val(),
				password: jQuery('#password').val(),
				hostname: jQuery('#hostname').val(),
				connection_type: jQuery(
					'input[name="connection_type"]:checked'
				).val(),
				public_key: jQuery('#public_key').val(),
				private_key: jQuery('#private_key').val(),
				_fs_nonce: jQuery('#_fs_nonce').val(),
			},
		};

		if (args.before_send) {
			args.before_send();
		}

		options.data = jQuery.extend(options.data, args.data);
		const request = jQuery.ajax(options);

		if (args.done) {
			request.done(args.done);
		}

		if (args.fail) {
			request.fail(args.fail);
		}
	},
};

window.Advanced_Ads_Admin = window.Advanced_Ads_Admin || {
	/**
	 * Change the user id to the current user and save the post.
	 *
	 * @param {int} user_id
	 */
	reassign_ad(user_id) {
		let $authorBox = jQuery('#post_author_override');
		if (!$authorBox.length) {
			$authorBox = jQuery('#post_author');
		}

		$authorBox.val(user_id).queue(() => {
			jQuery('#post').submit();
		});
	},

	/**
	 * Toggle placement advanced options.
	 *
	 * @param       elm
	 * @param       state
	 * @deprecated. Used only by add-ons when the base plugin version < 1.19.
	 */
	toggle_placements_visibility(elm, state) {
		const advadsplacementformrow = jQuery(elm).next(
			'.advads-placements-advanced-options'
		);

		const hide =
			typeof state !== 'undefined'
				? !state
				: advadsplacementformrow.is(':visible');
		if (hide) {
			advadsplacementformrow.hide();
			// clear last edited id
			jQuery('#advads-last-edited-placement').val('');
		} else {
			const placement_id = jQuery(elm)
				.parents('.advads-placements-table-options')
				.find('.advads-placement-id')
				.val();
			advadsplacementformrow.show();
			jQuery('#advads-last-edited-placement').val(placement_id);
			// Some special elements (color picker) may not be detected with jquery.
			const tr = jQuery(elm).closest('tr.advanced-ads-placement-row');
			if (tr) {
				tr.data('touched', true);
			}
		}
	},

	/**
	 * get a cookie value
	 *
	 * @param {str} name of the cookie
	 */
	get_cookie(name) {
		let i,
			x,
			y,
			ADVcookies = document.cookie.split(';');
		for (i = 0; i < ADVcookies.length; i++) {
			x = ADVcookies[i].substr(0, ADVcookies[i].indexOf('='));
			y = ADVcookies[i].substr(ADVcookies[i].indexOf('=') + 1);
			x = x.replace(/^\s+|\s+$/g, '');
			if (x === name) {
				return unescape(y);
			}
		}
	},

	/**
	 * set a cookie value
	 *
	 * @param {str} name   of the cookie
	 * @param {str} value  of the cookie
	 * @param {int} exdays days until cookie expires
	 *                     set 0 to expire cookie immidiatelly
	 *                     set null to expire cookie in the current session
	 * @param       path
	 * @param       domain
	 * @param       secure
	 */
	set_cookie(name, value, exdays, path, domain, secure) {
		// days in seconds
		const expiry = exdays == null ? null : exdays * 24 * 60 * 60;
		this.set_cookie_sec(name, value, expiry, path, domain, secure);
	},
	/**
	 * set a cookie with expiry given in seconds
	 *
	 * @param {str} name   of the cookie
	 * @param {str} value  of the cookie
	 * @param {int} expiry seconds until cookie expires
	 *                     set 0 to expire cookie immidiatelly
	 *                     set null to expire cookie in the current session
	 * @param       path
	 * @param       domain
	 * @param       secure
	 */
	set_cookie_sec(name, value, expiry, path, domain, secure) {
		const exdate = new Date();
		exdate.setSeconds(exdate.getSeconds() + parseInt(expiry));
		document.cookie =
			name +
			'=' +
			escape(value) +
			(expiry == null ? '' : '; expires=' + exdate.toUTCString()) +
			(path == null ? '; path=/' : '; path=' + path) +
			(domain == null ? '' : '; domain=' + domain) +
			(secure == null ? '' : '; secure');
	},
};

if (!window.AdvancedAdsAdmin) window.AdvancedAdsAdmin = {};
if (!window.AdvancedAdsAdmin.AdImporter)
	window.AdvancedAdsAdmin.AdImporter = {
		/**
		 * will highlight the currently selected ads in the list
		 * @param hideInactive when true will hide inactive ad units
		 * @return the selector of the selected row or false if no row was selected.
		 */
		highlightSelectedRowInExternalAdsList(hideInactive) {
			if (typeof hideInactive === 'undefined')
				hideInactive = AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
			const tbody = jQuery('#mapi-table-wrap tbody');
			const btn = jQuery('#mapi-toggle-idle');

			//  count the ad units to determine if there's a need for the overflow class (scrolling)
			const nbUnits = hideInactive
				? jQuery('#mapi-table-wrap tbody tr[data-active=1]').length
				: jQuery('#mapi-table-wrap tbody tr').length;
			if (nbUnits > 8) jQuery('#mapi-table-wrap').addClass('overflow');
			else jQuery('#mapi-table-wrap').removeClass('overflow');

			const selectedRow = AdvancedAdsAdmin.AdImporter.getSelectedRow();
			tbody.find('tr').removeClass('selected error');
			if (selectedRow) {
				//make sure, it is visible before applying the zebra stripes
				selectedRow.show();
			}

			//  make the table's rows striped.
			const visible = tbody.find('tr:visible');
			visible.filter(':odd').css('background-color', '#FFFFFF');
			visible.filter(':even').css('background-color', '#F9F9F9');

			//  highlight the selected row
			if (selectedRow) {
				//  highlight the selected row
				selectedRow.css('background-color', '');
				selectedRow.addClass('selected');

				this.scrollToSelectedRow(selectedRow);
			}

			return selectedRow || false;
		},

		scrollToSelectedRow($selectedRow) {
			const $wrap = jQuery('#mapi-table-wrap'),
				wrapHeight = $wrap.height(),
				wrapScrolled = $wrap.scrollTop();

			// just in case this does not get passed a selected row, scroll to top of the table
			if (!$selectedRow) {
				$wrap.animate({ scrollTop: 0 }, 200);
				return;
			}

			// get the position of the selectedRow within the table wrap
			let scroll = $selectedRow.position().top,
				bottom = +scroll + $selectedRow.height();
			// if the (top of the) element is not yet visible scroll to it
			if (
				scroll < wrapScrolled ||
				bottom > wrapScrolled ||
				scroll > wrapScrolled + wrapHeight
			) {
				// scrolled element is below current scroll position, i.e. we need to scroll past it not to top
				if (bottom > $wrap.children('table').height() - wrapHeight) {
					scroll = bottom;
				}

				// if the selected element is on the "first page" let's scroll all the way to the top
				if (scroll < wrapHeight) {
					scroll = 0;
				}

				$wrap.animate({ scrollTop: scroll }, 200);
			}
		},

		getSelectedRow() {
			const selectedId =
				AdvancedAdsAdmin.AdImporter.adNetwork.getSelectedId();
			const tbody = jQuery('#mapi-table-wrap tbody');

			if (selectedId) {
				const selectedRows = tbody.find(
					'tr[data-slotid="' + selectedId + '"]'
				);
				if (selectedRows.length) {
					return selectedRows;
				}
			}
			return null;
		},
		openExternalAdsList() {
			const network = AdvancedAdsAdmin.AdImporter.adNetwork;
			network.openSelector();

			jQuery('.mapi-insert-code').css('display', 'inline');
			jQuery('.mapi-open-selector').css('display', 'none');
			jQuery('.mapi-close-selector-link').css('display', 'inline');
			jQuery('.advads-adsense-code').css('display', 'none');
			jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');

			AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
				network.hideIdle
			);

			const SNT = network.getCustomInputs();
			SNT.css('display', 'none');

			jQuery('#mapi-wrap').css('display', 'block');

			if (!network.fetchedExternalAds) {
				network.fetchedExternalAds = true;
				const nbUnits = jQuery(
					'#mapi-table-wrap tbody tr[data-slotid]'
				).length;
				if (nbUnits == 0) {
					//usually we start with a preloaded list.
					//only reload, when the count is zero (true for new accounts).
					AdvancedAdsAdmin.AdImporter.refreshAds();
				}
			}
			jQuery('#wpwrap').trigger('advads-mapi-adlist-opened');
		},
		/**
		 * will be called every time the ad type is changed.
		 * required for onBlur detection
		 */
		onChangedAdType() {
			if (AdvancedAdsAdmin.AdImporter.adNetwork) {
				AdvancedAdsAdmin.AdImporter.adNetwork.onBlur();
				AdvancedAdsAdmin.AdImporter.adNetwork = null;
			}
		},
		setup(adNetwork) {
			AdvancedAdsAdmin.AdImporter.adNetwork = adNetwork;
			adNetwork.onSelected();
			if (AdvancedAdsAdmin.AdImporter.isSetup) {
				AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList();
				return;
			}
			AdvancedAdsAdmin.AdImporter.isSetup = true;

			jQuery(document).on('click', '.prevent-default', function (ev) {
				ev.preventDefault();
			});

			//  handle clicks for the "insert new ... code" anchor
			jQuery(document).on('click', '.mapi-insert-code', function (e) {
				e.preventDefault();
				jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
				jQuery('.advads-adsense-code').show();
				jQuery('.mapi-open-selector').css('display', 'inline');
				jQuery('.mapi-close-selector-link').css('display', 'inline');
				jQuery('.mapi-insert-code').css('display', 'none');
				jQuery('#mapi-wrap').css('display', 'none');
				const SNT =
					AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
				SNT.css('display', 'none');
			});

			//  handle clicks for the "get ad code from your linked account" anchor
			jQuery(document).on('click', '.mapi-open-selector a', function () {
				AdvancedAdsAdmin.AdImporter.openExternalAdsList();
			});

			//  the close button of the ad unit list
			jQuery(document).on(
				'click',
				'#mapi-close-selector,.mapi-close-selector-link',
				function () {
					jQuery('#remote-ad-unsupported-ad-type').css(
						'display',
						'none'
					);
					AdvancedAdsAdmin.AdImporter.manualSetup();
				}
			);

			//the individual rows of the ad units may contain elements with the mapiaction class
			jQuery(document).on('click', '.mapiaction', function (ev) {
				const action = jQuery(this).attr('data-mapiaction');
				switch (action) {
					case 'updateList':
						AdvancedAdsAdmin.AdImporter.refreshAds();
						break;
					case 'getCode':
						if (jQuery(this).hasClass('disabled')) {
							break;
						}
						var slotId = jQuery(this).attr('data-slotid');
						AdvancedAdsAdmin.AdImporter.adNetwork.selectAdFromList(
							slotId
						);
						break;
					case 'updateCode':
						var slotId = jQuery(this).attr('data-slotid');
						AdvancedAdsAdmin.AdImporter.adNetwork.updateAdFromList(
							slotId
						);
						break;
					case 'toggleidle':
						if (
							'undefined' !==
								typeof AdvancedAdsAdmin.AdImporter.adNetwork
									.getMapiAction &&
							'function' ===
								typeof AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
									'toggleidle'
								)
						) {
							AdvancedAdsAdmin.AdImporter.adNetwork.getMapiAction(
								'toggleidle'
							)(ev, this);
						} else {
							AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle =
								!AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle;
							AdvancedAdsAdmin.AdImporter.toggleIdleAds(
								AdvancedAdsAdmin.AdImporter.adNetwork.hideIdle
							);
							const $inactiveNotice = jQuery(
								'#mapi-notice-inactive'
							);
							if ($inactiveNotice.length) {
								$inactiveNotice.toggle(
									AdvancedAdsAdmin.AdImporter.adNetwork
										.hideIdle
								);
							}
							break;
						}
					default:
				}
			});

			AdvancedAdsAdmin.AdImporter.adNetwork.onDomReady();
			// AdvancedAdsAdmin.AdImporter.openExternalAdsList();
		},

		/**
		 * call this method to display the manual setup (if available for the current ad network)
		 * this method is an equivalent to the close ad list button.
		 */
		manualSetup() {
			jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
				'display',
				'inline'
			);
			jQuery('.mapi-insert-code').css('display', 'inline');
			jQuery('.mapi-close-selector-link').css('display', 'none');
			jQuery('#mapi-wrap').css('display', 'none');

			const SNT = AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
			SNT.css('display', 'block');
			// hide custom layout key if type is not in-feed
			if (jQuery('#unit-type').val() !== 'in-feed') {
				jQuery('.advads-adsense-layout-key')
					.css('display', 'none')
					.next('div')
					.css('display', 'none');
			}
			AdvancedAdsAdmin.AdImporter.adNetwork.onManualSetup();
		},

		setRemoteErrorMessage(msg) {
			if (!msg) jQuery('#remote-ad-code-msg').empty();
			else jQuery('#remote-ad-code-msg').html(msg);
		},

		/**
		 * legacy method
		 */
		closeAdSelector() {
			// close the ad unit selector
			setTimeout(function () {
				jQuery('#mapi-wrap').animate({ height: 0 }, 360, function () {
					jQuery('.mapi-open-selector,.advads-adsense-show-code').css(
						'display',
						'inline'
					);
					jQuery('.mapi-close-selector-link').css('display', 'none');
					jQuery('#mapi-wrap').css({
						display: 'none',
						height: 'auto',
					});
					const SNT =
						AdvancedAdsAdmin.AdImporter.adNetwork.getCustomInputs();
					SNT.css('display', 'block');
				});
			}, 80);
		},

		/**
		 * legacy method
		 * updates the UI, (call if the selected unit is supported)
		 * @param slotID
		 */
		unitIsNotSupported(slotID) {
			jQuery('#remote-ad-unsupported-ad-type').css('display', 'block');
			AdsenseMAPI.unsupportedUnits[slotID] = 1;
			jQuery('#unit-code').val('');
			jQuery('#unit-type').val('normal');
			jQuery('#ad-layout-key').val('');
			jQuery('tr[data-slotid^="ca-"]').removeClass('selected error');
			const $selectedRow = jQuery('tr[data-slotid="' + slotID + '"]');
			$selectedRow.addClass('selected error').css('background-color', '');
			this.scrollToSelectedRow($selectedRow);
		},

		/**
		 * legacy method
		 * updates the UI, (call if the selected unit is NOT supported)
		 * @param slotID
		 */
		unitIsSupported(slotID) {
			jQuery('#remote-ad-unsupported-ad-type').css('display', 'none');
			if ('undefined' !== typeof AdsenseMAPI.unsupportedUnits[slotID]) {
				delete AdsenseMAPI.unsupportedUnits[slotID];
			}
			jQuery(
				'i[data-mapiaction="getCode"][data-slotid="' + slotID + '"]'
			).removeClass('disabled');
			if (jQuery('tr[data-slotid="' + slotID + '"] .unittype a').length) {
				var td = jQuery('tr[data-slotid="' + slotID + '"] .unittype');
				var content = jQuery(
					'tr[data-slotid="' + slotID + '"] .unittype a'
				).attr('data-type');
				td.text(content);
			}
			if (jQuery('tr[data-slotid="' + slotID + '"] .unitsize a').length) {
				var td = jQuery('tr[data-slotid="' + slotID + '"] .unitsize');
				var content = jQuery(
					'tr[data-slotid="' + slotID + '"] .unitsize a'
				).attr('data-size');
				td.text(content);
			}
		},

		/**
		 * legacy method
		 * updates the UI, (call if the selected unit is NOT supported)
		 * @param msg
		 */
		emptyMapiSelector(msg) {
			const nag =
				'<div class="advads-notice-inline advads-error"><p>' +
				msg +
				'</p></div>';
			jQuery('#mapi-loading-overlay').css('display', 'none');
			jQuery('#mapi-wrap').html(jQuery(nag));
		},

		/**
		 * legacy method
		 */
		refreshAds() {
			const adNetwork = AdvancedAdsAdmin.AdImporter.adNetwork;
			jQuery('#mapi-loading-overlay').css('display', 'block');
			jQuery.ajax({
				type: 'post',
				url: ajaxurl,
				data: adNetwork.getRefreshAdsParameters(),
				success(response, status, XHR) {
					if ('undefined' !== typeof response.html) {
						jQuery('#mapi-wrap').replaceWith(jQuery(response.html));
						AdvancedAdsAdmin.AdImporter.openExternalAdsList();
					} else if ('undefined' !== typeof response.msg) {
						AdvancedAdsAdmin.AdImporter.emptyMapiSelector(
							response.msg
						);
					}
					if ('undefined' !== typeof response.raw) {
						console.log(response.raw);
					}
					jQuery('#mapi-loading-overlay').css('display', 'none');
				},
				error(request, status, err) {
					jQuery('#mapi-loading-overlay').css('display', 'none');
				},
			});
		},

		toggleIdleAds(hide) {
			if ('undefined' === typeof hide) {
				hide = true;
			}
			AdvancedAdsAdmin.AdImporter.highlightSelectedRowInExternalAdsList(
				hide
			);
		},
	};

/**
 * The "abstract" base class for handling external ad units
 * Every ad unit will provide you with a set of methods to control the GUI and trigger requests to the server
 * while editing an ad that is backed by this network. The main logic takes place in admin/assets/admin.js,
 * and the methods in this class are the ones that needed abstraction, depending on the ad network. When you
 * need new network-dependant features in the frontend, this is the place to add new methods.
 *
 * An AdvancedAdsAdNetwork uses these fields:
 * id string The identifier, that is used for this network. Must match with the one used in the PHP code of Advanced Ads
 * units array Holds the ad units of this network.
 * vars map These are the variables that were transmitted from the underlying PHP class (method: append_javascript_data)
 * hideIdle Remembers, wheter idle ads should be displayed in the list;
 * fetchedExternalAds Remembers if the external ads list has already been loaded to prevent unneccesary requests
 */
class AdvancedAdsAdNetwork {
	/**
	 * @param id string representing the id of this network. has to match the identifier of the PHP class
	 */
	constructor(id) {
		this.id = id;
		this.units = [];
		this.vars = window[id + 'AdvancedAdsJS'];
		this.hideIdle = true;
		this.fetchedExternalAds = false;
	}

	/**
	 * will be called when an ad network is selected (ad type in edit ad)
	 */
	onSelected() {
		console.error('Please override onSelected.');
	}

	/**
	 * will be called when an ad network deselected (ad type in edit ad)
	 */
	onBlur() {
		console.error('Please override onBlur.');
	}

	/**
	 * opens the selector list containing the external ad units
	 */
	openSelector() {
		console.error('Please override openSelector.');
	}

	/**
	 * returns the network specific id of the currently selected ad unit
	 */
	getSelectedId() {
		console.error('Please override getSelectedId.');
	}

	/**
	 * will be called when an external ad unit has been selected from the selector list
	 * @param slotId string the external ad unit id
	 */
	selectAdFromList(slotId) {
		console.error('Please override selectAdFromList.');
	}

	/**
	 * will be called when an the update button of an external ad unit has been clicked
	 * TODO: decide wheter to remove this method. not required anymore - the button was removed.
	 * @param slotId string the external ad unit id
	 */
	updateAdFromList(slotId) {
		console.error('Please override updateAdFromList.');
	}

	/**
	 * return the POST params that you want to send to the server when requesting a refresh of the external ad units
	 * (like nonce and action and everything else that is required)
	 */
	getRefreshAdsParameters() {
		console.error('Please override getRefreshAdsParameters.');
	}

	/**
	 * return the jquery objects for all the custom html elements of this ad type
	 */
	getCustomInputs() {
		console.error('Please override getCustomInputs.');
	}

	/**
	 * what to do when the DOM is ready
	 */
	onDomReady() {
		console.error('Please override onDomReady.');
	}

	/**
	 * when you need custom behaviour for ad networks that support manual setup of ad units, override this method
	 */
	onManualSetup() {
		//no console logging. this is optional
	}
}

class AdvancedAdsExternalAdUnit {}

/**
 * todo: this looks like something we could use in general, but where to put it?
 */
jQuery(document).ready(function () {
	// delete an existing row by removing the parent tr tag
	// todo: this could be moved to a general file
	jQuery(document).on('click', '.advads-tr-remove', function () {
		jQuery(this).closest('tr').remove();
	});
});

/**
 * If the jQuery function `escapeSelector` does not exist (add in jQuery 3.0) then add it.
 */
if (typeof jQuery.escapeSelector === 'undefined') {
	jQuery.escapeSelector = function (selector) {
		return selector.replace(
			// 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
			/([$%&()*+,./:;<=>?@\[\\\]^{|}~])/g,
			'\\$1'
		);
	};
}
