File "wpil_admin.js"

Full path: /home/webcknlt/admissiontell.com/wp-content/plugins/link-whisper-premium/js/wpil_admin.js
File size: 141.96 B (141.96 KB bytes)
MIME-type: text/plain
Charset: utf-8

Download   Open   Edit   Advanced Editor &nnbsp; Back

"use strict";

(function ($)
{

	var reloadGutenberg = false;

	/////////// preloading
	function getSuggestions(manualActivate = false){
		$('[data-wpil-ajax-container]').each(function(k, el){
			var $el = $(el);
			var url = $el.attr('data-wpil-ajax-container-url');
			var count = 0;
			var urlParams = parseURLParams(url);

			// don't load the suggestions automatically if the user has selected manual activation
			if($el.data('wpil-manual-suggestions') == 1 && !manualActivate){
				return
			}

			$el.css({'display': 'block'});
			$('.wpil-get-manual-suggestions-container').css({'display': 'none'});

			if(urlParams.type && 'outbound_suggestions_ajax' === urlParams.type[0]){
				ajaxGetSuggestionsOutbound($el, url, count);
			}else if(urlParams.type && 'inbound_suggestions_page_container' === urlParams.type[0]){
				ajaxGetSuggestionsInbound($el, url, count);
			}

			setupProcessingError();
		});
	}

	getSuggestions();

	$(document).on('click', '#wpil-get-manual-suggestions', function(e){e.preventDefault(); getSuggestions(true)});

	function ajaxGetSuggestionsInbound($el, url, count, lastPost = 0, processedPostCount = 0, key = null)
	{
		var urlParams = parseURLParams(url);
		var post_id = (urlParams.post_id) ? urlParams.post_id[0] : null;
		var term_id = (urlParams.term_id) ? urlParams.term_id[0] : null;
		var keywords = (urlParams.keywords) ? urlParams.keywords[0] : '';
		var sameParent = (urlParams.same_parent) ? urlParams.same_parent[0] : null;
		var sameCategory = (urlParams.same_category) ? urlParams.same_category[0] : '';
		var selectedCategory = (urlParams.selected_category) ? urlParams.selected_category[0].split(',') : '';
		var sameTag = (urlParams.same_tag) ? urlParams.same_tag[0] : '';
		var selectedTag = (urlParams.selected_tag) ? urlParams.selected_tag[0].split(',') : '';
		var selectPostTypes = (urlParams.select_post_types) ? urlParams.select_post_types[0] : '';
		var selectedPostTypes = (urlParams.selected_post_types) ? urlParams.selected_post_types[0].split(',') : '';
        var nonce = (urlParams.nonce) ? urlParams.nonce[0]: '';

        if(!nonce){
            return;
        }

		// start the clock on the error notice
		setupProcessingError();

        // if there isn't a key set, make one
        if(!key){
            while(true){
                key = Math.round(Math.random() * 1000000000);
                if(key > 999999){break;}
            }
        }

		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'get_post_suggestions',
                nonce: nonce,
				count: count,
				post_id: post_id,
                term_id: term_id,
				type: 'inbound_suggestions',
				keywords: keywords,
				same_parent: sameParent,
				same_category: sameCategory,
				selected_category: selectedCategory,
				same_tag: sameTag,
				selected_tag: selectedTag,
				last_post: lastPost,
                completed_processing_count: processedPostCount,
				select_post_types: selectPostTypes,
				selected_post_types: selectedPostTypes,
                key: key,
			},
			success: function(response){
				console.log(response);

				// stop the error clock and hide any visible message
				setupProcessingError(true);
				hideProcessingError();

                // if there was an error
                if(response.error){
                    // output the error message
                    wpil_swal(response.error.title, response.error.text, 'error');
                    // and exit
                    return;
                }

				count = parseInt(count) + 1;
				var progress = Math.floor(response.completed_processing_count / (response.post_count + 0.1) * 100);
				if (progress > 100) {
					progress = 100;
				}
                $('.progress_count').html(progress + '%');
				if(!response.completed){
					ajaxGetSuggestionsInbound($el, url, count, response.last_post, response.completed_processing_count, key);
				}else{
					return updateSuggestionDisplay(post_id, term_id, nonce, $el, 'inbound_suggestions', false, sameParent, sameCategory, key, selectedCategory, sameTag, selectedTag, selectPostTypes, selectedPostTypes);
				}
			},
			error: function(jqXHR, textStatus, errorThrown){
                console.log({jqXHR, textStatus, errorThrown});
//				setupProcessingError(true);
            }
		});
	}

	function ajaxGetSuggestionsOutbound($el, url, count, post_count = 0, key = null)
	{
        // if there isn't a key set, make one
        if(!key){
            while(true){
                key = Math.round(Math.random() * 1000000000);
                if(key > 999999){break;}
            }
        }

		var urlParams = parseURLParams(url);
		var post_id = (urlParams.post_id) ? urlParams.post_id[0] : null;
		var term_id = (urlParams.term_id) ? urlParams.term_id[0] : null;
		var linkOrphaned = (urlParams.link_orphaned) ? urlParams.link_orphaned[0] : null;
		var sameParent = (urlParams.same_parent) ? urlParams.same_parent[0] : null;
		var sameCategory = (urlParams.same_category) ? urlParams.same_category[0] : '';
		var selectedCategory = (urlParams.selected_category) ? urlParams.selected_category[0].split(',') : '';
		var sameTag = (urlParams.same_tag) ? urlParams.same_tag[0] : '';
		var selectedTag = (urlParams.selected_tag) ? urlParams.selected_tag[0].split(',') : '';
		var selectPostTypes = (urlParams.select_post_types) ? urlParams.select_post_types[0] : '';
		var selectedPostTypes = (urlParams.selected_post_types) ? urlParams.selected_post_types[0].split(',') : '';
        var nonce = (urlParams.nonce) ? urlParams.nonce[0]: '';

        if(!nonce){
            return;
        }

		// start the clock on the error notice
		setupProcessingError();

		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'get_post_suggestions',
                nonce: nonce,
				count: count,
				post_count: (post_count) ? parseInt(post_count): 0,
				post_id: post_id,
                term_id: term_id,
				link_orphaned: linkOrphaned,
				same_parent: sameParent,
				same_category: sameCategory,
				selected_category: selectedCategory,
				same_tag: sameTag,
				selected_tag: selectedTag,
				select_post_types: selectPostTypes,
				selected_post_types: selectedPostTypes,
				type: 'outbound_suggestions',
                key: key,
			},
			success: function(response){
				console.log({response, count});

				// stop the error clock and hide any visible message
				setupProcessingError(true);
				hideProcessingError();

                // if there was an error
                if(response.error){
                    // output the error message
                    wpil_swal(response.error.title, response.error.text, 'error');
                    // and exit
                    return;
                }

                // if there was a notice
                if(response.info){
                    // output the notice message
                    wpil_swal(response.info.title, response.info.text, 'info');
                    // and exit
                    return;
                }

				$el.find('.progress_count').html(response.message);

				if((count * response.batch_size) < response.post_count){
					ajaxGetSuggestionsOutbound($el, url, response.count, response.post_count, key);
				}else if( (sameCategory || sameTag) || (0 == wpil_ajax.site_linking_enabled) ){
					// if we're doing same tag or cat matching, skip the external sites.
					return updateSuggestionDisplay(post_id, term_id, nonce, $el, 'outbound_suggestions', linkOrphaned, sameParent, sameCategory, key, selectedCategory, sameTag, selectedTag, selectPostTypes, selectedPostTypes);
				}else{
					ajaxGetExternalSiteSuggestions($el, url, 0, 0, key);
				}
			},
            error: function(jqXHR, textStatus, errorThrown){
                console.log({jqXHR, textStatus, errorThrown});
//				setupProcessingError(true);
            }
		});
	}


	function ajaxGetExternalSiteSuggestions($el, url, count, post_count = 0, key = null)
	{
        // if there isn't a key set, make one
        if(!key){
            while(true){
                key = Math.round(Math.random() * 1000000000);
                if(key > 999999){break;}
            }
        }

		var urlParams = parseURLParams(url);
		var post_id = (urlParams.post_id) ? urlParams.post_id[0] : null;
		var term_id = (urlParams.term_id) ? urlParams.term_id[0] : null;
		var linkOrphaned = (urlParams.link_orphaned) ? urlParams.link_orphaned[0] : null;
		var sameParent = (urlParams.same_parent) ? urlParams.same_parent[0] : null;
		var sameCategory = (urlParams.same_category) ? urlParams.same_category[0] : '';
		var selectedCategory = (urlParams.selected_category) ? urlParams.selected_category[0].split(',') : '';
		var sameTag = (urlParams.same_tag) ? urlParams.same_tag[0] : '';
		var selectedTag = (urlParams.selected_tag) ? urlParams.selected_tag[0].split(',') : '';
		var selectPostTypes = (urlParams.select_post_types) ? urlParams.select_post_types[0] : '';
		var selectedPostTypes = (urlParams.selected_post_types) ? urlParams.selected_post_types[0].split(',') : '';
        var nonce = (urlParams.nonce) ? urlParams.nonce[0]: '';

        if(!nonce){
            return;
        }

		// start the clock on the error notice
		setupProcessingError();

		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'wpil_get_external_site_suggestions',
                nonce: nonce,
				count: count,
				post_count: (post_count) ? parseInt(post_count): 0,
				post_id: post_id,
                term_id: term_id,
				link_orphaned: linkOrphaned,
				same_parent: sameParent,
				same_category: sameCategory,
				selected_category: selectedCategory,
				same_tag: sameTag,
				selected_tag: selectedTag,
				select_post_types: selectPostTypes,
				selected_post_types: selectedPostTypes,
				type: 'outbound_suggestions',
                key: key,
			},
			success: function(response){
				console.log(response);
				console.log([url, count, post_count, key]);

				// stop the error clock and hide any visible message
				setupProcessingError(true);
				hideProcessingError();

                // if there was an error
                if(response.error){
                    // output the error message
                    wpil_swal(response.error.title, response.error.text, 'error');
                    // and exit
                    return;
                }

				$el.find('.progress_count').html(response.message);

				if((count * response.batch_size) < response.post_count){
					ajaxGetExternalSiteSuggestions($el, url, response.count, response.post_count, key);
				}else{
					return updateSuggestionDisplay(post_id, term_id, nonce, $el, 'outbound_suggestions', linkOrphaned, sameParent, sameCategory, key, selectedCategory, sameTag, selectedTag, selectPostTypes, selectedPostTypes);
				}
			},
            error: function(jqXHR, textStatus, errorThrown){
                console.log({jqXHR, textStatus, errorThrown});
//				setupProcessingError(true);
            }
		});
	}

    var batch = {};
	function ajaxGetSuggestionsInboundBatched($el, url, count, lastPost = 0, processedPostCount = 0, key = null)
	{



        // list the ids
        // store the process key for each run

        // run the db search one at a time


        // when the db search is complete
        // kick off an inbound search process

        // run no more than 5 processes



        // get all of the usual items
		var urlParams = parseURLParams(url);
		var post_id = (urlParams.post_id) ? urlParams.post_id[0] : null;
		var term_id = (urlParams.term_id) ? urlParams.term_id[0] : null;
		var keywords = (urlParams.keywords) ? urlParams.keywords[0] : '';
		var sameParent = (urlParams.same_parent) ? urlParams.same_parent[0] : null;
		var sameCategory = (urlParams.same_category) ? urlParams.same_category[0] : '';
		var selectedCategory = (urlParams.selected_category) ? urlParams.selected_category[0].split(',') : '';
		var sameTag = (urlParams.same_tag) ? urlParams.same_tag[0] : '';
		var selectedTag = (urlParams.selected_tag) ? urlParams.selected_tag[0].split(',') : '';
		var selectPostTypes = (urlParams.select_post_types) ? urlParams.select_post_types[0] : '';
		var selectedPostTypes = (urlParams.selected_post_types) ? urlParams.selected_post_types[0].split(',') : '';
        var nonce = (urlParams.nonce) ? urlParams.nonce[0]: '';

        if(!nonce){
            return;
        }

		// start the clock on the error notice
		setupProcessingError();

        // if there isn't a key set, make one
        if(Object.keys(batch).length < 1){
            if(post_id){
                for(var i in post_id){
                    while(true){
                        key = Math.round(Math.random() * 1000000000);
                        if(key > 999999){
                            batch['post' + post_id[i]] = key;
                            break;
                        }
                    }
                }
            }

            if(term_id){
                for(var i in term_id){
                    while(true){
                        key = Math.round(Math.random() * 1000000000);
                        if(key > 999999){
                            batch['term' + term_id[i]] = key;
                            break;
                        }
                    }
                }
            }
        }

        for(var j in batch){
            var dat = batch[j].split('_');

            var search_post_id, 
                search_term_id;

            if(dat[0] === 'post'){
                search_post_id = dat[1], 
                search_term_id = null;
            }else{
                search_post_id = null, 
                search_term_id = dat[1];
            }

            jQuery.ajax({
                type: 'POST',
                url: ajaxurl,
                data: {
                    action: 'search_for_inbound_targets',
                    nonce: nonce,
                    count: count,
                    post_id: search_post_id,
                    term_id: search_term_id,
                    keywords: keywords,
                    same_parent: sameParent,
                    same_category: sameCategory,
                    selected_category: selectedCategory,
                    same_tag: sameTag,
                    selected_tag: selectedTag,
                    last_post: lastPost,
                    completed_processing_count: processedPostCount,
                    select_post_types: selectPostTypes,
                    selected_post_types: selectedPostTypes,
                    key: key,
                },
                success: function(response){
                    console.log(response);

                    // stop the error clock and hide any visible message
                    setupProcessingError(true);
                    hideProcessingError();

                    // if there was an error
                    if(response.error){
                        // output the error message
                        wpil_swal(response.error.title, response.error.text, 'error');
                        // and exit
                        return;
                    }

                    count = parseInt(count) + 1;
                    var progress = Math.floor(response.completed_processing_count / (response.post_count + 0.1) * 100);
                    if (progress > 100) {
                        progress = 100;
                    }
                    $('.progress_count').html(progress + '%');
                    if(!response.completed){
                        ajaxGetSuggestionsInbound($el, url, count, response.last_post, response.completed_processing_count, key);
                    }else{
                        return updateSuggestionDisplay(post_id, term_id, nonce, $el, 'inbound_suggestions', false, sameParent, sameCategory, key, selectedCategory, sameTag, selectedTag, selectPostTypes, selectedPostTypes);
                    }
                },
                error: function(jqXHR, textStatus, errorThrown){
                    console.log({jqXHR, textStatus, errorThrown});
    //				setupProcessingError(true);
                }
            });
        }
	}

	function updateSuggestionDisplay(postId, termId, nonce, $el, type = 'outbound_suggestions', linkOrphaned, sameParent, sameCategory = '', key = null, selectedCategory, sameTag, selectedTag, selectPostTypes, selectedPostTypes){
		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'update_suggestion_display',
                nonce: nonce,
				post_id: postId,
                term_id: termId,
                key: key,
				type: type,
				link_orphaned: linkOrphaned,
				same_parent: sameParent,
				same_category: sameCategory,
				selected_category: selectedCategory,
				same_tag: sameTag,
				selected_tag: selectedTag,
				select_post_types: selectPostTypes,
				selected_post_types: selectedPostTypes,
			},
			success: function(response){
                // if there was an error
                if(response.error){
                    // output the error message
                    wpil_swal(response.error.title, response.error.text, 'error');
                    // and exit
                    return;
                }

                // update the suggestion report
				$el.html(response);
				// style the sentences
				styleSentences();
				// initialize the sentence editor
				wpilEditorInitialize();
				// make sure the error notice is cleared
				setupProcessingError(true);
				hideProcessingError();
			}
		});
	}

    /**
     * Helper function that parses urls to get their query vars.
     **/
	function parseURLParams(url) {
		var queryStart = url.indexOf("?") + 1,
			queryEnd   = url.indexOf("#") + 1 || url.length + 1,
			query = url.slice(queryStart, queryEnd - 1),
			pairs = query.replace(/\+/g, " ").split("&"),
			parms = {}, i, n, v, nv;
	
		if (query === url || query === "") return;
	
		for (i = 0; i < pairs.length; i++) {
			nv = pairs[i].split("=", 2);
			n = decodeURIComponent(nv[0]);
			v = decodeURIComponent(nv[1]);
	
			if (!parms.hasOwnProperty(n)) parms[n] = [];
			parms[n].push(nv.length === 2 ? v : null);
		}
		return parms;
	}

	function wpilImplodeEls(sep, els)
	{
		var res = [];
		$(els).each(function(k, el) {
			res.push(el.outerHTML);
		});

		return res.join(sep);
	}

	function wpilImplodeText(sep, els)
	{
		var res = [];
		$(els).each(function(k, el) {
			var $el = $(el);
			res.push($el.text());
		});

		return res.join(sep);
	}

	function wpilPushFix($ex)
	{
		var $div = $("<div/>");
		$div.append($ex);
		return $div.html();
	}

	$(document).on('click', '.wpil_sentence a', function (e) {
		e.preventDefault();
	});

	var wordClicked = false;
	var wordClickedWait;
	var doubleClickWait;
	var clickedWordId = false;
	var clickedSentenceId = false;
	var notDirectlyStyled = true;
	$(document).on('click', '[class*=wpil_word]', function (e) {
		e.preventDefault();

		var clickedWord = $(this);
		var sentence = clickedWord.closest('.wpil_sentence');
		var inboundSelectedId = sentence.closest('.wpil-inbound-sentence-data-container').data('container-id');
		var collapsible = (sentence.closest('.wpil-collapsible').length > 0) ? true: false;

		if(wordClicked && false === clickedWordId || sentence.hasClass('wpil-disable-word-click')){
			return;
		}else if(	clickedWordId === clickedWord.data('wpil-word-id') &&
					clickedSentenceId === clickedWord.closest('tr').data('wpil-sentence-id') &&
					notDirectlyStyled
		){
			processDoubleClick(clickedSentenceId, clickedWordId, inboundSelectedId);
			return;
		}else if(wordClicked){
			return;
		}

		wordClicked = true;
		notDirectlyStyled = true;

		// set up a timeout on the word clicked check so if processing fails the user doesn't have to reload the page to use the suggestion panel.
		clearTimeout(wordClickedWait);
		wordClickedWait = setTimeout(function(){
			wordClicked = false;
			notDirectlyStyled = true;
		}, 250);

		// set up a double click timeout to clear the double click watcher
		clearTimeout(doubleClickWait);
		doubleClickWait = setTimeout(function(){
			clickedWordId = false;
			clickedSentenceId = false;
		}, 200);


		// find the words in the current sentence
		var $words = sentence.find('.wpil_word');

		// tag all the words in the sentence with ids
		var word_id = 0;
		var word_id_attr = 'wpil-word-id';
		$words.each(function(i, el) {
			word_id++;
			var $el = $(el);
			$el.data(word_id_attr, word_id);
			$el.attr('data-' + word_id_attr, word_id);
		});

		// get the id of the clicked word and the current sentece
		clickedWordId = clickedWord.data('wpil-word-id');
		clickedSentenceId = clickedWord.closest('tr').data('wpil-sentence-id');

		if(clickedWordId > 1){
			var previousTag = sentence.find('[data-wpil-word-id="' + (clickedWordId - 1) + '"]');
			var nextTag = sentence.find('[data-wpil-word-id="' + (clickedWordId + 1) + '"]');
			if(nextTag.length && previousTag.hasClass('open-tag') && nextTag.hasClass('close-tag')){
				notDirectlyStyled = false;
			}
		}

		// find all the words in the anchor and get the start and end words of the anchor
		var anchorWords = sentence.find('a span');
		var start = anchorWords.first().data('wpil-word-id');
		var end = anchorWords.last().data('wpil-word-id');
		var middleWord = findMiddleWord(start, end, anchorWords);
		var clickedPos = clickedWord.data('wpil-word-id');

		// get the link minus contents
		var anchorClone = sentence.clone().find('a').html('');

		// if the link start and end is undefinded, insert a link at the click location
		if(undefined === end && undefined === start){
			console.log('no link');

			// set the clicked word as the link's only word
			var linkWords = sentence.find('[data-wpil-word-id="' + clickedPos + '"]');

			// clone the word
			var clonedWords = linkWords.clone();

			// create a new link if we didn't find one
			if(anchorClone.length < 1){
				anchorClone = $('<a href="%view_link%" target="_blank"></a>');
			}

			// insert the cloned words into the cloned anchor
			anchorClone = anchorClone.html(clonedWords);

			// replace the anchor with just the words
			sentence.find('a').replaceWith(sentence.find('a').html());

			// now remove all the new anchor words from the sentence
			sentence.find('[data-wpil-word-id="' + clickedPos + '"]').remove();

			if((clickedPos - 1) > 0){
				// insert the anchor before the clicked word in the sentence
				anchorClone.insertAfter(sentence.find('[data-wpil-word-id="' + (clickedPos - 1) + '"]'));
			}else{
				// insert the anchor at the start of the sentence
				sentence.prepend(anchorClone);
			}

			customSentenceRefresh(sentence);

			if (sentence.closest('.wp-list-table').hasClass('inbound')) {
				var li = sentence.closest('li');
				if(li.length){
					sentence.closest('li').find('input[type="radio"]').click();
				}else if(li.length < 1 && collapsible){ // if the sentence is the top-level sentence in a dropdown
					updateDropdownSentence(sentence);
				}
			}
			toggleSentenceReset(sentence);

			wordClicked = false;
			return;
		}

		// find out where the clicked word lands relative to the anchor
		if((clickedPos > end || clickedPos >= middleWord)){
			// if it's past the end of the anchor or middle of the sentence
			console.log('link end');

			// if the user clicked on the last word in the link,
			// reduce the clicked pos by 1 to remove the word from the link
			if(end == clickedPos && start < end){
				clickedPos -= 1;
			}

			var wordIds = numberRange(start, clickedPos);

			// find all the words that will be in the link
			var wordString = '[data-wpil-word-id="' + wordIds.join('"], [data-wpil-word-id="') + '"]';
			var linkWords = sentence.find(wordString);

			// clone the words
			var clonedWords = linkWords.clone();
			
			// insert the cloned words into the cloned anchor
			anchorClone = anchorClone.html(clonedWords);

			// replace the anchor with just the words
			sentence.find('a').replaceWith(sentence.find('a').html());

			// now remove all the new anchor words from the sentence
			sentence.find(wordString).remove();

			if((start - 1) > 0){
				// insert the anchor before the clicked word in the sentence
				anchorClone.insertAfter(sentence.find('[data-wpil-word-id="' + (start - 1) + '"]'));
			}else{
				// insert the anchor at the start of the sentence
				sentence.prepend(anchorClone);
			}
		}else if(clickedPos < start || clickedPos < middleWord){
			console.log('link start');
			// if it's past the end of the anchor or middle of the sentence

			// if the user clicked on the last word in the link,
			// increase the clicked pos by 1 to remove the word from the link
			if(start == clickedPos && start < end){
				clickedPos += 1;
			}

			var wordIds = numberRange(clickedPos, end);

			// find all the words that will be in the link
			var wordString = '[data-wpil-word-id="' + wordIds.join('"], [data-wpil-word-id="') + '"]';
			var linkWords = sentence.find(wordString);

			// clone the words
			var clonedWords = linkWords.clone();

			// insert the cloned words into the cloned anchor
			anchorClone = anchorClone.html(clonedWords);

			// replace the anchor with just the words
			sentence.find('a').replaceWith(sentence.find('a').html());

			// now remove all the new anchor words from the sentence
			sentence.find(wordString).remove();

			if((clickedPos - 1) > 0){
				// insert the anchor before the clicked word in the sentence
				anchorClone.insertAfter(sentence.find('[data-wpil-word-id="' + (clickedPos - 1) + '"]'));
			}else{
				// insert the anchor at the start of the sentence
				sentence.prepend(anchorClone);
			}
		}

		spaceSentenceWords(sentence);

		// check for html style tags inside the link
		var tags = $(anchorClone).find('.wpil_suggestion_tag');

		// if there are some
		if(tags.length){
			// process the tags
			processSentenceTags(sentence, anchorClone);
		}

		styleSentenceWords(sentence);

		customSentenceRefresh(sentence);

		if (sentence.closest('.wp-list-table').hasClass('inbound')) {
			var li = sentence.closest('li');
			if(li.length){
				sentence.closest('li').find('input[type="radio"]').click();
			}else if(li.length < 1 && collapsible){ // if the sentence is the top-level sentence in a dropdown
				updateDropdownSentence(sentence);
			}
		}
		toggleSentenceReset(sentence);
		wordClicked = false;
	});

	function processDoubleClick(sentenceId, wordId, dataId = false){
		// if this is
		if(false !== dataId){
			// get the current sentence
			var sentence = $('tr[data-wpil-sentence-id="' + sentenceId + '"] .wpil-inbound-sentence-data-container[data-container-id="' + dataId + '"] [data-wpil-word-id="' + wordId + '"]').closest('.wpil_sentence');
		}else{
			// get the current sentence
			var sentence = $('tr[data-wpil-sentence-id="' + sentenceId + '"] .top-level-sentence [data-wpil-word-id="' + wordId + '"]').closest('.wpil_sentence');
		}

		// get the link minus contents
		var anchorClone = sentence.clone().find('a').html('');

		// set the clicked word as the link's only word
		var linkWords = sentence.find('[data-wpil-word-id="' + wordId + '"]');

		// clone the word
		var clonedWords = linkWords.clone();
		
		// create a new link if we didn't find one
		if(anchorClone.length < 1){
			anchorClone = $('<a href="%view_link%" target="_blank"></a>');
		}

		// insert the cloned words into the cloned anchor
		anchorClone = anchorClone.html(clonedWords);

		// replace the anchor with just the words
		sentence.find('a').replaceWith(sentence.find('a').html());

		// now remove all the new anchor words from the sentence
		sentence.find('[data-wpil-word-id="' + wordId + '"]').remove();

		if((wordId - 1) > 0){
			// insert the anchor before the clicked word in the sentence
			anchorClone.insertAfter(sentence.find('[data-wpil-word-id="' + (wordId - 1) + '"]'));
		}else{
			// insert the anchor at the start of the sentence
			sentence.prepend(anchorClone);
		}

		spaceSentenceWords(sentence);

		// check for html style tags inside the link
		var tags = $(anchorClone).find('.wpil_suggestion_tag');

		// if there are some
		if(tags.length){
			// process the tags
			processSentenceTags(sentence, anchorClone);
		}

		styleSentenceWords(sentence);
		customSentenceRefresh(sentence);

		if (sentence.closest('.wp-list-table').hasClass('inbound')) {
			var li = sentence.closest('li');
			if(li.length){
				sentence.closest('li').find('input[type="radio"]').click();
			}else if(li.length < 1 && sentence.closest('.wpil-collapsible').length > 0){ // if the sentence is the top-level sentence in a dropdown
				updateDropdownSentence(sentence);
			}
		}
		toggleSentenceReset(sentence);

		wordClicked = false;
		clickedWordId = false;
		clickedSentenceId = false;

		// clear any selections so the user doesn't wind up selecting the full sentence
		clearSelection();
	}

	/**
	 * Helper function to clear any text selection
	 **/
	function clearSelection(){
		if(window.getSelection){
			window.getSelection().removeAllRanges();
		}else if(document.selection){
			document.selection.empty();
		}
	}

	function findMiddleWord(start = 0, end = 0, words = []){
		start = parseInt(start);
		end = parseInt(end);

		if(start === end){
			return start;
		}

		var letterRange = [];
		var totalLetters = 0;
		words.each(function(index, word){
			word = $(word);
			if(!word.hasClass('wpil_suggestion_tag')){
				var length = word.text().length;
				totalLetters += length;
				letterRange[word.data('wpil-word-id')] = length;
			}
		});

		var middleLetter = Math.round(totalLetters/2);
		var currentCount = 0;
		var middle = 0;
		for(var i in letterRange){
			currentCount += letterRange[i];

			if(currentCount >= middleLetter){
				middle = i;
				break;
			}
		}

		return middle;
	}

	function numberRange(start = 0, end = 0){
		var result = [];
		for(var i = start; i <= end; i++){
			result.push(i);
		}

		return result;
	}

	/**
	 * Sets the correct word spacing on words in the clicked sentence.
	 * @param {object} sentence 
	 */
	function spaceSentenceWords(sentence){
		var words = sentence.find('.wpil_word');

		// find all the existing spaces in the sentence
		var spaces = [];
		sentence.contents().filter(function(){
			if(this.nodeType === Node.TEXT_NODE){
				spaces.push(this);
			}
		});

		// and remove them
		$(spaces).remove();

		// now add new spaces to the sentence
		sentence.find('span').map(function(index, element) {
			var $el = $(this);
			var data = [];

			if(0 === index){
				if(undefined !== words[index + 1] && $(words[index + 1]).hasClass('no-space-left')){
					data = [this];
				}else if($el.hasClass('no-space-right')){
					data = [document.createTextNode(' '), this];
				}else{
					data = [this, document.createTextNode(' ')];
				}
			}else{
				if(undefined !== words[index + 1] && $(words[index + 1]).hasClass('no-space-left')){
					data = [this];
				}else if(undefined !== words[index + 1] && $(words[index + 1]).hasClass('no-space-right')){
					data = [document.createTextNode(' '), this];
				}else if($el.hasClass('no-space-right')){
					data = [this];
				}else{
					data = [this, document.createTextNode(' ')];
				}
			}

			$(data).insertAfter(element);
		});
	}

	/**
	 * Moves the html style tags based on the user's link selection so we don't get half a style tag in the link with the other half outside it.
	 * @param sentence 
	 * @param anchor 
	 */
	function processSentenceTags(sentence, anchor){
		var tagTypes = ['wpil-bold', 'wpil-ital', 'wpil-under', 'wpil-strong', 'wpil-em', 'wpil-code'];

		// find all the tags in the anchor and add them to a list
		var anchorTagData = {};
		anchor.find('.wpil_suggestion_tag').map(function(){
			var $el = $(this);
			for(var i in tagTypes){
				if($el.hasClass(tagTypes[i])){
					if(undefined === anchorTagData[tagTypes[i]]){
						anchorTagData[tagTypes[i]] = [];
					}

					anchorTagData[tagTypes[i]].push($el);
				}
			}
		});

		// look over all the found tags
		var keys = Object.keys(anchorTagData);
		$(keys).each(function(index, key){
			// if the anchor doesn't contain the opening and closing tags, 
			// move the tag to the correct location
			if(anchorTagData[key].length === 1){
				// if the tag is an opening one
				if(anchorTagData[key][0].hasClass('open-tag')){
					// move it right until it's outside the anchor
					var tag = sentence.find(anchorTagData[key][0]).detach();
					tag.insertAfter(sentence.find('a'));
				}else{
					// if the tag is an opening one, move it left until it's outside the anchor
					var tag = sentence.find(anchorTagData[key][0]).detach();
					tag.insertBefore(sentence.find('a'));
				}

			}else if(anchorTagData[key].length > 2){
				// todo handle cases where there's 3 of the same type of tag in the link...
			}
		});

		// now remove any tags that are right next to each other
		var words = sentence.find('span');
		words.map(function(index, element){
			var current = $(element);
			// if this is a style tag and the word after this one is a style tag
			if(current.hasClass('wpil_suggestion_tag') && undefined !== words[index + 1] && $(words[index + 1]).hasClass('wpil_suggestion_tag')){
				var next = $(words[index + 1]);

				// see if they're both the same kind of tag
				var tagType = '';
				for(var i in tagTypes){
					if(current.hasClass(tagTypes[i])){
						tagType = tagTypes[i];
						break;
					}
				}

				// if it does
				if(next.hasClass(tagType)){
					// remove both tags
					sentence.find(current).remove();
					sentence.find(next).remove();
				}
			}
		});
	}

	/**
	 * Styles the words in the sentence based on the HTML style tags found in the text.
	 * Mostly this is to give the user some idea of what we're doing with his style tags.
	 * @param sentence 
	 */
	function styleSentenceWords(sentence){
		var tagTypes = ['wpil-bold', 'wpil-ital', 'wpil-under', 'wpil-strong', 'wpil-em', 'wpil-code'];
		var styleSettings = {'wpil-bold': {'font-weight': 600}, 'wpil-ital': {'font-style': 'italic'},  'wpil-under': {'text-decoration': 'underline'}, 'wpil-strong': {'font-weight': 600}, 'wpil-em': {'font-style': 'italic'}, 'wpil-code': {'font-family': 'monospace'}};
		var styles = {};

		var words = sentence.find('span');
		words.map(function(index, element){
			var current = $(element);
			// if this is a style tag
			if(current.hasClass('wpil_suggestion_tag')){
				// find out what kind it is
				var tagType = '';
				for(var i in tagTypes){
					if(current.hasClass(tagTypes[i])){
						tagType = tagTypes[i];
						break;
					}
				}

				// if it's an opening tag
				if(current.hasClass('open-tag')){
					// add the correct styles to the styling array to mimic the html tag effect
					for(var key in styleSettings[tagType]){
						styles[key] = styleSettings[tagType][key];
					}
				}else{
					// if it's a closing tag, remove the style
					for(var key in styleSettings[tagType]){
						delete styles[key];
					}
				}
			}else{
				current.removeAttr("style").css(styles);
			}
		});
	}

	/**
	 * Styles all of the page's sentences.
	 */
	function styleSentences(){
		$('#the-list .sentence .wpil_sentence, #the-list .wpil-content .wpil_sentence').each(function(index, sentence){
			styleSentenceWords($(sentence));
		});
	}

	var same_category_loading = false;

	$(document).on('click', '#wpil-regenerate-suggestions', function(){
		if (!same_category_loading) {
			same_category_loading = true;
			var container = $(this).closest('[data-wpil-ajax-container]');
			var url = container.attr('data-wpil-ajax-container-url');
			var urlParams = parseURLParams(url);
			var linkOrphaned = container.find('#field_link_orphaned').prop('checked');
			var sameParent = container.find('#field_same_parent').prop('checked');
			var sameCategory = container.find('#field_same_category').prop('checked');
			var selectedCategories = container.find('select[name="wpil_selected_category"').val();
			var sameTag = container.find('#field_same_tag').prop('checked');
			var selectedTags = container.find('select[name="wpil_selected_tag"').val();
			var category_checked = '';
			var tag_checked = '';
			var post_id = (urlParams.post_id) ? urlParams.post_id[0] : 0;
			var postTypeSelect = container.find('#field_select_post_types').prop('checked');
			var postTypes = container.find('select[name="selected_post_types"').val();

			// remove any active filtering settings
			url = url.replace(new RegExp("(&link_orphaned[^&]*)|(&same_parent[^&]*)|(&same_category[^&]*)|(&same_tag[^&]*)|(&select_post_types[^&]*)|(&selected_category[^&]*)|(&selected_tag[^&]*)|(&selected_post_types[^&]*)", 'ig'), '');

			//link to orphaned
			if (linkOrphaned) {
				url += "&link_orphaned=true";
			}

			//same parent
			if (sameParent) {
				url += "&same_parent=true";
			}

			//category
			if (sameCategory) {
				url += "&same_category=true";
				url += "&selected_category=" + selectedCategories.join(',');
				category_checked = 'checked="checked"';
			}

			//tag
			if (sameTag) {
				url += "&same_tag=true";
				url += "&selected_tag=" + selectedTags.join(',');
				tag_checked = 'checked="checked"';
			}

			// selected post types
			if(postTypeSelect && postTypes){
				url += "&select_post_types=true";
				url += "&selected_post_types=" + postTypes.join(',');
			}

			if(urlParams.wpil_no_preload && '1' === urlParams.wpil_no_preload[0]){
				var checkAndButton = '<div style="margin-bottom: 30px;">' +
						'<input style="margin-bottom: -5px;" type="checkbox" name="same_category" id="field_same_category_page" ' + category_checked + '>' +
						'<label for="field_same_category_page">Only Show Link Suggestions in the Same Category as This Post</label> <br>' +
						'<input style="margin-bottom: -5px;" type="checkbox" name="same_tag" id="field_same_tag_page" ' + tag_checked + '>' +
						'<label for="field_same_category_page">Only Show Link Suggestions with the Same Tag as This Post</label> <br>' +
					'</div>' +
					'<button id="inbound_suggestions_button" class="sync_linking_keywords_list button-primary" data-id="' + post_id + '" data-type="inbound_suggestions_page_container" data-page="inbound">Custom links</button>';
				container.html(checkAndButton);
			}else{
				container.html('<div class="progress_panel loader"><div class="progress_count" style="width: 100%"></div></div>');
			}

			if(urlParams.type && 'outbound_suggestions_ajax' === urlParams.type[0]){
				ajaxGetSuggestionsOutbound(container, url, 0);
			}else if(urlParams.type && 'inbound_suggestions_page_container' === urlParams.type[0]){
				ajaxGetSuggestionsInbound(container, url, 0);
			}

			same_category_loading = false;
		}
	});

	$(document).on('change', '#field_link_orphaned, #field_same_parent, #field_same_category, #field_same_tag, #field_select_post_types, select[name="wpil_selected_category"], select[name="wpil_selected_tag"], select[name="selected_post_types"], .wpil-suggestions-can-be-regenerated', function(){
		var inputs = $('.wpil-suggestion-input');
		var changed = false;
		inputs.each(function(index, element){
			var el = $(element);
			var initial = el.data('suggestion-input-initial-value');
			if(el.is("input") && el.attr('type') === 'checkbox' && el.is(":checked") != initial){
				changed = true;
			}else if(el.is("input") && el.attr('type') === 'hidden' && el.val() !== initial){
				changed = true;
			}else if(el.is("select") && initial.toString() !== el.val().join(',')){
				changed = true;
			}
		});

		if(changed){
			$('#wpil-regenerate-suggestions').removeClass('disabled').prop('disabled', false);
		}else{
			$('#wpil-regenerate-suggestions').addClass('disabled').prop('disabled', true);
		}
	});

	$(document).on('change', '#field_select_post_types,#field_same_tag,#field_same_category', function(){
		var name = $(this).attr('name');
		if($(this).is(":checked")){
			$('.best_keywords .select2, #wpil-inbound-suggestions-head-controls .' + name + '-aux .select2, .' + name + '-aux').css({'display': 'inline-block'});
		}else{
			$('.best_keywords .select2, #wpil-inbound-suggestions-head-controls .' + name + '-aux .select2, .' + name + '-aux').css({'display': 'none'});
		}
	});

	/*
	$(document).on('change', '#field_same_category_page', function(){
		var url = document.URL;
		if ($(this).prop('checked')) {
			url += "&same_category=true";
		} else {
			url = url.replace('/&same_category=true/g', '');
		}

		location.href = url;
	});
*/

	$(document).on('click', '.sync_linking_keywords_list', function (e) {
		e.preventDefault();

		var page = $(this).data('page');
		var links = [];
		var data = [];
		var button = $(this);
		$(this).closest('div:not(#wpil-inbound-suggestions-head-controls)').find('[wpil-link-new][type=checkbox]:checked').each(function() {
			if (page == 'inbound') {
				var item = {};
				item.id = $(this).closest('tr').find('.sentence').data('id');
				item.type = $(this).closest('tr').find('.sentence').data('type');
				item.links = [{
					'sentence': $(this).closest('tr').find('.sentence').find('[name="sentence"]').val(),
					'sentence_with_anchor': $(this).closest('tr').find('.wpil_sentence_with_anchor').html(),
					'custom_sentence': $(this).closest('tr').find('input[name="custom_sentence"]').val()
				}];

				data.push(item);
			} else {
				if ($(this).closest('tr').find('input[type="radio"]:checked').length) {
					var id =  $(this).closest('tr').find('input[type="radio"]:checked').data('id');
					var type = $(this).closest('tr').find('input[type="radio"]:checked').data('type');
					var custom_link = $(this).closest('tr').find('input[type="radio"]:checked').data('custom');
					var post_origin = $(this).closest('tr').find('input[type="radio"]:checked').data('post-origin');
					var site_url = $(this).closest('tr').find('input[type="radio"]:checked').data('site-url');
				} else {
					var id =  $(this).closest('tr').find('.suggestion').data('id');
					var type =  $(this).closest('tr').find('.suggestion').data('type');
					var custom_link =  $(this).closest('tr').find('.suggestion').data('custom');
					var post_origin = $(this).closest('tr').find('.suggestion').data('post-origin');
					var site_url = $(this).closest('tr').find('.suggestion').data('site-url');
				}

				links.push({
					id: id,
					type: type,
					custom_link: custom_link,
					post_origin: post_origin,
					site_url: site_url,
					sentence: $(this).closest('div').find('[name="sentence"]').val(),
					sentence_with_anchor: $(this).closest('div').find('.wpil_sentence_with_anchor').html(),
					custom_sentence: $(this).closest('.sentence').find('input[name="custom_sentence"]').val()
				});
			}
		});

		if (page == 'outbound') {
			data.push({'links': links});
		}else{
			button.addClass('wpil_button_is_active');
		}

		$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').addClass('ajax_loader');

		var data_post = {
			"id": $(this).data('id'),
			"type": $(this).data('type'),
			"page": $(this).data('page'),
			"action": 'wpil_save_linking_references',
			'data': data,
			'gutenberg' : $('.block-editor-page').length ? true : false
    	};

		$.ajax({
			url: ajaxurl,
			dataType: 'json',
			data: data_post,
			method: 'post',
			error: function (jqXHR, textStatus, errorThrown) {
                var wrapper = document.createElement('div');
                $(wrapper).append('<strong>' + textStatus + '</strong><br>');
                $(wrapper).append(jqXHR.responseText);
                wpil_swal({"title": "Error", "content": wrapper, "icon": "error"});

				$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
			},
			success: function (data) {
				if (data.err_msg) {
					wpil_swal('Error', data.err_msg, 'error');
					button.removeClass('wpil_button_is_active');
					$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
				} else if(undefined != data.further_processing && data.further_processing){
					continueInsertingInboundLinks(button, data.data);
				}else {
					if (page == 'outbound') {
						if ($('.editor-post-save-draft').length) {
							$('.editor-post-save-draft').click();
						} else if ($('#save-post').length) {
							$('#save-post').click();
						} else if ($('.editor-post-publish-button').length) {
							$('.editor-post-publish-button').click();
						} else if ($('#publish').length) {
							$('#publish').click();
						} else if ($('.edit-tag-actions').length) {
							$('.edit-tag-actions input[type="submit"]').click();
						}

						// set the flag so we know that the editor needs to be reloaded
						reloadGutenberg = true;
					} else {
						location.reload();
					}

					button.removeClass('wpil_button_is_active');
					$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
				}
			}
		})
	});

	function continueInsertingInboundLinks(button, data){
		if(!button || !data){
			return;
		}

		// go over all the datas that have been given to us and remove any Inbound Internal Suggestion Rows that are checked and not on the list
		$('.chk-keywords:checked').each(function(index, element){
			var row = $(element).parents('tr.wpil-inbound-sentence');
			var postData = row.find('div.suggestion');

			if(postData.length > 0){
				var type = postData.data('type'); // saving sanity
				var id = postData.data('id');

				if(undefined != data[type] && undefined == data[type][id]){
					row.fadeOut(300, function(){ $(this).remove(); });
				}
			}
		});

		var ajaxData = {
			"action": 'wpil_continue_inbound_saving_process',
			"target_id": button.data('id'),
			"target_type": button.data('type'),
			'data': data
    	};

		$.ajax({
			url: ajaxurl,
			dataType: 'json',
			data: ajaxData,
			method: 'post',
			error: function (jqXHR, textStatus, errorThrown) {
                var wrapper = document.createElement('div');
                $(wrapper).append('<strong>' + textStatus + '</strong><br>');
                $(wrapper).append(jqXHR.responseText);
                wpil_swal({"title": "Error", "content": wrapper, "icon": "error"});

				$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
			},
			success: function (response) {
				if (response.err_msg) {
					wpil_swal('Error', response.err_msg, 'error');
					button.removeClass('wpil_button_is_active');
					$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
				} else if(undefined != response.further_processing && response.further_processing){
					continueInsertingInboundLinks(button, response.data);
				} else{
					button.removeClass('wpil_button_is_active');
					$('.wpil_keywords_list, .tbl-link-reports .wp-list-table').removeClass('ajax_loader');
					location.reload();
				}
			}
		})
	}

	$(document).on('change', '#suggestion_filter_field', filterSuggestionsWaiter);
	$(document).on('keyup', '#suggestion_filter_field', filterSuggestionsWaiter);

	var filterSuggestionsWait = false;
	function filterSuggestionsWaiter(){
		clearTimeout(filterSuggestionsWait);
		filterSuggestionsWait = setTimeout(filterSuggestions, 500);
	}

	var filteringSuggestions = false;
    function filterSuggestions(){
		var keywords = $('#suggestion_filter_field').val();
		var inbound = ($('.wpil-inbound-links').length > 0) ? true: false;

		// exit if the suggestion table isn't currently being filtered for keywords and there are no keywords
		if(!filteringSuggestions && '' === keywords){
			return;
		}

		filteringSuggestions = true;

		// close any open editors
		var editors = $('[id^="wp-wpil_editor"][id$="-wrap"]');
		editors.each(function(index, element){
			var block = $(element).closest('.sentence');
			if(block.length > 0){
				wpil_editor_remove(block);
			}
		});

		// if there are no keywords, show all suggestions and close the dropdowns
		if(keywords === '' || keywords.trim() === ''){
			$('.wpil-active').removeClass('wpil-active');
			$('.hidden-suggestion').removeClass('hidden-suggestion');
			$('.wpil-content').css({'display':'none'});
			filteringSuggestions = false;
			return;
		}else if(keywords.length > 0){
			keywords = keywords.trim().toLowerCase().split("\n");
		}

		// go over each suggestion
		$('.wpil-inbound-links tr:not(.wpil-suggestion-table-heading), .wpil-outbound-links tr:not(.wpil-suggestion-table-heading)').each(function(index, element){
			var wrapper = $(element).find('.wpil-collapsible-wrapper');
			var visibleCount = 0;

			// if the suggested post has a dropdown selector
			if(wrapper.length > 0){
				// go over each suggestion and hide the ones without the filter words
				$(element).find('.wpil-content li').each(function(index, element2){
					if(inbound){
						var text = $(element2).find('.wpil_sentence_with_anchor').text().trim().toLowerCase();
					}else{
						var text = $(element2).find('.suggested-post-title').text().trim().toLowerCase();
					}
					var hasKeyword = false;
					var hasNegativeKeyword = false;
					var doingKeywordSearch = false;
					var doingNegativeMatch = false;
	
					for(var i in keywords){
						// check if the a negative char is used
						var negativeMatch = keywords[i].length > 1 && keywords[i].charAt(0) === '-';
	
						if(!hasKeyword && false === negativeMatch && -1 !== text.indexOf(keywords[i])){ // if the suggestion has the keyword somewhere
							hasKeyword = true;
						}else if(!hasNegativeKeyword && true === negativeMatch && -1 !== text.indexOf(keywords[i].slice(1))){ // if the suggestion has a keyword the user doesn't want
							hasNegativeKeyword = true;
						}
	
						if(negativeMatch){
							doingNegativeMatch = true;
						}else{
							doingKeywordSearch = true;
						}
					}
	
					if(	(!hasKeyword && !doingNegativeMatch) || 
						(hasNegativeKeyword) || 
						(doingKeywordSearch && doingNegativeMatch && !hasNegativeKeyword && !hasKeyword))
					{
						$(element2).addClass('hidden-suggestion');
					}else{
						$(element2).removeClass('hidden-suggestion');
						visibleCount++;
					}
				});

				var containers = $(element).find('.wpil-collapsible-wrapper, .wpil-collapsible');
				if(visibleCount === 0){
					if($(containers[0]).hasClass('wpil-active')){ $(containers[0]).removeClass('wpil-active'); }
					if($(containers[1]).hasClass('wpil-active')){ $(containers[1]).removeClass('wpil-active'); }
					$(element).find('.wpil-content').css({'display':'none'});
					$(element).addClass('hidden-suggestion');
				}else{
					if(!$(containers[0]).hasClass('wpil-active')){ $(containers[0]).addClass('wpil-active'); }
					if(!$(containers[1]).hasClass('wpil-active')){ $(containers[1]).addClass('wpil-active'); }
					$(element).removeClass('hidden-suggestion');
					$(element).find('.wpil-content').css({'display':'block'});

					// select the top sentence and set it to be the top_level_sentence
					if(!$(element).find('.chk-keywords').is(':checked')){
						var firstVisible = $(element).find('.wpil-content li:not(.hidden-suggestion) input').first();
						var id = $(firstVisible).data('id');
						var data = $(firstVisible).closest('li').find('.data').html();

						if(inbound){
							$(firstVisible).closest('ul').find('input').prop('checked', false);
							$(firstVisible).prop('checked', true);
							$(firstVisible).closest('.wpil-collapsible-wrapper').find('.sentence').html(data + '<span class="wpil_edit_sentence">| <a href="javascript:void(0)">Edit Sentence</a></span>');
							$(firstVisible).closest('tr').find('input[type="checkbox"]').prop('checked', false);
							$(firstVisible).closest('tr').find('.raw_html').hide();
							$(firstVisible).closest('tr').find('.raw_html[data-id="' + id + '"]').show();
						}else{
							var type = $(firstVisible).data('type');
							var suggestion = $(firstVisible).data('suggestion');
							var origin = $(firstVisible).data('post-origin');
							var siteUrl = $(firstVisible).data('site-url');

							$(firstVisible).closest('ul').find('input').prop('checked', false);

							$(firstVisible).prop('checked', true);
							$(firstVisible).closest('.wpil-collapsible-wrapper').find('.wpil-collapsible-static').html('<div data-id="' + id + '" data-type="' + type + '" data-post-origin="' + origin + '" data-site-url="' + siteUrl + '">' + data + '<span class="add_custom_link_button link-form-button"> | <a href="javascript:void(0)">Custom Link</a></span><span class="wpil_add_link_to_ignore link-form-button"> | <a href="javascript:void(0)">Ignore Link</a></span></div>');
							$(firstVisible).closest('tr').find('input[type="checkbox"]').prop('checked', false);
							$(firstVisible).closest('tr').find('input[type="checkbox"]').val(suggestion + ',' + id);

							if (!$(firstVisible).closest('tr').find('input[data-wpil-custom-anchor]').length && $(firstVisible).closest('tr').find('.sentence[data-id="'+id+'"][data-type="'+type+'"]').length) {
								$(firstVisible).closest('tr').find('.sentences > div').hide();
								$(firstVisible).closest('tr').find('.sentence[data-id="'+id+'"][data-type="'+type+'"]').show();
							}
						};
					}
				}
			}else{
				if(inbound){
					var text = $(element).find('.wpil_sentence_with_anchor').text().trim().toLowerCase();
				}else{
					var text = $(element).find('.suggested-post-title').text().trim().toLowerCase();
				}
				var hasKeyword = false;
				var hasNegativeKeyword = false;
				var doingKeywordSearch = false;
				var doingNegativeMatch = false;

				for(var i in keywords){
					// check if the a negative char is used
					var negativeMatch = keywords[i].length > 1 && keywords[i].charAt(0) === '-';

					if(!hasKeyword && false === negativeMatch && -1 !== text.indexOf(keywords[i])){ // if the suggestion has the keyword somewhere
						hasKeyword = true;
					}else if(!hasNegativeKeyword && true === negativeMatch && -1 !== text.indexOf(keywords[i].slice(1))){ // if the suggestion has a keyword the user doesn't want
						hasNegativeKeyword = true;
					}

					if(negativeMatch){
						doingNegativeMatch = true;
					}else{
						doingKeywordSearch = true;
					}
				}

				if(	(!hasKeyword && !doingNegativeMatch) || 
					(hasNegativeKeyword) || 
					(doingKeywordSearch && doingNegativeMatch && !hasNegativeKeyword && !hasKeyword))
				{
					$(element).addClass('hidden-suggestion');
				}else{
					$(element).removeClass('hidden-suggestion');
				}
			}
		});
    }

	/** Related Posts Widget Controls */
	$(document).on('keyup', '#link-whisper-related-posts-search', searchForRelatedPosts);
	var relatedPostSearchWait;
	function searchForRelatedPosts(e){
		clearTimeout(relatedPostSearchWait);
		var search = $(e.target).val();
		if(search.length > 3){
			relatedPostSearchWait = setTimeout(function(){
				ajaxSearchRelatedPosts();
			}, 750);
		}else{
			$('#link-whisper-related-posts-search-results').empty();
			$('#link-whisper-related-posts-add-posts, #link-whisper-related-posts-search-results-title').css({'display': 'none'});
			$('#link-whisper-related-posts-search-container').removeClass('searching');
		}
	}

	/**
	 * Makes the request for posts and updates the related post metabox with the results
	 **/
	function ajaxSearchRelatedPosts(){
		var search = $('#link-whisper-related-posts-search').val(),
			selected = $('#link-whisper-related-posts-link-list .link-whisper-related-posts-item input:checked'),
			selectedIds = [],
			nonce = $('#link-whisper-related-posts-nonce').val();

		// hide the "add posts" button when we start searching
		$('#link-whisper-related-posts-add-posts, #link-whisper-related-posts-search-results-title').css({'display': 'none'});
		// show the loader
		$('#link-whisper-related-posts-search-container').addClass('searching');

		selected.each(function(index, element){
			selectedIds.push($(element).data('post-id'));
		});

		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'wpil_search_related_posts',
				search: search,
				selected_ids: selectedIds,
				nonce: nonce,
			},
			error: function (jqXHR, textStatus) {
				var wrapper = document.createElement('div');
				$(wrapper).append('<strong>' + textStatus + '</strong><br>');
				$(wrapper).append(jqXHR.responseText);
				wpil_swal({"title": "Error", "content": wrapper, "icon": "error"}).then(wpil_report_next_step());
			},
			success: function(response){
				// if there was an error
				if(response.error){
					wpil_swal(response.error.title, response.error.text, 'error');
					return;
				}
				
				if(response.success){
					$('#link-whisper-related-posts-search-results').empty().html(response.success.content);
					if(response.success.found > 0){
						$('#link-whisper-related-posts-add-posts, #link-whisper-related-posts-search-results-title').css({'display': 'block'});
					}else{
						$('#link-whisper-related-posts-add-posts, #link-whisper-related-posts-search-results-title').css({'display': 'none'});
					}
				}
			},
			complete: function(){
				// hide the loading animation when the search is ended
				$('#link-whisper-related-posts-search-container').removeClass('searching');
			}
		});
	}

	$(document).on('click', '#link-whisper-related-posts-add-posts', addSelectedRelatedPosts);
	function addSelectedRelatedPosts(){
		var related = $('#link-whisper-related-posts-search-results-container .link-whisper-related-posts-item input:checked').parents('li');
		if(related.length < 1){
			return;
		}

		$('#link-whisper-related-posts-link-list').append(related.detach());
		$('#link-whisper-related-posts-add-posts').addClass('disabled');
		activateSaveRelatedPostsButton();
	}

	$(document).on('change', '#link-whisper-related-posts-enable', toggleRelatedPostsActive);
	function toggleRelatedPostsActive(e){
		if($(e.target).is(':checked')){
			$('#link-whisper-related-posts-content-container').removeClass('wpil-section-disabled').removeClass('hidden');
			$('.wpil-related-posts-enable-helptext.unchecked').addClass('hidden');
			$('.wpil-related-posts-enable-helptext.checked').removeClass('hidden');
		}else{
			$('#link-whisper-related-posts-content-container').addClass('wpil-section-disabled');
			$('.wpil-related-posts-enable-helptext.checked').addClass('hidden');
			$('.wpil-related-posts-enable-helptext.unchecked').removeClass('hidden');
		}

		activateSaveRelatedPostsButton();
	}

	$(document).on('change', '#link-whisper-related-posts-search-results input:checked', toggleAddItemButton);
	function toggleAddItemButton(){
		var items = $('#link-whisper-related-posts-search-results input:checked');
		if(items.length > 0){
			$('#link-whisper-related-posts-add-posts').removeClass('disabled');
		}else{
			$('#link-whisper-related-posts-add-posts').addClass('disabled');
		}
	}

	$(document).on('change', '#link-whisper-related-posts-link-list input', activateSaveRelatedPostsButton);
	function activateSaveRelatedPostsButton(){
		$('#link-whisper-related-posts-save').removeClass('disabled');
	}

	function disableSaveRelatedPostsButton(){
		$('#link-whisper-related-posts-save').addClass('disabled');
	}

	$(document).on('click', '#link-whisper-related-posts-save', saveSelectedRelatedPosts);
	function saveSelectedRelatedPosts(){
		var	active = $('#link-whisper-related-posts-enable').is(':checked'),
			selected = $('#link-whisper-related-posts-link-list .link-whisper-related-posts-item input:checked'),
			selectedIds = [],
			postId = $('#link-whisper-related-posts-current-post').val(),
			nonce = $('#link-whisper-related-posts-nonce').val();

		selected.each(function(index, element){
			selectedIds.push($(element).data('post-id'));
		});

		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'wpil_save_related_posts',
				active: active,
				post_id: postId,
				selected_ids: selectedIds,
				nonce: nonce,
			},
			error: function (jqXHR, textStatus) {
				var wrapper = document.createElement('div');
				$(wrapper).append('<strong>' + textStatus + '</strong><br>');
				$(wrapper).append(jqXHR.responseText);
				wpil_swal({"title": "Error", "content": wrapper, "icon": "error"}).then(wpil_report_next_step());
			},
			success: function(response){
				// if there was an error
				if(response.error){
					wpil_swal(response.error.title, response.error.text, 'error');
					return;
				}

				// remove any unchecked posts from the Related Posts box
				$('#link-whisper-related-posts-link-list .link-whisper-related-posts-item input').not(':checked').parents('li.link-whisper-related-posts-item').remove();
				// deactivate the save button
				disableSaveRelatedPostsButton();
			}
		});
	}



	/** /Related Posts Widget Controls */


	function stristr(haystack, needle, bool)
	{
		// http://jsphp.co/jsphp/fn/view/stristr
		// +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
		// +   bugfxied by: Onno Marsman
		// *     example 1: stristr('Kevin van Zonneveld', 'Van');
		// *     returns 1: 'van Zonneveld'
		// *     example 2: stristr('Kevin van Zonneveld', 'VAN', true);
		// *     returns 2: 'Kevin '
		var pos = 0;

		haystack += '';
		pos = haystack.toLowerCase().indexOf((needle + '').toLowerCase());

		if (pos == -1) {
			return false;
		} else {
			if (bool) {
				return haystack.substr(0, pos);
			} else {
				return haystack.slice(pos);
			}
		}
	}

	function wpil_handle_errors(resp)
	{
		if (stristr(resp, "520") && stristr(resp, "unknown error") && stristr(resp, "Cloudflare")) {
			wpil_swal('Error', "It seems you are using CloudFlare and CloudFlare is hiding some error message. Please temporary disable CloudFlare, open reporting page again, look if it has any new errors and send it to us", 'error')
				.then(wpil_report_next_step);
			return true;
		}

		if (stristr(resp, "504") && stristr(resp, "gateway")) {
			wpil_swal('Error', "504 error: Gateway timeout - please ask your hosting support about this error", 'error')
				.then(wpil_report_next_step);
			return true;
		}

		return false;
	}

	function wpil_report_next_step()
	{
		location.reload();
	}

    /**
     * Makes the call to reset the report data when the user clicks on the "Reset Data" button.
     **/
    function resetReportData(e){
        e.preventDefault();
        var form = $(this);
        var nonce = form.find('[name="reset_data_nonce"]').val();
       
        if(!nonce || form.attr('disabled')){
            return;
        }
        
        // disable the reset button
        form.attr('disabled', true);
        // add a color change to the button indicate it's disabled
        form.find('button.button-primary').addClass('wpil_button_is_active');
        processReportReset(nonce, 0, true);
    }

    /**
     * Makes the call to reset the report data when the user clicks on the "Reset Data" button.
     **/
    function resumeReportData(e){
        e.preventDefault();

        var form = $(this).parents('form');
        var nonce = form.find('[name="reset_data_nonce"]').val();

        if(!nonce || form.attr('disabled')){
            return;
        }

        // disable the reset button
        form.attr('disabled', true);
        // add a color change to the button indicate it's disabled
        $(this).addClass('wpil_button_is_active');
        // and hide the "New Link Scan" button
        form.find('button.button-primary').css({'opacity': '0.3'});
        processReportData(nonce, 0, 0, 0, 0, false, false, 0, true);
    }

    var timeList = [];    
    function processReportReset(nonce = null, loopCount = 0, clearData = false){
        if(!nonce){
            return;
        }

        jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'reset_report_data',
                nonce: nonce,
                loop_count: loopCount,
                clear_data: clearData,
			},
            error: function (jqXHR, textStatus) {
				var resp = jqXHR.responseText;

				if (wpil_handle_errors(resp)) {
					wpil_report_next_step();
					return;
				}

				var wrapper = document.createElement('div');
				$(wrapper).append('<strong>' + textStatus + '</strong><br>');
				$(wrapper).append(jqXHR.responseText);
				wpil_swal({"title": "Error", "content": wrapper, "icon": "error"}).then(wpil_report_next_step());
			},
			success: function(response){
                // if there was an error
                if(response.error){
                    wpil_swal(response.error.title, response.error.text, 'error');
                    return;
                }
                
                // if we've been around a couple times without processing links, there must have been an error
                if(!response.links_to_process_count && response.loop_count > 5){
                    wpil_swal('Data Reset Error', 'Link Whisper has tried a number of times to reset the report data, and it hasn\'t been able to complete the action.', 'error');
                    return;
                }

                // if the data has been successfully reset
                if(response.data_setup_complete){
                    // set the loading screen now that the data setup is complete
                    if(response.loading_screen){
                        $('#wpbody-content').html(response.loading_screen);
                    }
                    // set the time
                    timeList.push(response.time);
                    // and call the data processing function to handle the data
                    processReportData(response.nonce, 0, 0, 0);
                }else{
                    // if we're not done processing links, go around again
                    processReportReset(response.nonce, (response.loop_count + 1), true);
                }
			}
		});
    }

    // listen for clicks on the "Reset Data" button
    $('#wpil_report_reset_data_form').on('submit', resetReportData);

    // also listen for when the user wants to resume an existing scan
    $('#wpil_report_reset_data_form .wpil-resume-link-scan').on('click', resumeReportData);

	/**
	 * Keeps track of the loop's progress in a global context so the scan is less susceptible to minor errors like timeouts
	 **/
	var globalScan = {
		'nonce': '', 						// nonce
		'loop': 0, 							// loop count
		'link_posts_to_process_count': 0, 	// posts/cats to process count
		'processed': 0, 					// how many have been processed so far
		'link_posts_to_process_diff': 0,	// the difference between the number of posts to process and the ones that have been processed
		'meta_filled': false, 				// if the meta processing is complete
		'links_filled': false,				// if the link processing is complete
		'error_count': 0,					// the number of times the scan has errored
		'loops_unchanged': 0				// the number of loops we've gone over without a change in the total number of processed posts
	};

    /**
     * Process runner that handles the report data generation process.
     * Loops around until all the site's links are inserted into the LW link table
     **/
    function processReportData(	nonce = null, 
								loopCount = 0, 
								linkPostsToProcessCount = 0, 
								linkPostsProcessed = 0, 
								linkPostProcessDiff = 0,
								metaFilled = false, 
								linksFilled = false,
								loopsUnchanged = 0,
								resumeScan = false)
	{
        if(!nonce){
            return;
        }

        // initialize the stage clock. // The clock is useful for debugging
        if(loopCount < 1){
            if(timeList.length > 0){
                var lastTime = timeList.pop();
                timeList = [lastTime];
            }else{
                timeList = [];
            }
        }

        jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'process_report_data',
                nonce: nonce,
                loop_count: loopCount,
                link_posts_to_process_count: linkPostsToProcessCount,
                link_posts_processed: linkPostsProcessed,
				link_posts_to_process_diff: linkPostProcessDiff,
                meta_filled: metaFilled,
                links_filled: linksFilled,
				loops_unchanged: loopsUnchanged,
				resume_scan: (resumeScan) ? 1: 0 
			},
            error: function (jqXHR, textStatus, errorThrown) {
				console.log('There has been an error during the scan!');
				console.log(globalScan);
				globalScan.error_count += 1;

				// if the scan has errored less than 5 times, try it again
				if(globalScan.error_count < 5){
					processReportData(
						globalScan.nonce,
						globalScan.loop,
						globalScan.link_posts_to_process_count,
						globalScan.processed,
						globalScan.link_posts_to_process_diff,
						globalScan.meta_filled,
						globalScan.links_filled,
						globalScan.loops_unchanged
					);
				}else{
					var resp = jqXHR.responseText;
					if (wpil_handle_errors(resp)) {
						wpil_report_next_step();
						return;
					}

					var wrapper = document.createElement('div');
					$(wrapper).append('<strong>' + textStatus + '</strong><br>');
					$(wrapper).append(jqXHR.responseText);
					wpil_swal({"title": "Error", "content": wrapper, "icon": "error"}).then(wpil_report_next_step());
				}
			},
			success: function(response){
                console.log(response);

                // if there was an error
                if(response.error){
                    // output the error message
                    wpil_swal(response.error.title, response.error.text, 'error');
                    // and exit
                    return;
                }

                // log the time
                timeList.push(response.time);

				// update the global stats
				globalScan.nonce = response.nonce;
				globalScan.loop = 0;
				globalScan.link_posts_to_process_count = response.link_posts_to_process_count;
				globalScan.processed = response.link_posts_processed;
				globalScan.link_posts_to_process_diff = response.link_posts_to_process_diff;
				globalScan.meta_filled = response.meta_filled;
				globalScan.links_filled = response.links_filled;
				globalScan.error_count = 0;
				globalScan.loops_unchanged = response.loops_unchanged;

                // if the meta has been successfully processed
				if(response.processing_complete){
					// if the processing is complete
					// console.log the time if available
					if(timeList > 1){
						console.log('The post processing took: ' + (timeList[(timeList.length - 1)] - timeList[0]) + ' seconds.');
					}

					// update the loading bar one more time
					animateTheReportLoadingBar(response);

					// if there are linked sites, show the external site processing loading page
					if(response.loading_screen){
						$('#wpbody-content').html(response.loading_screen);
					}

					// find out if there's external sites we need to get data from
					var externalSites = $('.wpil_report_need_prepare.processing');

					// if there are no linked sites or the site linking is disabled
					if(externalSites.length < 1 || (0 == wpil_ajax.site_linking_enabled)){
						// show the user the success message!
						wpil_swal('Success!', 'The Link Scan is complete!', 'success').then(wpil_report_next_step);
					}else{
						// call the site updator if there are sites to update
						processExternalSites();
					}

					// and exit since in either case we're done here
					return;
				} else if(response.link_processing_complete){
					// if we've finished loading links into the link table
					// show the post processing loading page
					if(response.loading_screen){
						$('#wpbody-content').html(response.loading_screen);
					}

					// console.log the time if available
					if(timeList > 1){
						console.log('The link processing took: ' + (timeList[(timeList.length - 1)] - timeList[0]) + ' seconds.');
					}

					// re-call the function for the final round of processing
					processReportData(  response.nonce,
						0,
						response.link_posts_to_process_count,
						0,
						response.link_posts_to_process_diff,
						response.meta_filled,
						response.links_filled,
						response.loops_unchanged);

				} else if(response.meta_filled){
					// show the link processing loading screen
					if(response.loading_screen){
						$('#wpbody-content').html(response.loading_screen);
					}
					// console.log the time if available
					if(timeList > 1){
						console.log('The meta processing took: ' + (timeList[(timeList.length - 1)] - timeList[0]) + ' seconds.');
					}

					// update the loading bar
					animateTheReportLoadingBar(response);

					// and recall the function to begin the link processing (loading the site's links into the link table)
					processReportData(  response.nonce,                         // nonce
						0,                                      // loop count
						response.link_posts_to_process_count,   // posts/cats to process count
						0,                                      // how many have been processed so far
						response.link_posts_to_process_diff,	// what's the difference between the posts processed and the ones coming up
						response.meta_filled,                   // if the meta processing is complete
						response.links_filled,					// if the link processing is complete
						response.loops_unchanged);				// how many loops have we gone through without processing posts
				} else{
					// update the loop count
					globalScan.loop = (response.loop_count + 1);
                    // if we're not done processing, go around again
                    processReportData(  response.nonce, 
                                        (response.loop_count + 1), 
                                        response.link_posts_to_process_count, 
                                        response.link_posts_processed,
										response.link_posts_to_process_diff,
                                        response.meta_filled,
                                        response.links_filled,
										response.loops_unchanged);
                    
                    // if the meta has been processed
                    if(response.meta_filled){
                        // update the loading bar
                        animateTheReportLoadingBar(response);
                    }
                }
			}
		});
    }

	/**
	 * Processes the external sites by ajax calls
	 **/
	function processExternalSites(){
		var externalSites = $('.wpil_report_need_prepare.processing').first();

		if(externalSites.length < 1){
			// show the user the success message!
			wpil_swal('Success!', 'The Link Scan is complete!', 'success').then(wpil_report_next_step);
			return;
		}

		var site = $(externalSites),
			url = site.data('linked-url'), 
			page = site.data('page'), 
			saved = site.data('saved'), 
			total = site.data('total'), 
			nonce = site.data('nonce');


		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			data: {
				action: 'wpil_refresh_site_data',
				process_url: url,
				encoded_process_url: btoa(url),
				nonce: nonce,
				page: page,
				saved: saved,
				total: total
			},
			success: function(response){
				console.log(response);
				// if there was an error
				if(response.error){
					// remove the processing class
					site.removeClass('processing');
					// make the background of the loading bar red to indicate an error
					site.find('.progress_panel').css({'background': '#c7584d'});
					site.find('.progress_count').css({'background': '#fd2d2d'});
					// and add an error text
					site.find('.wpil-loading-status').text('Processing Error');

					// and go on to the next site
					processExternalSites();

					return;
				}else if(response.success){
					// if the site is processed, update the display

					// remove the processing class
					site.removeClass('processing');
					// and go on to the next site
					processExternalSites();
					return;
				}else if(response){
					// if there's still posts to process in the current site

					// update the page relavent data
					site.data('page', response.page), 
					site.data('saved', response.saved), 
					site.data('total', response.total), 

					// update the display
					animateLinkedSiteLoadingBar(site, response);

					// and go around again
					processExternalSites();
					return;
				}
			}
		});
	}


    /**
     * Updates the loading bar length and the displayed completion status.
     * 
     * A possible improvement might be to progressively update the loading bar so its more interesting.
     * As it is now, the bar jumps every 60s, so it might be a bit dull and the user might wonder if it's working.
     **/
    function animateTheReportLoadingBar(response){
        // get the loading display
        var loadingDisplay = $('#wpbody-content .wpil-loading-screen');
        // create some variable to update the display with
        var percentCompleted = Math.floor((response.link_posts_processed/response.link_posts_to_process_count) * 100);
        var displayedStatus = percentCompleted + '%' + ((response.links_filled) ? (', ' + response.link_posts_processed + '/' + response.link_posts_to_process_count) : '') + ' ' + wpil_ajax.completed;
//        var oldPercent = parseInt(loadingDisplay.find('.progress_count').css('width'));

        // update the display with the new info
        loadingDisplay.find('.wpil-loading-status').text(displayedStatus);
        loadingDisplay.find('.progress_count').css({'width': percentCompleted + '%'});
    }

    /**
     * Runs Tippy and generates the standard tooltips for a page
     **/
    function runStandardTippy(){
        var toTip = $('.wpil-tippy-tooltipped');
        if(toTip.length < 1){
            return;
        }

        toTip.each(function(index, element){
            var el = $(element);
            if(el.data('wpilTooltipContent')){
                var args = {
                    content: el.data('wpilTooltipContent'),
                    onShow(instance){
                        var target = $(instance.reference);
                        if(target.attr('data-wpil-tooltip-theme') === 'delete-post'){
                            target.parents('span.delete').css({'display': 'inline-block', 'margin-right': '4px'});
                        }
                    }
                };

                if(el.data('wpilTooltipInteractive')){
                    args['interactive'] = true;
                }

                if(el.data('wpilTooltipAllowhtml')){
                    args['allowHTML'] = true;
                }

                if(el.data('wpilTooltipMaxwidth')){
                    args['maxWidth'] = parseInt(el.data('wpilTooltipMaxwidth'));
                }

                if(el.data('wpilTooltipTheme')){
                    args['theme'] = el.data('wpilTooltipTheme');
                }

                tippy(element, args);
            }
        });
    }

    /**
     * Updates the loading bars for linked sites during the link scan.
     * Increases the length of the loading bars and the text content contained in the bar as the data is downloaded.
	 * 
     **/
    function animateLinkedSiteLoadingBar(site, response){
        // create some variables to update the display with
        var percentCompleted = Math.floor((response.saved/response.total) * 100);
        var displayedStatus = percentCompleted + '%' + ((response.saved) ? (', ' + response.saved + '/' + response.total) : '');

        // update the display with the new info
        site.find('.wpil-loading-status').text(displayedStatus);
        site.find('.progress_count').css({'width': percentCompleted + '%'});
    }

	$(document).on('click', '.wpil-collapsible', function (e) {
		if ($(this).hasClass('wpil-no-action') ||
            $(e.target).hasClass('wpil_word') || 
            $(e.target).hasClass('add-internal-links') ||
            $(e.target).hasClass('add-outbound-internal-links') ||
            $(e.target).hasClass('add_custom_link_button') ||
            $(e.target).hasClass('add_custom_link') || 
            $(e.target).parents('.add_custom_link').length || 
            $(this).find('.custom-link-wrapper').length > 0 || 
            $(this).find('.wp-editor-wrap').length > 0 ||
			$(e.target).hasClass('wpil-reload-sentence-with-anchor') ||
			$(e.target).hasClass('button-primary') ||
			$(e.target).hasClass('button-secondary') ||
			$(e.target).parent().hasClass('wpil_edit_sentence')
        ) 
        {
			return;
		}

		// exit if the user clicked the "Add" button in the link report
		if($(e.srcElement).hasClass('add-internal-links') || $(e.srcElement).hasClass('add-outbound-internal-links')){
			return;
		}
		e.preventDefault();

		var $el = $(this);
		var $content = $el.closest('.wpil-collapsible-wrapper').find('.wpil-content');
		var cl_active = 'wpil-active';
		var wrapper = $el.parents('.wpil-collapsible-wrapper');

		if ($el.hasClass(cl_active)) {
			$el.removeClass(cl_active);
			wrapper.removeClass(cl_active);
			$content.hide();
		} else {
			// if this is the link report or target keyword report or autolink table or the domains table
			if($('.tbl-link-reports').length || $('#wpil_target_keyword_table').length || $('#wpil_keywords_table').length || $('#report_domains').length){
				// hide any open dropdowns in the same row
				$(this).closest('tr').find('td .wpil-collapsible').removeClass('wpil-active');
				$(this).closest('tr').find('td .wpil-collapsible-wrapper').removeClass('wpil-active');
				$(this).closest('tr').find('td .wpil-collapsible-wrapper').find('.wpil-content').hide();
			}
			$el.addClass(cl_active);
			wrapper.addClass(cl_active);
			$content.show();
		}
	});

	$(document).on('click', '#select_all', function () {
		if ($(this).prop('checked')) {
			if ($('.best_keywords').hasClass('outbound')) {
				$(this).closest('table').find('.sentence:visible input[type="checkbox"].chk-keywords:visible').prop('checked', true);
			} else {
				$(this).closest('table').find('input[type="checkbox"].chk-keywords:visible').prop('checked', true);
			}

			$('.suggestion-select-all').prop('checked', true);
		} else {
			$(this).closest('table').find('input[type="checkbox"].chk-keywords').prop('checked', false);
			$('.suggestion-select-all').prop('checked', false);
		}
	});

	$(document).on('click', '.best_keywords.outbound .wpil-collapsible-wrapper input[type="radio"]', function () {
		var id = $(this).data('id');
		var data = $(this).closest('li').find('.data').html();
		var type = $(this).data('type');
		var suggestion = $(this).data('suggestion');
		var origin = $(this).data('post-origin');
		var siteUrl = $(this).data('site-url');

		var additionalData = [
			'data-wpil-post-published-date="' + $(this).data('wpil-post-published-date') + '"',
			'data-wpil-suggestion-score="' + $(this).data('wpil-suggestion-score') + '"',
			'data-wpil-inbound-internal-links="' + $(this).data('wpil-inbound-internal-links') + '"',
			'data-wpil-outbound-internal-links="' + $(this).data('wpil-outbound-internal-links') + '"',
			'data-wpil-outbound-external-links="' + $(this).data('wpil-outbound-external-links') + '"',
		];

		$(this).closest('ul').find('input').prop('checked', false);

		$(this).prop('checked', true);
		$(this).closest('.wpil-collapsible-wrapper').find('.wpil-collapsible-static').html('<div data-id="' + id + '" data-type="' + type + '" data-post-origin="' + origin + '" data-site-url="' + siteUrl + '" ' + additionalData.join(' ') + '>' + data + '<span class="add_custom_link_button link-form-button"> | <a href="javascript:void(0)">Custom Link</a></span><span class="wpil_add_link_to_ignore link-form-button"> | <a href="javascript:void(0)">Ignore Link</a></span></div>');
		$(this).closest('tr').find('input[type="checkbox"]').prop('checked', false);
		$(this).closest('tr').find('input[type="checkbox"]').val(suggestion + ',' + id);

		if (!$(this).closest('tr').find('input[data-wpil-custom-anchor]').length && $(this).closest('tr').find('.sentence[data-id="'+id+'"][data-type="'+type+'"]').length) {
			$(this).closest('tr').find('.sentences > div').hide();
			$(this).closest('tr').find('.sentence[data-id="'+id+'"][data-type="'+type+'"]').show();
		}
	});

	$(document).on('click', '.best_keywords.inbound .wpil-collapsible-wrapper input[type="radio"]', function () {
		var id = $(this).data('id');
		var data = $(this).closest('li').find('.data').html();
		$(this).closest('ul').find('input').prop('checked', false);
		$(this).prop('checked', true);
		$(this).closest('.wpil-collapsible-wrapper').find('.sentence').html(data + '<span class="wpil_edit_sentence">| <a href="javascript:void(0)">Edit Sentence</a></span>');
		$(this).closest('tr').find('input[type="checkbox"]').prop('checked', false);
		$(this).closest('tr').find('.raw_html').hide();
		$(this).closest('tr').find('.raw_html[data-id="' + id + '"]').show();
	});

	$(document).on('click', '.best_keywords input[type="checkbox"]', function () {
		if ($(this).prop('checked')) {
			if ($('.best_keywords').hasClass('outbound')) {
				var checked = $('.best_keywords .sentence:visible input[type="checkbox"].chk-keywords:checked');
			} else {
				var checked = $('.best_keywords input[type="checkbox"].chk-keywords:checked');
			}
			if (checked.length > 50) {
				checked = checked.slice(50);
				console.log(checked);
				checked.each(function(){
					$(this).prop('checked', false);
				});
				wpil_swal('Warning', 'You can choose only 50 links', 'warning');
			}
		}

	});

	/**
	 * Asks the user if they want to consign a post to the trash when they click the "Trash Post" button
	 **/
	$(document).on('click', '.wpil-trash-post-link', function (e) {
		e.preventDefault();

		var rowItem = $(this),
			trashLink = rowItem.attr('href');

		if(trashLink.length < 1){
			return;
		}

        if ((wpil_ajax.dismissed_popups && wpil_ajax.dismissed_popups['link_report_trash_post'] !== 1)) {
            var popupWrapper = document.createElement('div');
            $(popupWrapper).append('Please confirm that you want to put this page in the trash. This will remove the page from your site and put it in the trash, not just remove it from the report. <br><br> <input type="checkbox" id="wpil-perma-dismiss-popup" data-wpil-popup-name="link_report_trash_post"><span style="font-size: 12px;">(Don\'t show this again)</span>');
            wpil_swal({
                'title': 'Notice:', 
                content: popupWrapper, 
                'icon': 'info',
                buttons: {
                    cancel: true,
                    confirm: true,
                }
            }).then((trash) => {
                if (trash) {
                    rowItem.closest('tr').css({'opacity': 0.4});
                    $.post(trashLink, function(){
                        rowItem.closest('tr').fadeOut(300);
                    });
                  }

                var checkbox = $('#wpil-perma-dismiss-popup');
                if(checkbox.is(':checked') && wpil_ajax.dismiss_popup_nonce){
                    $.ajax({
                        type: 'POST',
                        url: ajaxurl,
                        data: {
                            action: 'wpil_dismiss_popup_notice',
                            popup_name: checkbox.data('wpil-popup-name'),
                            nonce: wpil_ajax.dismiss_popup_nonce,
                        },
                        complete: function (data) {
                            console.log('ignoring complete!');
                            wpil_ajax.dismissed_popups['link_report_trash_post'] = 1;
                        }
                    })
                }
            });
        }else{
            rowItem.closest('tr').css({'opacity': 0.4});
            $.post(trashLink, function(){
                rowItem.closest('tr').fadeOut(300);
            });
        }
	});

	//ignore link in error reports
	$(document).on('click', '.column-url .row-actions .wpil_ignore_link', function () {
		var el = $(this);
		var parent = el.parents('.column-url');
		var data = {
			url: el.data('url'),
			anchor: el.data('anchor'),
			post_id: el.data('post_id'),
			post_type: el.data('post_type'),
			link_id: typeof el.data('link_id') !== 'undefined' ? el.data('link_id') : ''
		};

		if (el.hasClass('wpil_ignore_link')) {
			var rowParent = el.closest('tr');
		} else {
			var rowParent = el.closest('li');
		}

		parent.html('<div style="margin-left: calc(50% - 16px);" class="la-ball-clip-rotate la-md"><div></div></div>');

		$.post('admin.php?page=link_whisper&type=ignore_link', data, function(){
			rowParent.fadeOut(300);
		});
	});

	//stop ignoring link in error reports
	$(document).on('click', '.column-url .row-actions .wpil_stop_ignore_link', function () {
		var el = $(this);
		var parent = el.parents('.column-url');
		var data = {
			url: el.data('url'),
			anchor: el.data('anchor'),
			post_id: el.data('post_id'),
			post_type: el.data('post_type'),
			link_id: typeof el.data('link_id') !== 'undefined' ? el.data('link_id') : ''
		};

		if (el.hasClass('wpil_stop_ignore_link')) {
			var rowParent = el.closest('tr');
		} else {
			var rowParent = el.closest('li');
		}

		parent.html('<div style="margin-left: calc(50% - 16px);" class="la-ball-clip-rotate la-md"><div></div></div>');

		$.post('admin.php?page=link_whisper&type=stop_ignore_link', data, function(){
			rowParent.fadeOut(300);
		});
	});

	//delete link from post content
	$(document).on('click', '.wpil_link_delete', function () {
		if (confirm("Are you sure you want to delete this link? This will delete the link from the page that it\'s on.")) {
			var el = $(this);
			var data = {
				url: el.data('url'),
				anchor: el.data('anchor'),
				post_id: el.data('post_id'),
				post_type: el.data('post_type'),
				link_id: typeof el.data('link_id') !== 'undefined' ? el.data('link_id') : ''
			};

			$.post('admin.php?page=link_whisper&type=delete_link', data, function(){
				if (el.hasClass('broken_link')) {
					el.closest('tr').fadeOut(300);
				} else {
					el.closest('li').fadeOut(300);
				}
			});
		}
	});

	$(document).on('click', '.wpil_link_select', toggleSelectedDeleteButton);
	function toggleSelectedDeleteButton(){
		var checkedBoxes = $(this).parents('.wpil-collapsible-wrapper').find('.wpil-content .wpil_link_select:checked');
		var deleteButton = $(this).parents('.wpil-collapsible-wrapper').find('.update-post-links .wpil-delete-selected-links');
		var selectAll = $(this).parents('.wpil-collapsible-wrapper').find('.update-post-links .wpil-select-all-dropdown-links');
		if(checkedBoxes.length > 0){
			deleteButton.removeClass('disabled');
		}else{
			deleteButton.removeClass('disabled').addClass('disabled');
			selectAll.prop('checked', false);
		}
	}

	$(document).on('click', '.wpil-select-all-dropdown-links', toggleLinkSelection);
	function toggleLinkSelection(){
		var checkBoxes = $(this).parents('.wpil-collapsible-wrapper').find('.wpil-content .wpil_link_select');
		var deleteButton = $(this).parents('.update-post-links').find('.wpil-delete-selected-links');
		if($(this).is(':checked')){
			checkBoxes.prop('checked', true);
			deleteButton.removeClass('disabled');
		}else{
			checkBoxes.prop('checked', false);
			deleteButton.addClass('disabled');
		}
	}

	//delete link from post content
	$(document).on('click', '.wpil-delete-selected-links', triggerDeleteSelectedLinks);
	function triggerDeleteSelectedLinks(e){
		e.preventDefault();

		var wrapper = $(this).parents('.wpil-collapsible-wrapper');
		var checkedBoxes = wrapper.find('.wpil-content .wpil_link_select:checked');
		var button = $(this);

		if(checkedBoxes.length < 1){
			return;
		}

		if (confirm("Are you sure you want to delete the selected links? This will delete the links from the page(s) that they\'re on.")) {
			deleteSelectedLinks(checkedBoxes, wrapper, button);
		}
	}


	function deleteSelectedLinks(checkedBoxes, wrapper, button){
		if(checkedBoxes.length < 1 || wrapper.length < 1){
			return;
		}

		var links = [];
		checkedBoxes.each(function(index, element){
			var el = $(element);
			if(!el.parent().hasClass('deleting-link')){
				el.parent().addClass('deleting-link');
			}
			links.push({'post_id': el.data('post_id'), 'post_type': el.data('post_type'), 'anchor': el.data('anchor'), 'url': el.data('url')});
		});

		var data = {
			action: 'wpil_delete_selected_links',
			links: links.slice(0, 80),
			nonce: button.data('nonce')
		};

		$.ajax({
			type: 'POST',
			url: ajaxurl,
			dataType: 'json',
			data: data,
			error: function (jqXHR, textStatus, errorThrown) {
				var wrapper = document.createElement('div');
				$(wrapper).append('<strong>' + textStatus + '</strong><br>');
				$(wrapper).append(jqXHR.responseText);
				wpil_swal({"title": "Error", "content": wrapper, "icon": "error"});
			},
			success: function(response){
				console.log(response);
				if(response.error){
					wpil_swal(response.error.title, response.error.text, 'error');
					wrapper.find('.deleting-link').removeClass('deleting-link');
					return;
				}

				if(response.success){
					wpil_swal(response.success.title, response.success.text, 'success');
					wrapper.find('.deleting-link').removeClass('deleting-link');
					flushObjectCache();
					return;
				}

				if(response.progress){
					console.log(response.progress);
					for(var i in response.progress){
						var dat = response.progress[i];
						for(var j in dat){
							var search = '[data-url="' + dat[j].url + '"]';
							search += '[data-post_id="' + dat[j].post_id + '"]';
							search += '[data-post_type="' + dat[j].post_type + '"]';
							search += (dat[j].anchor > 0) ? '[data-anchor="' + dat[j].anchor + '"]': '';
							
							var box = checkedBoxes.filter(search);
							if(box){
								box.parent().fadeOut(300, function(){ $(this).remove(); });
							}
						}
					}

					// recount the number of links in the dropdown!
					setTimeout(function(){
						var items = wrapper.find('.wpil-content .wpil_link_select'); // Todo: update the "posts" dropdown in the Domains report so that it will reflect the link deletions
						wrapper.find('.wpil_ul').text(items.length);
						// if there are no items left, hide the delete bar
						if(items.length == 0){
							wrapper.find('.update-post-links').fadeOut(300, function(){ $(this).remove(); });

							// if this is the Domains page, hide the parent row too
							if($('#report_domains').length > 0){
								wrapper.parents('tr').fadeOut(300, function(){ $(this).remove(); });
							}
						}

						// also, check if there's visible checked boxes
						checkedBoxes = wrapper.find('.wpil-content .wpil_link_select:checked');

						// if there are
						if(checkedBoxes.length > 0){
							// go around again
							deleteSelectedLinks(checkedBoxes, wrapper, button);
						}else{
							// if there are no links, flush the cache!
							flushObjectCache();
						}
					}, 500);

				}
				
			}
		});

	}

	// ignore an orphaned post from the link report
	$(document).on('click', '.wpil-ignore-orphaned-post', function (e) {
		e.preventDefault();
		var el = $(this);

		if (confirm("Are you sure you want to ignore this post on the Orphaned Posts view? It will still be visible on the Internal Links Report and you can re-add the post to the Orphaned Posts from the settings.")) {
			var el = $(this);
			var data = {
				action: 'wpil_ignore_orphaned_post',
				post_id: el.data('post-id'),
				type: el.data('type'),
				nonce: el.data('nonce')
			};
			jQuery.ajax({
				type: 'POST',
				url: ajaxurl,
				dataType: 'json',
				data: data,
				error: function (jqXHR, textStatus, errorThrown) {
					var wrapper = document.createElement('div');
					$(wrapper).append('<strong>' + textStatus + '</strong><br>');
					$(wrapper).append(jqXHR.responseText);
					wpil_swal({"title": "Error", "content": wrapper, "icon": "error"});
				},
				success: function(response){
					if(response.success){
						if (el.hasClass('wpil-ignore-orphaned-post')) {
							el.closest('tr').fadeOut(300);
						} else {
							el.closest('li').fadeOut(300);
						}
					}else if(response.error){
						wpil_swal(response.error.title, response.error.text, 'error');
					}
				}
			});
		}
	});

    $(document).ready(function(){
        runStandardTippy();
        var saving = false;

		if (typeof wp.data != 'undefined' && typeof wp.data.select('core/editor') != 'undefined') {
			wp.data.subscribe(function () {
				if (document.body.classList.contains( 'block-editor-page' ) && !saving && reloadGutenberg) {
					saving = true;
					setTimeout(function(){
						$.post( ajaxurl, {action: 'wpil_editor_reload', post_id: $('#post_ID').val()}, function(data) {
							if (data == 'reload') {
								location.reload();
							}

							saving = false;
							reloadGutenberg = false;
						});
					}, 3000);
				}
			});
		}

		if ($('#post_ID').length) {
			$.post( ajaxurl, {action: 'wpil_is_outbound_links_added', id: $('#post_ID').val(), type: 'post'}, function(data) {
				if (data == 'success' && (wpil_ajax.dismissed_popups && wpil_ajax.dismissed_popups['suggestions'] !== 1)) {
					var wrapper = document.createElement('div');
					$(wrapper).append('Links have been added successfully! <br><br> <input type="checkbox" id="wpil-perma-dismiss-popup" data-wpil-popup-name="suggestions"><span style="font-size: 12px;">(Don\'t show this again)</span>');
					wpil_swal({'title': 'Success', content: wrapper, 'icon': 'success'}).then(() => {
						var checkbox = $('#wpil-perma-dismiss-popup');
						var nonce = (checkbox.data('wpil-popup-name') === 'suggestion') ? $('div[data-wpil-ajax-container=""]').data('wpil-suggestion-nonce'): '';
						if(checkbox.is(':checked') && nonce){
							$.ajax({
								type: 'POST',
								url: ajaxurl,
								data: {
									action: 'wpil_dismiss_popup_notice',
									popup_name: checkbox.data('wpil-popup-name'),
									nonce: nonce,
								},
								complete: function (data) {
									console.log('ignoring complete!');
								}
							})
						}
					});
				}
			});
		}

		if ($('#inbound_suggestions_page').length) {
			var id  = $('#inbound_suggestions_page').data('id');
			var type  = $('#inbound_suggestions_page').data('type');

			$.post( ajaxurl, {action: 'wpil_is_inbound_links_added', id: id, type: type}, function(data) {
				if (data == 'success' && (!wpil_ajax.dismissed_popups || (wpil_ajax.dismissed_popups && wpil_ajax.dismissed_popups['suggestions'] === undefined || wpil_ajax.dismissed_popups['suggestions'] !== 1))) {
					var popupWrapper = document.createElement('div');
					$(popupWrapper).append('Links have been added successfully! <br><br> <input type="checkbox" id="wpil-perma-dismiss-popup" data-wpil-popup-name="suggestions"><span style="font-size: 12px;">(Don\'t show this again)</span>');
					wpil_swal({'title': 'Success', content: popupWrapper, 'icon': 'success'}).then(() => {
						var checkbox = $('#wpil-perma-dismiss-popup');
						var nonce = wpil_ajax.dismiss_popup_nonce;
						if(checkbox.is(':checked') && nonce){
							$.ajax({
								type: 'POST',
								url: ajaxurl,
								data: {
									action: 'wpil_dismiss_popup_notice',
									popup_name: checkbox.data('wpil-popup-name'),
									nonce: nonce,
								},
								complete: function (data) {
									console.log('ignoring complete!');
								}
							})
						}
					});
				}
			});
		}

		//show links chart in dashboard
		if ($('#wpil_links_chart').length) {
			var internal = $('input[name="internal_links_count"]').val();
			var external = $('input[name="total_links_count"]').val() - $('input[name="internal_links_count"]').val();

			$('#wpil_links_chart').jqChart({
				title: { text: '' },
				legend: {
					title: '',
					font: '15px sans-serif',
					location: 'top',
					border: {visible: false}
				},
				border: { visible: false },
				animation: { duration: 1 },
				shadows: {
					enabled: true
				},
				series: [
					{
						type: 'pie',
						fillStyles: ['#33c7fd', '#7646b0'],
						labels: {
							stringFormat: '%d',
							valueType: 'dataValue',
							font: 'bold 15px sans-serif',
							fillStyle: 'white',
							fontWeight: 'bold'
						},
						explodedRadius: 8,
						explodedSlices: [1],
						data: [['Internal', internal], ['External', external]],
						labelsPosition: 'inside', // inside, outside
						labelsAlign: 'circle', // circle, column
						labelsExtend: 20,
						leaderLineWidth: 1,
						leaderLineStrokeStyle: 'black'
					}
				]
			});
		}

		//show links click chart in detailed click report
		if ($('#link-click-detail-chart').length) {
			
			var clickData	= JSON.parse($('input#link-click-detail-data').val());
			var range		= JSON.parse($('input#link-click-detail-data-range').val());
			var clickCount = 0;
			var dateRange = getAllDays(range.start, range.end);
			var displayData = [];

			if(clickData !== ''){
				for(var i in dateRange){
					var date = dateRange[i];
					if(clickData[date] !== undefined){
						displayData.push([date, clickData[date]]);
						clickCount += clickData[date];
					}else{
						displayData.push([date, 0]);
					}
				}
			}

			$('#link-click-detail-chart').jqChart({
				title: { text: 'Clicks per day' },
				legend: {
					title: '',
					font: '15px sans-serif',
					location: 'top',
					border: {visible: false},
					visible: false
				},
				border: { visible: false },
				animation: { duration: 1 },
				shadows: {
					enabled: true
				},
				axes: [
					{
						type: 'linear',
						location: 'left',
						minimum: 0,
					},
					{
						location: 'bottom',
						labels: {
							resolveOverlappingMode: 'hide'
						},
						majorTickMarks: {
						},
						minorTickMarks: {
						}
					},
					{
						location: 'bottom',
						title: {
							text: 'Total Clicks for Selected Range: ' + clickCount,
							font: '16px sans-serif',
							fillStyle: '#282828',
						},
						strokeStyle: '#ffffff	',
						labels: {
							resolveOverlappingMode: 'hide'
						},
						majorTickMarks: {
						},
						minorTickMarks: {
						}
					},
				],
				series: [
					{
						type: 'area',
						title: '',
						shadows: {
							enabled: true
						},
//						fillStyles: ['#33c7fd', '#7646b0'],
						lineWidth : 2,
						fillStyle: '#2dc0fd',
						strokeStyle:'#6b3da7',
						markers: { 
							size: 8, 
							type: 'circle',
							strokeStyle: 'black', 
							fillStyle : '#6b3da7', 
							lineWidth: 1 
						},
						labels: {
							visible: false,
							stringFormat: '%d',
							valueType: 'dataValue',
							font: 'bold 15px sans-serif',
							fillStyle: 'transparent',
							fontWeight: 'bold'
						},
						data: displayData,
						leaderLineWidth: 1,
						leaderLineStrokeStyle: 'black'
					}
				]
			});
		}

		function getAllDays(start, end) {
			var s = new Date(start);
			var e = new Date(end);
			var a = [];
		
			while(s < e) {
				a.push(moment(s).format("MMMM DD, YYYY"));
				s = new Date(s.setDate(
					s.getDate() + 1
				))
			}
		
			// add an extra day because the date range counter cuts the last day off.
			a.push(moment(s).format("MMMM DD, YYYY"));

			return a;
		};

	});

	$(document).on('click', '.add_custom_link_button', function(e){
        $(this).closest('div').append('<div class="custom-link-wrapper">' + 
                '<div class="add_custom_link">' +
                    '<input type="text" placeholder="Paste URL or type to search">' +
                    '<div class="links_list"></div>' +
                    '<span class="button-primary">' +
                        '<i class="mce-ico mce-i-dashicon dashicons-editor-break"></i>' +
                    '</span>' +
                '</div>' +
                '<div class="cancel_custom_link">' +
                    '<span class="button-primary">' +
                        '<i class="mce-ico mce-i-dashicon dashicons-no"></i>' +
                    '</span>' +
                '</div>' +
            '</div>');
        $(this).closest('.suggestion').find('.link-form-button').hide();
        $(this).closest('.wpil-collapsible-wrapper').find('.link-form-button').hide();
	});

	$(document).on('keyup', '.add_custom_link input[type="text"]', wpil_link_autocomplete);
	$(document).on('click', '.add_custom_link .links_list .item', wpil_link_choose);

	var wpil_link_autocomplete_timeout = null;
	var wpil_link_number = 0;
	function wpil_link_autocomplete(e) {
		var list = $(this).closest('div').find('.links_list');

		//choose variant with keyboard
		if ((e.which == 38 || e.which == 40 || e.which == 13) && list.css('display') !== 'none') {
			switch (e.which) {
				case 38:
					wpil_link_number--;
					if (wpil_link_number > 0) {
						list.find('.item').removeClass('active');
						list.find('.item:nth-child(' + wpil_link_number + ')').addClass('active')
					}
					break;
				case 40:
					wpil_link_number++;
					if (wpil_link_number <= list.find('.item').length) {
						list.find('.item').removeClass('active');
						list.find('.item:nth-child(' + wpil_link_number + ')').addClass('active')
					}
					break;
				case 13:
					if (list.find('.item.active').length) {
						var url = list.find('.item.active').data('url');
						list.closest('.add_custom_link').find('input[type="text"]').val(url);
						list.html('').hide();
						wpil_link_number = 0;
					}
					break;
			}
		} else {
			//search posts
			var search = $(this).val();
			if ($('#_ajax_linking_nonce').length && search.length) {
				var nonce = $('#_ajax_linking_nonce').val();
				clearTimeout(wpil_link_autocomplete_timeout);
				wpil_link_autocomplete_timeout = setTimeout(function(){
					$.post(ajaxurl, {
						page: 1,
						search: search,
						action: 'wp-link-ajax',
						_ajax_linking_nonce: nonce,
						'wpil_custom_link_search': 1
					}, function (response) {
						list.html('');
						response = jQuery.parseJSON(response);
						for (var item of response) {
							list.append('<div class="item" data-url="' + item.permalink + '"><div class="title">' + item.title + '</div><div class="date">' + item.info + '</div></div>');
						}
						list.show();
						wpil_link_number = 0;
					});
				}, 500);
			}
		}
	}

	function wpil_link_choose() {
		var url = $(this).data('url');
		$(this).closest('.add_custom_link').find('input[type="text"]').val(url);
		$(this).closest('.links_list').html('').hide();
	}

	$(document).on('click', '.add_custom_link span', function(){
		var el = $(this),
			link = el.parents('.add_custom_link').find('input').val(),
			nonce = $('[data-wpil-ajax-container]').data('wpil-suggestion-nonce');

		if (link) {
			$.post(
				ajaxurl, 
				{
					action: 'wpil_get_link_title',
					link: link,
					nonce: nonce
				}, function (response) {
					if(response && undefined !== response.error){
						wpil_swal(response.error.title, response.error.text, 'error');
						return;
					}

					if (!el.parents('.wpil-collapsible-wrapper').length) {
						var suggestion = el.closest('.suggestion');
						suggestion.html(response.title + '<br><a class="post-slug" target="_blank" href="'+link+'">'+response.link+'</a>' +
							'<span class="add_custom_link_button link-form-button"> | <a href="javascript:void(0)">Custom Link</a></span>');
						suggestion.data('id', response.id);
						suggestion.data('type', response.type);
						suggestion.data('custom', response.link);
					} else {
						var wrapper = el.closest('.wpil-collapsible-wrapper');
						wrapper.find('input[type="radio"]').prop('checked', false);
						wrapper.find('.wpil-content ul').prepend('<li>' +
							'<div>' +
							'<input type="radio" checked="" data-id="'+response.id+'" data-type="'+response.type+'" data-suggestion="-1" data-custom="'+link+'" data-post-origin="internal" data-site-url="">' +
							'<span class="data">' +
							'<div class="suggested-post-data-container"><strong>Title:</strong> <span class="suggested-post-title">'+response.title+'</span></div>' +
							'<div class="suggested-post-data-container"><strong>Published:</strong> '+response.date+'</div>' +
							'<strong>URL:</strong> <a class="post-slug" target="_blank" href="'+link+'">'+response.link+'</a>\n' +
							'</span>' +
							'</div>' +
							'</li>');
						wrapper.find('input[type="radio"]')[0].click();
						wrapper.find('.wpil-collapsible').addClass('wpil-active');
						wrapper.find('.wpil-content').show();
					}
			});
		} else {
			alert("The link is empty!");
		}
	});

    // if the user cancels the custom link
    $(document).on('click', '.cancel_custom_link span', function(){
        $(this).closest('.suggestion').find('.link-form-button').show();
        $(this).closest('.wpil-collapsible-wrapper').find('.link-form-button').show();
        $(this).closest('.custom-link-wrapper').remove();
    });

	//show edit sentence form
	$(document).on('click', '.wpil_edit_sentence', function(){
		var block = $(this).closest('.sentence');
		setTimeout(function(){openSentenceEditor(block);}, 300); // delay the opening so things can finish their processing
	});

	// listen for clicks to the "Allow multiple links" checkbox
	var multiLinkSet;
	$(document).on('click', '.wpil-sentence-allow-multiple-links', function(){
		var checkbox = $(this);
		clearTimeout(multiLinkSet);
		multiLinkSet = setTimeout(function(){
			ajaxSetMultiLinksInEditor(checkbox);
		}, 200);
	});

	function ajaxSetMultiLinksInEditor(checkbox){
		if(!checkbox){
			return;
		}

		var checked = checkbox.is(':checked') ? 1: 0;

		var data = {
			action: 'wpil_set_multi_link_in_sentence_editor',
			checked: checked,
			nonce: checkbox.data('nonce')
		};
		jQuery.ajax({
			type: 'POST',
			url: ajaxurl,
			dataType: 'json',
			data: data,
			error: function (jqXHR, textStatus, errorThrown) {
				var wrapper = document.createElement('div');
				$(wrapper).append('<strong>' + textStatus + '</strong><br>');
				$(wrapper).append(jqXHR.responseText);
				wpil_swal({"title": "Error", "content": wrapper, "icon": "error"});
			},
			success: function(response){
				if(response.success){
					console.log(response.success.text);
				}
			},
			complete: function(){
				// regardless of the outcome, set all the other checkboxes to the same setting as this one
				if(checkbox.is(':checked')){
					$('.wpil-sentence-allow-multiple-links').prop('checked', true);
				}else{
					$('.wpil-sentence-allow-multiple-links').prop('checked', false);
				}
			}
		});

	}

	function openSentenceEditor(block){
		var form = block.find('.wpil_edit_sentence_form');
		var id = 'wpil_editor' + block.data('id');
		var sentence = form.find('.wpil_content').html();

		if (typeof inbound_internal_link !== 'undefined') {
			var link = inbound_internal_link;
		} else {
			var link = $(block).closest('tr').find('.post-slug:first').attr('href');
		}

		sentence = sentence.replace('%view_link%', link);
		form.find('.wpil_content').attr('id', id).html(sentence).show();
		form.show();
		var textarea_height = form.find('.wpil_content').height() + 100;
		form.find('.wpil_content').height(textarea_height);
        if(undefined === wp.blockEditor){
            wp.editor.initialize(id, {
                tinymce: true,
                quicktags: true,
            });
        }else{
            wp.oldEditor.initialize(id, {
                tinymce: true,
                quicktags: true,
			});
        }

		tinyMCE.activeEditor.setContent(form.find('.wpil_content').text());
		block.find('input[type="checkbox"]:not(.wpil-sentence-allow-multiple-links), .wpil_sentence_with_anchor, .wpil_edit_sentence').hide();
		setTimeout(function(){ 
			block.find('.mce-tinymce').show(); 
			block.find('.wp-editor-tabs .switch-tmce').trigger('click');
			block.find('.mce-tinymce.mce-container.mce-panel').css({'display': 'block'});
			console.log('editor open!');
		}, 500);
		form.find('.wpil_content').hide();
		form.show();
	}

	// make sure the text area shows when the user clicks the "text" button
	$(document).on('click', '.wpil_edit_sentence_form .wp-editor-tabs .switch-html', function(){
		var textEditor = $(this).parents('.wp-editor-tools').find('textarea.wpil_content');
		if(!$(textEditor).is(':visible')){
			setTimeout(function(){
				$(textEditor).css({'display': 'inline-block'});
			}, 50);
		}
	});

	//Cancel button pressed
	$(document).on('click', '.wpil_edit_sentence_form .button-secondary', function(){
		var block = $(this).closest('.sentence');
		wpil_editor_remove(block);
	});

	//Save edited sentence
	$(document).on('click', '.wpil_edit_sentence_form .button-primary', function(){
		var block = $(this).closest('.sentence');
		var id = 'wpil_editor' + block.data('id');

		//get content from the editor
		var sentence;
		if ($('#' + id).css('display') == 'none') {
			var editor = tinyMCE.get(id);
			sentence = editor.getContent();
		} else {
			sentence = $('#' + id).val();
		}

		//remove multiple whitespaces and outer P tag
		if (sentence.substr(0,3) == '<p>') {
			sentence = sentence.substr(3);
		}
		if (sentence.substr(-4) == '</p>') {
			sentence = sentence.substr(0, sentence.length - 4);
		}
		var sentence_clear = sentence;

		// clear any click-disabling classes
		block.find('.wpil_sentence').removeClass('wpil-disable-word-click').prop('title', 'Double clicking a word will select it.');

		// update the text in the plain text version of the link content
		block.find('.wpil_edit_sentence_form').find('.wpil_content').text(sentence_clear);

		// if the user wants to allow multiple links in the suggestion text
		if(block.find('.wpil-sentence-allow-multiple-links').is(':checked')){
			// grab all the links and replace their text representations with placeholders
			var links = sentence.match(/<a[^>]+>/g);

			if (links[0] != null) {
				sentence = sentence.replace(/<a[^>]+\s*>/g, ' %link_start% ');
				sentence = sentence.replace(/\s*<\/a>/g, ' %link_end% ');

				// if there's more than one link
				if(links[1] != null){
					// disable the sentence word clicking
					block.find('.wpil_sentence').addClass('wpil-disable-word-click').prop('title', 'Word click-selecting disabled when multiple links present.');;
				}
			}
		}else{
			//put each word to span
			var link = sentence.match(/<a[^>]+>/);
			if (link[0] != null) {
				sentence = sentence.replace(/<a[^>]+\s*>/, ' %link_start% ');
				sentence = sentence.replace(/\s*<\/a>/, ' %link_end% ');
			}

			// check for a second link
			var secondLink = sentence.match(/<a[^>]+>/);
			if (secondLink != null && secondLink[0] != null) {
				// if there are more links, remove them
				sentence = sentence.replace(/<a[^>]+\s*>/g, '');
				sentence = sentence.replace(/\s*<\/a>/g, '');
				// and update the clear sentence so the additional links aren't present
				sentence_clear = sentence.replace(/%link_start%/g, link[0]);
				sentence_clear = sentence_clear.replace(/%link_end%/g, '</a>');
				block.find('.wpil_edit_sentence_form').find('.wpil_content').text(sentence_clear);
			}
		}

		sentence = sentence.replace(/\s+/g, ' ');
		sentence = sentence.replace(/ /g, '</span> <span class="wpil_word">');
		sentence = '<span class="wpil_word">' + sentence + '</span>';
		if (link && link[0] != null) {
			sentence = sentence.replace(/<span class="wpil_word">%link_start%<\/span>/g, link[0]);
			sentence = sentence.replace(/<span class="wpil_word">%link_end%<\/span>/g, '</a>');
		}else if(links && links[0] != null){
			for(var i in links){
				sentence = sentence.replace(/<span class="wpil_word">%link_start%<\/span>/, links[i]);
			}
			sentence = sentence.replace(/<span class="wpil_word">%link_end%<\/span>/g, '</a>');
		}

		block.find('.wpil_sentence').html(sentence);
		block.find('input[name="custom_sentence"]').val(btoa(unescape(encodeURIComponent(sentence_clear))));

		spaceSentenceWords(block.find('.wpil_sentence'));

		if(block.closest('.wp-list-table').hasClass('inbound')){
			if(block.closest('.wpil-collapsible').length > 0){ // if the sentence is the top-level sentence in a dropdown
				updateDropdownSentence(block.find('.wpil_sentence'));
			}
		}
		toggleSentenceReset(block.find('.wpil_sentence'));

		if (block.closest('tr').find('.raw_html').length) {
			sentence_clear = sentence_clear.replace(/</g, '&lt;');
			sentence_clear = sentence_clear.replace(/>/g, '&gt;');
			block.closest('tr').find('.raw_html').hide();
			block.closest('tr').find('.raw_html.custom-text').html(sentence_clear).show();
		}

		block.closest('tr').find('.chk-keywords').prop('checked', true);
		wpil_editor_remove(block)
	});

	/**
	 * Fires the WP editor at a target element to run through the initialization process
	 **/
	function wpilEditorInitialize(){
        if(undefined === wp.blockEditor){
            wp.editor.initialize('wpil-editor-target', {
                tinymce: true,
                quicktags: true,
            });
			setTimeout(function(){
				wp.editor.remove('wpil-editor-target');
			}, 250);
        }else{
            wp.oldEditor.initialize('wpil-editor-target', {
                tinymce: true,
                quicktags: true,
			});
			setTimeout(function(){
				wp.oldEditor.remove('wpil-editor-target');
			}, 250);
        }
	}

	//Remove WP Editor after sentence editing
	function wpil_editor_remove(block) {
		var form = block.find('.wpil_edit_sentence_form');
		var textarea_height = form.find('.wpil_content').height() - 100;
		form.find('.wpil_content').height(textarea_height);
		form.hide();
		form.find('.wpil_content').attr('id', '').prependTo(form);
        if(undefined === wp.blockEditor){
            wp.editor.remove('wpil_editor' + block.data('id'));
        }else{
            wp.oldEditor.remove('wpil_editor' + block.data('id')); 
        }
		form.find('.wp-editor-wrap').remove();
		block.find('input[type="checkbox"], .wpil_sentence_with_anchor, .wpil_edit_sentence').show();
	}

	function customSentenceRefresh(el) {
		if(el.parents('.wpil-content').length){
			var input = el.closest('.data').find('input[name="custom_sentence"]');
			var sentence = el.html();
			var editorContent = el.closest('.data').find('.wpil_content');
		}else{
			var input = el.closest('.sentence').find('input[name="custom_sentence"]');
			var sentence = el.closest('.wpil_sentence').html();
			var editorContent = el.closest('.sentence').find('.wpil_content');
		}

		sentence = sentence.replace(/<span[^>]+wpil_suggestion_tag[^>]+>([a-zA-Z0-9=+]+)<\/span>/g, function (x) {
			x = x.replace(/<span[^>]+>/g, '');
			x = x.replace(/<\/span>/g, '');
			return atob(x);
		});
		sentence = sentence.replace(/<\/span> <\/a>/g, '<\/span><\/a> ');
		sentence = sentence.replace(/<span[^>]+>/g, '');
		sentence = sentence.replace(/<\/span>/g, '');
		editorContent.html(sentence);

		if (input.val() !== '') {
			input.val(btoa(unescape(encodeURIComponent(sentence))));
		}
	}

	/**
	 * Updates the sentence and "custom_sentence" text of suggested sentences in dropdowns
	 **/
	function updateDropdownSentence(sentence){
		var sentenceWithAnchor = sentence.closest('.wpil_sentence_with_anchor');
		var listItemId = sentenceWithAnchor.data('li-id');

		if(undefined !== listItemId){
			var itemData = $(sentence).closest('.wpil-collapsible-wrapper').find('.wpil-inbound-sentence-data-container[data-container-id="' + listItemId + '"] .data');

			itemData.find('.wpil_sentence').html(sentence.html());
			itemData.find('.wpil_content').html(sentenceWithAnchor.siblings('.wpil_edit_sentence_form').find('.wpil_content').html());
			itemData.find('[name="custom_sentence"]').val(sentenceWithAnchor.siblings('[name="custom_sentence"]').val());

			if(sentence.hasClass('wpil-disable-word-click')){
				itemData.find('.wpil_sentence').addClass('wpil-disable-word-click').prop('title', 'Word click-selecting disabled when multiple links present.');
			}else{
				itemData.find('.wpil_sentence').removeClass('wpil-disable-word-click').prop('title', 'Double clicking a word will select it.');
			}

			customSentenceRefresh(itemData.find('.wpil_sentence'));
		}
	}

	/**
	 * Toggles the display of the "reset sentence" button.
	 **/
	function toggleSentenceReset(sentence){
		var parent = sentence.closest('div');
		var listItemId = sentence.closest('.wpil_sentence_with_anchor').data('li-id');
		var currentSentence = sentence.html().toString().replace(new RegExp(' data-wpil-word-id="[0-9]*"', 'ig'), '').replace(new RegExp('[\\s]*</a>[\\s]*', 'ig'), '</a> ').trim();

		// get the current target link
		if (typeof inbound_internal_link !== 'undefined') {
			var link = inbound_internal_link;
		} else {
			var link = $(sentence).closest('tr').find('.post-slug:first').attr('href');
		}

		// if the target link is in the sentence
		if(currentSentence.indexOf(link) !== -1){
			// normalize the changed sentence so we can tell if it's basically the same as the original
			currentSentence = currentSentence.replace(link, '%view_link%')
												.replace(new RegExp('[\\s]*<a href="%view_link%">[\\s]*', 'ig'), ' <a href="%view_link%">')
												.replace(new RegExp('[\\s]*</a>[\\s]*', 'ig'), '</a> ')
												.replace(new RegExp('[\\s][\\s]*', 'ig'), ' ').trim();

			if(currentSentence.indexOf('<span class="wpil_word"></span> <a href="%view_link%">') === 0){
				currentSentence = currentSentence.replace('<span class="wpil_word"></span> <a href="%view_link%">', '<a href="%view_link%">');
			}

			if(currentSentence.indexOf('</span></a> <span class="wpil_word"></span>') + 43 === currentSentence.length){
				currentSentence = currentSentence.replace('</span></a> <span class="wpil_word"></span>', '</span></a>');
			}
		}

		// base64 the sentence
		currentSentence = Base64.encode(currentSentence);

		if(parent.find('[name="original_sentence_with_anchor"]').val() === currentSentence){
			parent.find('.wpil-reload-sentence-with-anchor').removeClass('wpil-reset-active');
		}else{
			parent.find('.wpil-reload-sentence-with-anchor').addClass('wpil-reset-active');
		}

		if(undefined !== listItemId){
			var itemData = $(sentence).closest('.wpil-collapsible-wrapper').find('.wpil-inbound-sentence-data-container[data-container-id="' + listItemId + '"] .data');

			if(itemData.find('[name="original_sentence_with_anchor"]').val() === currentSentence){
				itemData.find('.wpil-reload-sentence-with-anchor').removeClass('wpil-reset-active');
			}else{
				itemData.find('.wpil-reload-sentence-with-anchor').addClass('wpil-reset-active');
			}
		}

		if(parent.hasClass('data')){ // if this is a sentence in a dropdown
			// do the check on the active sentence
			var tLS = parent.closest('.wpil-collapsible-wrapper').find('.top-level-sentence');
			if(tLS.find('[name="original_sentence_with_anchor"]').val() === currentSentence){
				tLS.find('.wpil-reload-sentence-with-anchor').removeClass('wpil-reset-active');
			}else{
				tLS.find('.wpil-reload-sentence-with-anchor').addClass('wpil-reset-active');
			}
		}
	}

	/**
	 * Resets modified suggestion texts back to their initial values when the user clicks the reset button.
	 **/
	$(document).on('click', '.wpil-reload-sentence-with-anchor', function(){
		var parent = $(this).closest('div');
		var sentence = parent.find('.wpil_sentence');
		var originalSentence = Base64.decode(parent.find('[name="original_sentence_with_anchor"]').val());
		var dropdownWrapper = parent.closest('.wpil-collapsible-wrapper');

		sentence.html(originalSentence);
		sentence.removeClass('wpil-disable-word-click').prop('title', 'Double clicking a word will select it.');
		$(this).removeClass('wpil-reset-active');

		styleSentenceWords(sentence);
		customSentenceRefresh(parent.find('.wpil_sentence'));

		// if the user clicked the reset button in the top level sentence in a dropdown,
		// trigger the sentence refresh in the element in the dropdown
		if(dropdownWrapper.length > 0){
			if(parent.hasClass('top-level-sentence')){
				var listItemId = parent.find('.wpil_sentence_with_anchor').data('li-id');
				if(undefined !== listItemId){
					var reset = dropdownWrapper.find('.wpil-inbound-sentence-data-container .wpil_sentence_with_anchor[data-li-id="' + listItemId + '"] .wpil-reload-sentence-with-anchor');
					if(reset.hasClass('wpil-reset-active')){
						reset.trigger('click');
					}
				}
			}else{
				var listItemId = parent.closest('.wpil-inbound-sentence-data-container').data('container-id');
				if(undefined !== listItemId){
					var activeSentence = dropdownWrapper.find('.sentence.top-level-sentence .wpil_sentence_with_anchor');
					if(listItemId === activeSentence.data('li-id')){
						var reset = activeSentence.find('.wpil-reload-sentence-with-anchor');
						if(reset.hasClass('wpil-reset-active')){
							reset.trigger('click');
						}
					}
				}
			}
		}
	});

	$(document).on('click', '.wpil_add_link_to_ignore', function(){
		if (confirm('You are about to add this link to your ignore list and it will not be suggested as a link in the future. However, you can reverse this decision on the settings page.')) {
			var block = $(this).closest('div');
			var id = block.data('id');
			var type = block.data('type');
			var postOrigin = block.data('post-origin');
			var siteUrl = block.data('site-url');

			$.post(ajaxurl, {
				id: id,
				type: type,
				post_origin: postOrigin,
				site_url: siteUrl,
				action: 'wpil_add_link_to_ignore'
			}, function (response) {
				response = $.parseJSON(response);
				if (response.error) {
					wpil_swal('Error', response.error, 'error');
				} else {
					if (block.closest('.suggestion').length) {
						block.closest('tr').fadeOut(300, function(){
							$(this).remove();
						});
					} else {
						var id = block.data('id');
						var type = block.data('type');
						var wrapper = block.closest('.wpil-collapsible-wrapper');

						wrapper.find('input[data-id="' +  id + '"][data-type="' +  type + '"]').closest('li').remove();
						wrapper.find('li:first input').prop('checked', true).click();
					}
					wpil_swal('Success', 'Link was added to the ignored list successfully!', 'success');
				}
			});
		}
	});

	var mouseExit;
	$(document).on('mouseover', '.wpil_help i, .wpil_help div', function(){
		clearTimeout(mouseExit);
		$('.wpil_help div').hide();
		$(this).parent().children('div').show();
	});

	$(document).on('mouseout', '.wpil_help i, .wpil_help div', function(){
		var element = this;
		mouseExit = setTimeout(function(){
			$(element).parent().children('div').hide();
		}, 250);
		
	});

	$(document).on('click', '.csv_button', function(){
		if($(this).hasClass('file-downloadable')){
			return;
		}

		$(this).addClass('wpil_button_is_active');
		var type = $(this).data('type');
		var data = null;
		var id = Math.floor(Math.random() * 100000);
		if(type === 'error'){ data = $(this).data('codes'); }
		wpil_csv_request(type, 1, data, id);
	});

	function wpil_csv_request(type, count, data = null, id = 0) {
		$.post(ajaxurl, {
			count: count,
			type: type,
			action: 'wpil_csv_export',
			export_data: data,
			id: id
		}, function (response) {
			if (response.error) {
				wpil_swal(response.error.title, response.error.text, 'error');
			} else {
				console.log(response);
				if (response.filename) {
					if(undefined !== response.fileExists && !response.fileExists){
						wpil_swal('File Not Creatable', 'Unfortunately, it wasn\'t possible to create the export file. It is most likely caused by server settings preventing Link Whisper from writing in it\'s current directory', 'error');
						$('#wpil_report_reset_data_form .csv_button').removeClass('wpil_button_is_active');
						return;
					}

					// get the current button and remove the loading from it
					var currentButton = $('.csv_button[data-type="'+type+'"]');
					currentButton.removeClass('wpil_button_is_active');

					// create our download link and try downloading the file
					var link = document.createElement('a');
					link.href = response.filename;
					link.download = currentButton.data('file-name');
					document.body.appendChild(link);
					link.click();
					document.body.removeChild(link);

					// as a backup, convert the csv button the user clicked into a download button
					currentButton.addClass('file-downloadable');
					var text = 'Download ' + currentButton.first().text();
					currentButton.text(text);
					currentButton.attr('download', currentButton.data('file-name'));
					currentButton.attr('href', response.filename);

//					location.href = response.filename;
				} else {
					wpil_csv_request(response.type, ++response.count, data, id);
				}
			}
		});
	}

	$(document).on('click', '.return_to_report', function(e){
		e.preventDefault();

		// if a link is specified
		if(undefined !== this.href){
			// parse the url
			var params = parseURLParams(this.href);
			// if the url is back to an edit page
			if(	undefined !== typeof params &&
				( (undefined !== params.action && undefined !== params.post && 'edit' === params.action[0]) || params.direct_return || true) // NOTE: if we make it to 2.2.8 without issues, make the checks a little neater. I'm seeing about doing away with the JS report redirect thing to save some system resources for customers.
			){
				if(params.ret_url && params.ret_url[0]){
					var link = atob(decodeURI(params.ret_url[0]));
				}else{
					var link = this.href;
				}

				// redirect back to the page
				location.href = link;
				return;
			}
		}
	});

	$(document).on('click', '.wpil-export-suggestions', function(e){
		e.preventDefault();

		var links = [];
		var data = [];
		var suggestions = $('#tbl_keywords').find('[wpil-link-new][type=checkbox]:checked');
		var suggestionType = $(this).data('suggestion-type');
		if(suggestions.length === 0){
			suggestions = $('#tbl_keywords').find('[wpil-link-new][type=checkbox]');
		}

		suggestions.each(function() {
			if (suggestionType == 'inbound') {
				var dropdownData = $(this).closest('tr').find('.sentences .wpil-content');
				var item = {};
				var id = $(this).closest('tr').find('.sentence').data('id');
				var type = $(this).closest('tr').find('.sentence').data('type');
				if(dropdownData.length > 0){
					item.links = [];
					$(dropdownData).find('.data').each(function(index, element){
						item.links.push({
							'id': id,
							'type': type,
							'sentence': $(element).find('[name="sentence"]').val(),
							'sentence_with_anchor': $(element).find('.wpil_sentence_with_anchor').html(),
							'custom_sentence': $(element).find('input[name="custom_sentence"]').val()
						});
					});
				}else{
					item.links = [{
						'id': id,
						'type': type,
						'sentence': $(this).closest('tr').find('.sentence').find('[name="sentence"]').val(),
						'sentence_with_anchor': $(this).closest('tr').find('.wpil_sentence_with_anchor').html(),
						'custom_sentence': $(this).closest('tr').find('input[name="custom_sentence"]').val()
					}];
				}

				data.push(item);
			} else {
				if ($(this).closest('tr').find('input[type="radio"]:checked').length) {
					var id =  $(this).closest('tr').find('input[type="radio"]:checked').data('id');
					var type = $(this).closest('tr').find('input[type="radio"]:checked').data('type');
					var custom_link = $(this).closest('tr').find('input[type="radio"]:checked').data('custom');
					var post_origin = $(this).closest('tr').find('input[type="radio"]:checked').data('post-origin');
					var site_url = $(this).closest('tr').find('input[type="radio"]:checked').data('site-url');
				} else {
					var id =  $(this).closest('tr').find('.suggestion').data('id');
					var type =  $(this).closest('tr').find('.suggestion').data('type');
					var custom_link =  $(this).closest('tr').find('.suggestion').data('custom');
					var post_origin = $(this).closest('tr').find('.suggestion').data('post-origin');
					var site_url = $(this).closest('tr').find('.suggestion').data('site-url');
				}

				links.push({
					id: id,
					type: type,
					custom_link: custom_link,
					post_origin: post_origin,
					site_url: site_url,
					sentence: $(this).closest('div').find('[name="sentence"]').val(),
					sentence_with_anchor: $(this).closest('div').find('.wpil_sentence_with_anchor').html(),
					custom_sentence: $(this).closest('.sentence').find('input[name="custom_sentence"]').val()
				});
			}
		});

		if (suggestionType == 'outbound') {
			data.push({'links': links});
		}

		var exportData = {
			"id": $(this).data('id'),
			"type": $(this).data('type'),
			"suggestion_type": suggestionType,
			'export_type': $(this).data('export-type'),
			'data': JSON.stringify(data)
    	};

		$.post(ajaxurl, {
			action: 'wpil_export_suggestion_data',
			export_data: exportData,
			nonce: $(this).data('nonce'),
		}, function (response) {
			if (response.error) {
				wpil_swal(response.error.title, response.error.text, 'error');
			} else {
				if (response.filename) {
					var link = document.createElement('a');
					link.href = response.filename;
					link.download = response.nicename;
					document.body.appendChild(link);
					link.click();
					document.body.removeChild(link);
//					location.href = response.filename;
				}
			}
		});
	});

	/**
	 * Makes a call to the object cache flusher.
	 * Only works on pages that have the nonce defined
	 */
	function flushObjectCache(){
		var nonce = $('#wpil-object-cache-flush-nonce').val();
		if(!nonce || nonce.length < 1){
			return;
		}

		$.post(ajaxurl, {
			action: 'wpil_flush_object_cache',
			nonce: nonce,
		}, function (response) {
			console.log('flush!');
		});
	}

	$(document).on('click', '.wpil_gsc_switch_app', function(){
		if($(this).hasClass('enter-custom')){
			$('.wpil_gsc_app_inputs').hide();
			$('.wpil_gsc_custom_app_inputs').show();
		}else{
			$('.wpil_gsc_app_inputs').show();
			$('.wpil_gsc_custom_app_inputs').hide();
		}
	});

	/*$(document).on('click', '.wpil-get-gsc-access-token', function(){
		$('.wpil_gsc_get_authorize').show();
		$(this).hide();
	});*/

	$(document).on('click', '.wpil_gsc_enter_app_creds', function(){
		$('#frmSaveSettings').trigger('submit');
	});

	$(document).on('click', '.wpil_gsc_clear_app_creds', function(){
		$.post(ajaxurl, {
			action: 'wpil_clear_gsc_app_credentials',
			nonce: $(this).data('nonce')
		}, function (response) {
			location.reload();
		});
	});

	$(document).on('click', '.wpil-gsc-deactivate-app', function(){
		$.post(ajaxurl, {
			action: 'wpil_gsc_deactivate_app',
			nonce: $(this).data('nonce')
		}, function (response) {
			location.reload();
		});
	});

	/** Showing processing errors **/
	var processingError;
	// sets up a notice that will display if it's not cleared
	function setupProcessingError(clear = false){
		clearTimeout(processingError);
		if(!clear){
			processingError = setTimeout(function(){
				$('.wpil-process-loading-error-message').css({'display': 'inline-block'});
			}, 180 * 1000); // the max processing time for a LW process _should_ be 90 seconds, but this allows more breathing room
		}
	}

	// hides the error message in case it's showing
	function hideProcessingError(){
		$('.wpil-process-loading-error-message').css({'display': 'none'});
	}
	/** /Showing processing errors **/

    /** Sticky Header **/
	// Makes the thead sticky to the top of the screen when scrolled down far enough
	if($('.wpil_styles .wp-list-table:not(.sticky-ignore)').length){
		var theadTop = $('.wpil_styles .wp-list-table:not(.sticky-ignore)').offset().top;
		var adminBarHeight = parseInt(document.getElementById('wpadminbar').offsetHeight);
		var scrollLine = (theadTop - adminBarHeight);
		var sticky = false;

		// duplicate the footer and insert in the table head
		$('.wpil_styles .wp-list-table:not(.sticky-ignore) tfoot tr').clone().addClass('wpil-sticky-header').css({'display': 'none', 'top': adminBarHeight + 'px'}).appendTo('.wp-list-table thead');

		// resizes the header elements
		function sizeHeaderElements(){
			// get the width of the normal header
			var headerWidth = $('.wpil_styles .wp-list-table:not(.sticky-ignore) thead tr').width();

			// adjust for any change in the admin bar
			adminBarHeight = parseInt(document.getElementById('wpadminbar').offsetHeight);
			$('.wpil-sticky-header').css({'top': adminBarHeight + 'px', 'width': headerWidth});

			// adjust the size of the header columns
			var elements = $('.wpil-sticky-header').find('th');
			$('.wpil_styles .wp-list-table:not(.sticky-ignore) thead tr').not('.wpil-sticky-header').find('th').each(function(index, element){
				//var width = getComputedStyle(element).width;
				var width = $(element).get(0).scrollWidth - (parseInt(getComputedStyle(element).paddingLeft) + parseInt(getComputedStyle(element).paddingRight));
				$(elements[index]).attr('style', 'width:' + width + "px !important;");
			});
		}
		sizeHeaderElements();

		function resetScrollLinePositions(){
			if($('.wpil_styles .wp-list-table:not(.sticky-ignore)').length < 1){
				return;
			}
			theadTop = $('.wpil_styles .wp-list-table:not(.sticky-ignore)').offset().top;
			adminBarHeight = parseInt(document.getElementById('wpadminbar').offsetHeight);
			scrollLine = (theadTop - adminBarHeight);
		}

		$(window).on('scroll', function(e){
			var scroll = parseInt(document.documentElement.scrollTop);

			// if we've passed the scroll line and the head is not sticky
			if(scroll > scrollLine && !sticky){
				// sticky the header
				$('.wpil-sticky-header').css({'display': 'table-row'});
				sticky = true;
			}else if(scroll < scrollLine && sticky){
				// if we're above the scroll line and the header is sticky, unsticky it
				$('.wpil-sticky-header').css({'display': 'none'});
				sticky = false;
			}
		});

		var wait;
		$(window).on('resize', function(){
			clearTimeout(wait);
			setTimeout(function(){ 
				sizeHeaderElements(); 
				resetScrollLinePositions();
			}, 150);
		});

		setTimeout(function(){ 
			resetScrollLinePositions();
		}, 1500);
	}
    /** /Sticky Header **/

    /** Making the "Load without animation" setting sticky **/
    $(document).on('click', '.wpil-animation-load-setting', toggleLoadWithoutAnimation);
    function toggleLoadWithoutAnimation(e){
		e.preventDefault();
        saveLoadWithoutAnimation(this);
    }

    function saveLoadWithoutAnimation(button){
        var status = $(button).data('disable-load-with-animation');
        var nonce = $(button).data('nonce');

        $.ajax({
            type: "POST",
            url: ajaxurl,
            data: {
                action: 'wpil_save_animation_load_status',
                nonce: nonce,
                status: (status) ? 1: 0,
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(textStatus);
            },
            success: function(response){
                console.log(response);

            },
			complete: function(){
				window.location = button.href;
			}
        });
    }
	/** /Making the "Load without animation" setting sticky **/

	/** Showing link stats in inbound suggestions **/
    $(document).on('click', '.wpil-inbound-show-link-stats-button .button-primary', togglePostLinkingStats);
    function togglePostLinkingStats(){
        $('.wpil-inbound-show-link-stats-form').toggle();
        saveInboundPostLinkingStatsVisibility(this);
    }

    function saveInboundPostLinkingStatsVisibility(button){
        var visible = $('.wpil-inbound-show-link-stats-form').is(':visible');
        var nonce = $(button).data('nonce');

        $.ajax({
            type: "POST",
            url: ajaxurl,
            data: {
                action: 'wpil_save_inbound_link_stats_visibility',
                nonce: nonce,
                visible: (visible) ? 1: 0,
            },
            error: function (jqXHR, textStatus, errorThrown) {
                console.log(textStatus);
            },
            success: function(response){
                console.log(response);
            },
        });
    }
	/** /Showing link stats in inbound suggestions **/

	/** General Items **/
	$(document).on('keyup', '.wpil_styles #current-page-selector', maybeChangePage);
	function maybeChangePage(e){
		if(!e || !e.target || e.keyCode !== 13){
			return;
		}

		// if the selector isn't in a form
		if($(e.target).parents('form').length < 1){
			// manually perform the page updating
			var page = parseInt($(e.target).val());

			if(page > 1){
				if(-1 !== window.location.href.indexOf('paged')){
					window.location.href = window.location.href.replace(/paged=([0-9]*)/, 'paged=' + page);
				}else{
					window.location.href += '&paged=' + page;
				}
			}else if(-1 !== window.location.href.indexOf('paged')){
				window.location.href = window.location.href.replace(/paged=([0-9]*)/, '');
			}
		}
	}
	/** /General Items */

	/** Ajax saving for Screen Options **/
	var savingScreenOptions = false;
	$(document).on('submit', '#adv-settings', ajaxSaveScreenOptions);
	function ajaxSaveScreenOptions(e){
		// exit if this is not a Link Whisper page
		if($('body').find('.wpil_styles').length < 1 || savingScreenOptions){
			return;
		}
		// stop the form submit
		e.preventDefault();

		// get the form
		var form = $(this);

		// get the values from the screen options
		var saveOptions = {};

		$(this).find('input').each(function(index, element){
			if(!element.id){
				return;
			}

			var el = $(element);
			if(el.attr('type') === 'checkbox'){
				saveOptions[element.id] = el.is(':checked') ? 'on': 'off';
			}else{
				saveOptions[element.id] = $(element).val();
			}
		});

		if(Object.keys(saveOptions).length > 0){
			$.ajax({
				type: "POST",
				url: ajaxurl,
				data: {
					action: 'wpil_save_screen_options',
					nonce: $(this).find('#screenoptionnonce').val(),
					options: saveOptions,
				},
				error: function (jqXHR, textStatus, errorThrown) {
					console.log(textStatus);
				},
				success: function(response){
					if(response.success){
						window.location.reload();
					}else{
						savingScreenOptions = true;
						form.submit();
					}
					console.log(response);
				}
			});
		}
	}

	/** /Ajax saving for Screen Options **/
})(jQuery);