ResetEra - Hide Forum Threads

Hides threads on resetera.com

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name ResetEra - Hide Forum Threads
// @namespace ThreadFilter
// @description Hides threads on resetera.com
// @require http://code.jquery.com/jquery-latest.min.js
// @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// @include http*://*resetera.com/forums/**
// @version 1.0.6
// ==/UserScript==

let threadTitle;
let currentVisibleThreads = [];
let shownCount = 0;
let originalPageCount = GetNextPage();
let pageCount = originalPageCount;
let additionalThreadCount = 0;

let filterAnchorElementSelector = '.buttonGroup-buttonWrapper:first';
let threadNamePrefix = 'js-threadListItem-';
let memberLinkSelector = '.posterDate a[href*="members/"]';
let memberLinkPrefix = 'https://www.resetera.com/members/';
let threadLinkPrefix = 'https://www.resetera.com/threads/';
let filterButtonClass = 'callToAction';
let darkPurpleColor = 'rgb(86, 65, 132)';
let lightPurpleColor = 'rgb(167, 145, 207)';
let threadsPerPage = 50;

$(document).ready(function() {
    CheckExpiredThreads();
    CreateStyles();
    CreateFilteringElements();
    CreateEventHandlers();

    SetOptions();

	UpdateHideLinks();

    UpdateThreads();
});

function CreateFilteringElements()
{
    let filteringElements = '<div style="font-size:.8rem; margin-left:50px !important; float:right !important;" class="FilteringElementsContainer RowOrdering">';
    filteringElements += '<div style="margin-right:20px;color:#ae8fd6;font-size:12px"><strong>Thread Filter:</strong><br />' + GetFilter() + '</div>';
    filteringElements += '<div>' + GetOpenControlPanelButton() + '</div>';
    filteringElements += '</div>';

    $(filterAnchorElementSelector).parent().append(GetControlPanel());
    $(filterAnchorElementSelector).parent().append(filteringElements);
    $('.TabLinksContainer div a').click(ControlPanelTabClicked);

    
    AddTitleBarSpacer();
}

function GetOpenControlPanelButton() {
    //return '<span class="nodeListNewDiscussionButton"><a id="OpenFilterCP" class="callToAction FilterCP">Filter Control Panel</a></span>';
    return '<span class="nodeListNewDiscussionButton"><button id="OpenFilterCP" class="callToAction FilterCP">Filter Control Panel</button></span>';
}

function CreateStyles()
{
    $("body").append("<link rel='stylesheet' href='//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css'>");

    CreateFilterCPStyle();

    AddStyleToBody('.RowOrdering { display:flex; flex-direction:row; margin-bottom:10px;}');
    AddStyleToBody('.FilteringElementsContainer { padding:5px; }');
    AddStyleToBody('.BoldText { font-weight:bold; }');
    AddStyleToBody('.DisabledFeature { display:none; }');
    AddStyleToBody('.ListingTable td { padding-bottom:10px; }');

    if (localStorage.getItem("HideLinkStyle") != "HideShow")
    {
        $("body").append(GetRemoveStyle());
    }
}

function CreateFilterCPStyle() {
    let  FilterCPStyle = ' .FilterCP { padding: 10px;';
    FilterCPStyle += 'font-weight: bolder;';
    FilterCPStyle += 'font-size: 11px;';
    FilterCPStyle += 'color: black;';
    FilterCPStyle += '-webkit-box-pack: "Open Sans", sans-serif;';
    FilterCPStyle += 'background-color: rgb(167, 145, 207); }';

    FilterCPStyle += '.HiddenTab { display:none }';

    FilterCPStyle += '.TabLinksContainer div { background-color: ' + darkPurpleColor + '; color: white; padding: 10px;}';
    FilterCPStyle += '.TabLinksContainer div a { color: white !important;}';

    FilterCPStyle += '.SelectedTabLink { border: 2px solid white; padding: 2px; }';

    AddStyleToBody(FilterCPStyle);
}

function AddStyleToBody(FilterCPStyle) {
    $("body").append("<style>" + FilterCPStyle + "</style>");
}

function CreateFilter()
{
    $(filterAnchorElementSelector).parent().append(GetFilter());

}

function GetFilter() {
    return "<select id='ThreadFilter'><option value='Unignored' selected='true'>Show Unignored Only</option><option value='Ignored'>Show Ignored Only</option><option value='All'>Show All</option></select>&nbsp;";
}

function AddTitleBarSpacer() {
    $('dl.sectionHeaders .main').after('<dd></dd>');
}

function GetRemoveStyle()
{
    var HideThreadStyle = 'margin-left: -11px;  margin-top: -38px;';
    var HideThreadStyle2 = 'padding-left:10px; margin-left:-45px;  margin-top:-2px;';
    let XStyle = 'content: "x";  font-size: 20pt; color:' + lightPurpleColor;

    RemoveStyle = '<style id="RemoveStyle">';
    RemoveStyle += ' .RemoveUser { padding-left: 35px; padding-top: 0px !important; margin-top: 0px !important; }';
    RemoveStyle += ' .RemoveThread { padding-left: 35px; width:50px; }';

    let removeThreadSelector = 'a[id*="RemoveThread"]';

    RemoveStyle += removeThreadSelector + ':before { ' + XStyle + '; transition: visibility 1s; -webkit-transition:visibility 1s; }';
     RemoveStyle += removeThreadSelector + ' {  padding-left:35px; background-clip:content-box; visibility: hidden !important; transition: visibility 1s; -webkit-transition:visibility 1s;}';
     RemoveStyle += ' .structItem-title:hover > a[id*="RemoveThread"] { visibility: visible !important; transition: visibility 1s; -webkit-transition:visibility 1s; }';

    RemoveStyle += '</style>';

    return RemoveStyle;
}

function UpdateHideLinks()
{
    $(GetThreads()).each(function( index,value ) { AddHideLink(this);});
}

function GetThreads(parentElement)
{
    if (!parentElement)
    {
        parentElement = window.document;
    }

   return $(parentElement).find('.js-threadList').children();
}


function GetUserID(currentThread)
{
    let MemberLink = $(currentThread).find('.username')[0];
    let memberIDMatcher = /members\/.+?\.(\d+)\//i;
    let foundID = memberIDMatcher.exec(MemberLink.href);

    if (foundID && foundID.length > 1)
    {
    return foundID[1];
    }

    return 0;
}

function GetMemberLink(currentThread)
{
    return $(currentThread).find(memberLinkSelector)[0];
}

function GetThreadStarterUsername(currentThread)
{
    return GetMemberLink(currentThread).innerText;
}

function GetThreadID(currentThread)
{
    return currentThread.className.match(/js-threadListItem-(\d+)/i)[1];
}

function GetThreadTitle(currentThread)
{
    return $(currentThread).find('.structItem-title a:first')[0].innerText;
}

function AddHideLink(currentThread)
{
	    IgnoreList = GetListFromLocalStorage('IgnoreList');
    	IgnoredUserList = GetListFromLocalStorage('IgnoredUserList');

  	   	nThreadID = GetThreadID(currentThread);
      	nUserID = GetUserID(currentThread);

    	var bThreadIgnored = (containsObject(nThreadID,IgnoreList) == -1) ? false : true;
    	var bUserIgnored = (containsObject(nUserID,IgnoredUserList) == -1) ? false : true;
        var sThreadFilterVal = $('#ThreadFilter').val();
        let MemberLink = GetMemberLink(currentThread);

        ThreadIgnoreText = "";
            UserIgnoreText = "";
    	if ($(currentThread).has("a[id*='RemoveThread" + nThreadID + "']").length == 0)
	    {

            let RemoveUserLinks = $('a[id*=RemoveUser' + nUserID + ']').toArray();

    		sUserIDReference = (RemoveUserLinks.length > 0) ? nUserID + RemoveUserLinks.length : nUserID;

            $('#RemoveUser' + sUserIDReference).click({param1: nUserID, param2: 'IgnoredUserList', param3: UpdateThreads, param4: currentThread}, IgnoreItem);


            let removeThreadElement = '<a id="RemoveThread' + nThreadID + '">' + ThreadIgnoreText + '</a>';
            $($(currentThread).find('.structItem-title a')).after(removeThreadElement);

            $('#RemoveThread' + nThreadID).click({param1: nThreadID, param2: 'IgnoreList', param3: UpdateThreads, param4: currentThread}, IgnoreItem);
    	}
    	else
        {
            $('#RemoveThread' + nThreadID).text(ThreadIgnoreText);
            $('a[id*=RemoveUser' + nUserID).text(UserIgnoreText + " User");
        }
}


function CreateEventHandlers()
{
    $('#ThreadFilter').change(function() { UpdateThreads(); UpdateHideLinks();});
    $('#OpenFilterCP').click(OpenFilterCP);
    $('#AddWordButton').click(AddToWordFilter);
    $('#AddIgnoredUserButton').click(AddToIgnoredUserList);
    $('input[name="HideLinkStyle"]').change(function () { localStorage.setItem('HideLinkStyle', this.value); RemoveHideLinks(); SaveLastUpdate();});
    $('#SearchAdditional').change(function() { localStorage.setItem('SearchAdditional', this.checked); SaveLastUpdate();});
    //$('#CloudSync').change(function() { localStorage.setItem('CloudSync', this.checked); ShowCloudSyncOptions(this); });
    //$('#CloudSyncFrequency').change(function() { localStorage.setItem('CloudSyncFrequency', this.value); SaveLastUpdate(); });
    //$('#CloudSyncKey').change(function() {CloudKeyChanged(this.value);});
    //$('#GenerateCloudSyncKey').click(GenerateCloudSyncKey);
    $('#ThreadExpiration').change(function() { localStorage.setItem('ThreadExpiration', this.checked); if (localStorage.getItem('ExpirationDays') == null) {localStorage.setItem('ExpirationDays',30); 	document.getElementById("ExpirationDays").value = localStorage.getItem("ExpirationDays");} $('#ThreadExpirationOptions').toggle(); SaveLastUpdate(); });
	$('#ExpirationDays').change(function() {localStorage.setItem('ExpirationDays', this.value);});
}

function RemoveHideLinks()
{
    $("a[id*='RemoveThread']").remove();
    $("a[id*='RemoveUser']").remove();

    $("#RemoveStyle").remove();

    if (localStorage.getItem("HideLinkStyle") != "HideShow")
    	$("body").append(GetRemoveStyle());
}

function SetOptions()
{
    document.getElementById("ThreadFilter").value = CheckThreadFilterValue(localStorage.getItem("ThreadFilter"));

    //if (localStorage.getItem("CloudSyncKey"))
    //    document.getElementById("CloudSyncKey").value = localStorage.getItem("CloudSyncKey");

    if (!localStorage.getItem("HideLinkStyle"))
        localStorage.setItem("HideLinkStyle","X");

	if (localStorage.getItem("ExpirationDays"))
		document.getElementById("ExpirationDays").value = localStorage.getItem("ExpirationDays");

    CheckSettingOption("SearchAdditional");
    //CheckSettingOption("CloudSync");
    CheckSettingOption("HideLinkStyle");
	CheckSettingOption("ThreadExpiration");

    $('#ThreadExpirationOptions').css('display',$('#ThreadExpiration').prop('checked') ? 'block' : 'none');
}

function UpdateThreads()
    {
      shownCount = 0;
      $('#ThreadFilter').blur();
      localStorage.setItem('ThreadFilter',document.getElementById("ThreadFilter").value);
      currentVisibleThreads = [];

      $(GetThreads()).each(function(index)
        	{
    	 	 nThreadID = GetThreadID(this);
    	 	 threadTitle = GetThreadTitle(this);
             sUserID = GetUserID(this);

             if (CheckThreadHidden(nThreadID,threadTitle,sUserID))
             {
                 $(this).hide();
                 }
             else
             {
                 currentVisibleThreads.push(nThreadID);
                 shownCount++;

                 $(this).show();
             }
    	});

        if (localStorage.getItem("SearchAdditional") == "true")
        {
            pageCount = originalPageCount;
            GetAdditionalThreads();
        }

}



function GetAdditionalThreads()
{

    if (shownCount < threadsPerPage && pageCount <= (parseInt(originalPageCount) + 5))
    {
        let nextPageURL = window.location.href.replace(/page-\d*/i,'') + "page-" + pageCount;

        var jqxhr = $.get(nextPageURL, ProcessAdditionalThread)
    	.done(function() {
        pageCount++;
        GetAdditionalThreads();
  	});
    }
}

function ProcessAdditionalThread(data)
{
	    var lastThread = $(GetThreads()).last();
        let foundThreads = [];

        $(GetThreads(data)).each(function(index, value)
       	{
            nThreadID = GetThreadID(this);
        	threadTitle = GetThreadTitle(this);
        	sUserID = GetUserID(this);

        	additionalThreadCount = additionalThreadCount + 1;

            if (!CheckThreadHidden(nThreadID, threadTitle, sUserID) && shownCount < threadsPerPage && $.inArray(nThreadID,currentVisibleThreads) == -1)
            	{
                    lastThread = $(lastThread).after(this);
                    foundThreads.push(this);

    	    	AddHideLink(this);
            	shownCount++;
            	}

        });

        
}

function CheckThreadFilterValue(sFilterValue)
{
    if (sFilterValue != "Unignored" && sFilterValue != "Ignored" && sFilterValue != "All")
        sFilterValue = "Unignored";

    return sFilterValue;
}

function IgnoreItem(event) {
    var nCurrentID = event.data.param1;
    var sList = event.data.param2;
    var addItem = {};
    addItem.ID = nCurrentID;
    addItem.AddDate = new Date();

    if (sList == "IgnoreList")
        addItem.Title = GetThreadTitle(event.data.param4);
    else if (sList == "IgnoredUserList")
        addItem.Username = GetThreadStarterUsername(event.data.param4);

    CurrentList = GetListFromLocalStorage(sList);

    containsObject(nCurrentID,CurrentList,addItem);

    localStorage.setItem(sList, JSON.stringify(CurrentList));

    if (event.data.param3)
    	event.data.param3();

    AddHideLink(event.data.param4);
    IgnoreItemServerSide(nCurrentID);
    SaveLastUpdate();

    CheckCloudUpdateNeeded();




    return 0;
}

function IgnoreItemServerSide(threadID)
{
    var token = $('[name="_xfToken"]')[0].value;
    var data = {
        '_xfRequestUri': '/threads/',
        '_xfWithData': '1',
        '_xfToken': token,
        '_xfResponseType': 'json'};


    $.ajax({
  type: "POST",
  url: 'https://www.resetera.com/misc/tic-ignore?content_type=thread&is_confirmed=1&content_id=' + threadID,
  data: data,
  success: function( data ) {
console.log('Ignored thread #' + threadID + ' on server side', data);
}
});


}


function CheckThreadHidden(nThreadID, sThreadTitle,sUserID)
{
    	var sThreadFilterVal = $('#ThreadFilter').val();
    	var bWordFilterApplies = false;
    	var bUserFilterApplies = false;

    	IgnoreList = GetListFromLocalStorage('IgnoreList');
    	nThreadIndex = containsObject(nThreadID,IgnoreList);

    	var bThreadIgnored = (nThreadIndex == -1) ? false : true;

        if ((bThreadIgnored && sThreadFilterVal == 'Unignored'))
        {
            return true;
        }
        else
        {
            bWordFilterApplies = WordFilterApplies(sThreadTitle);

            if (bWordFilterApplies && sThreadFilterVal == 'Unignored')
          	{
              	return true;
           	}
            else
           	{
                bUserFilterApplies = containsObject(sUserID,GetListFromLocalStorage('IgnoredUserList')) != -1 ? true : false;

                if (bUserFilterApplies && sThreadFilterVal == 'Unignored')
             	{
                    return true;
             	}
                else if (!bThreadIgnored && !bWordFilterApplies && !bUserFilterApplies && sThreadFilterVal == 'Ignored')
             	{
                 	return true;
             	}
           	}

        }

    return false;
}

function WordFilterApplies(sThreadTitle)
{
    CurrentArea = GetCurrentArea();

    var bFilterApplies = false;
	WordList = GetListFromLocalStorage('WordList');

	jQuery.each(WordList,function (index)
	{

        if (this.Area == null || this.Area == 'All' || this.Area == CurrentArea)
        {
        if (this.Type == 'plaintext')
		{
			sFragments = this.Word.split('*');

			bMatchesPattern = true;

            jQuery.each(sFragments, function(index)
			{
				if (sThreadTitle.toLowerCase().indexOf(this.toLowerCase()) == -1)
				{
					bMatchesPattern = false;
				}
			});

			if (bMatchesPattern === true)
        	{
        		bFilterApplies = true;
				return 0;
        	}
		}
		else if (this.Type == 'regularexpression')
		{
			sRegExMatches = sThreadTitle.match(this.Word);

			if (sRegExMatches)
            	{
                	bFilterApplies = true;
                	return 0;
            	}
		}
            }
    });

    return bFilterApplies;
 }


function GetCurrentArea()
{
    CurrentLocation = window.location.href;

    if (CurrentLocation.indexOf("etcetera-forum.9") != -1 || CurrentLocation.indexOf("etcetera-hangouts.10") != -1)
        return "EtcetEra";
    else if (CurrentLocation.indexOf("gaming-forum.7") != -1 || CurrentLocation.indexOf("gaming-hangouts.8") != -1)
    	return "Video Games";

}

function AddToWordFilter(event) {
    newWord = $('#AddWordText').val();

    var addWord = {};
    addWord.Word = newWord;
    addWord.Type = $('input[name*=AddWordType]:checked').val();
    addWord.Area = $('input[name*=AddWordArea]:checked').val();

    WordList = GetListFromLocalStorage('WordList');
    nWordIndex = containsObject(addWord.Word, WordList);

    if (nWordIndex == -1) {

        WordList.push(addWord);
    }

    localStorage.setItem('WordList', JSON.stringify(WordList));
    $('#AddWordText').val('');
    $('input[name="AddWordArea"][value="All"]').prop('checked', true);
    UpdateListing('WordListing', 'WordList');

    localStorage.setItem("LastUpdate",new Date());
    CheckCloudUpdateNeeded();

}

function AddToIgnoredUserList(event) {
    newIgnoredUserText = $('#AddIgnoredUserText').val();

    var addIgnoredUser = {};
    addIgnoredUser.Username = newIgnoredUser;

    IgnoredUserList = GetListFromLocalStorage('IgnoredUserList');
    nIgnoredUserIndex = containsObject(addIgnoredUser.Username, IgnoredUserList);

    if (nIgnoredUserIndex == -1) {
        IgnoredUserList.push(addIgnoredUser);
    }

    localStorage.setItem('IgnoredUserList', JSON.stringify(IgnoredUserList));
    $('#AddIgnoredUserText').val('');

    UpdateListing('IgnoredUserListing', 'IgnoredUserList');

    localStorage.setItem("LastUpdate",new Date());
    CheckCloudUpdateNeeded();

}

function CreateControlPanel()
{
      var sControlPanel = GetControlPanel();

    $(filterAnchorElementSelector).parent().append(sControlPanel);
    $(filterAnchorElementSelector).parent().append($('<span class="nodeListNewDiscussionButton"><a id="OpenFilterCP" class="callToAction FilterCP">Filter Control Panel</a></span>'));
    $('.TabLinksContainer div a').click(ControlPanelTabClicked);

    AddTitleBarSpacer();
}

function GetControlPanel()
{
    var sControlPanel = "<div id='tabs' style='display:none;'>";
    sControlPanel += "<div class='TabLinksContainer RowOrdering'>";
    sControlPanel += "<div><a id='1' class='SelectedTabLink' href='javascript:void(0)'>Word Filter</a></div>";
  sControlPanel += "<div><a id='2' href='javascript:void(0)'>Ignored Threads</a></div>";
  sControlPanel += "<div class='DisabledFeature'><a id='3' href='javascript:void(0)'>Ignored Users</a></div>";
  sControlPanel += "<div><a id='4' href='javascript:void(0)'>Settings</a></div>";
  sControlPanel += "</div>";
    sControlPanel += "<div id='tabs-1'>";
  sControlPanel += CreateWordFilter();
  sControlPanel += "</div>";
  sControlPanel += "<div id='tabs-2' class='HiddenTab'>";
  sControlPanel += "<div id='RecentlyIgnoredListing'></div>";
  sControlPanel += "</div>";
  sControlPanel += "<div class='DisabledFeature' id='tabs-3' class='HiddenTab'>";
  sControlPanel += CreateIgnoredUserTab();
  sControlPanel += "</div>";
    sControlPanel += "<div id='tabs-4' class='HiddenTab'>";
  sControlPanel += CreateSettingsOptions();
  sControlPanel += "</div>";
  sControlPanel += "</div>";

  return sControlPanel;
}

function ControlPanelTabClicked()
{
    $('#tabs div[id*="tabs-"]').addClass('HiddenTab');
    $('#tabs div[id="tabs-' + this.id + '"]').removeClass('HiddenTab');

    $('.TabLinksContainer a').removeClass('SelectedTabLink');
    $('.TabLinksContainer div a[id="' + this.id + '"]').addClass('SelectedTabLink');
}

function OpenFilterCP()
    {
    	UpdateListing('WordListing', 'WordList');
        UpdateListing('RecentlyIgnoredListing', 'IgnoreList');
        UpdateListing('IgnoredUserListing', 'IgnoredUserList');
        //ShowCloudSyncOptions();

        let tabsContainer = $('#tabs');
         $('#tabs').dialog();
         $('#tabs').bind('dialogclose', function(event) { CheckExpiredThreads();	UpdateThreads(); UpdateHideLinks(); });
    	 $('#tabs').dialog({ title: "Filter Control Panel", closeText:""});
         $("#tabs").dialog("option", "width", '60%');
    }


function CreateWordFilter()
{
    sWordFilter = "<div id='WordFilter'>";
    sWordFilter += "<span class='BoldText'>Add New Word:</span>&nbsp;<input id='AddWordText'><input type='button' id='AddWordButton' value='Add'><br /><br />";
    sWordFilter += "<div style='margin-left:20px'><span class='BoldText'>Type</span> - <input type='radio' name='AddWordType' value='plaintext' checked>Plain Text (* supported)<input type='radio' name='AddWordType' value='regularexpression'>Regular Expression</div><br />";
    sWordFilter += "<div style='margin-left:20px'><span class='BoldText'>Area</span> - <input type='radio' name='AddWordArea' value='All' checked>All <input type='radio' name='AddWordArea' value='Video Games'>Video Games <input type='radio' name='AddWordArea' value='EtcetEra'>EtcetEra</div>";
    sWordFilter += "<br /><br /><hr width='100%' color='black'><div id='WordListing'></div>";
    sWordFilter += "</div>";

    return sWordFilter;
}

function CreateIgnoredUserTab()
{
    sIgnoredUserTab = "<hr width='100%' color='black'><div id='IgnoredUserListing'></div>";

    return sIgnoredUserTab;
}

function CreateSettingsOptions()
{
    sCreateSettings = "<span class='DisabledFeature'><span class='BoldText'>Hide Link Style</span><br /><input type='radio' name='HideLinkStyle' checked='true' value='X'>X <input type='radio' name='HideLinkStyle' value='HideShow'>Hide/Show<br /><br /></span>";
    sCreateSettings += "<input type='checkbox' id='SearchAdditional' checked='true'>Search additional pages for threads</input>";

	sCreateSettings += "<br />";
    sCreateSettings += "<input type='checkbox' id='ThreadExpiration'>Thread Expiration</input>";
    sCreateSettings += "<div id='ThreadExpirationOptions' style='display:none;margin-left:30px'>";
    sCreateSettings += "Remove threads from filter after <select id='ExpirationDays'>";

	for (var i = 1; i < 31; i++)
		sCreateSettings += "<option>" + i +"</option>";

	sCreateSettings += "</select> day(s).";
    sCreateSettings += "</div>";

    //sCreateSettings += "<span><br />";
    //sCreateSettings += "<input type='checkbox' id='CloudSync'>Cloud sync</input>";
    //sCreateSettings += "<br /><div id='CloudSyncOptions' style='display:none;float:left;margin-left:30px'><br />";
    //sCreateSettings += "Update Frequency:<br />";
    //sCreateSettings += "<select id='CloudSyncFrequency'>";
    //sCreateSettings += "<option value='Instant'>Instant</option>";
    //sCreateSettings += "<option value='1'>1 minute</option>";
    //sCreateSettings += "<option value='5'>5 minutes</option>";
    //sCreateSettings += "<option value='10'>10 minutes</option>";
    //sCreateSettings += "</select>";

    //sCreateSettings += "<br /><br />Sync Key:";
    //sCreateSettings += "<br /><div style='float:left'><input id='CloudSyncKey'></div><div style='float:left;margin-left:15px;vertical-align:middle'><input type='button' id='GenerateCloudSyncKey' value='Generate'></div>";
    //sCreateSettings += "<br /><br /><br />To sync up your settings with the cloud, enter your sync key above.  To create a new key, click the generate button.";
    //sCreateSettings += "<div id='CloudKeyNotFoundMessage' style='display:none;color:red'><br />Sorry, the sync key you entered was not found.  Please try another key or generate a new one.</div>";
    //sCreateSettings += "<div id='LastCloudUpdate' style='display:none;'><br />Last cloud update was at: <span class='BoldText'><div id='LastCloudUpdateTime'></div></span></div>";
    //sCreateSettings += "</div></span>";
    return sCreateSettings;
}

function CheckSettingOption(sSetting)
{
    if (sSetting == "HideLinkStyle")
    	$('input[name="HideLinkStyle"][value="' + localStorage.getItem(sSetting) + '"]').prop('checked', true);
    else
    {
        if (localStorage.getItem(sSetting))
			$("#" + sSetting).attr("checked", localStorage.getItem(sSetting) == "true" ? true : false);
        else if (sSetting != "CloudSync" && sSetting != "ThreadExpiration")
			localStorage.setItem(sSetting, "true");
    }

}

function UpdateListing(sListingDiv, sListName)
{
	$('#' + sListingDiv).empty();
    CurrentList = GetListFromLocalStorage(sListName);

    if (sListName == 'IgnoreList' || sListName == 'IgnoredUserList')
        CurrentList.reverse();

    var sListingText;

	if (sListName == 'IgnoredUserList')
    	sColumnHeadings = '<td align="center" width="300px"><span class="BoldText">Username</span></td>';
    else if (sListName == 'IgnoreList')
        sColumnHeadings = '<td align="center" width="300px"><span class="BoldText">Title</span></td>';
    else if (sListName == 'WordList')
        sColumnHeadings = '<td align="center" width="200px"><span class="BoldText">Word</span></td><td align="center" width="200px"><span class="BoldText">Type</span></td><td align="center" width="100px"><span class="BoldText">Area</span></td>';

    sListingText = '<table class="ListingTable" width="100%"><tr>' + sColumnHeadings + '<td>&nbsp;</td></tr>';

  	jQuery.each(CurrentList,function (index)
	{
        if (sListName == 'IgnoredUserList')
        	sListingText += '<tr><td align="center"><div style="word-wrap:break-word;width:300px"><a href="' + memberLinkPrefix +  + this.ID + '" target="_blank">' + this.Username + '</a></div></td><td><input type=button id="RemoveIgnoredUser' + this.ID + '" value=Unignore /></td></tr>';
    	else if (sListName == 'IgnoreList')
        	sListingText += '<tr><td align="center"><div style="word-wrap:break-word;width:300px"><a href="' + threadLinkPrefix + this.ID + '" target="_blank">' + this.Title + '</a></div></td><td><input type=button id="RemoveRecentlyIgnored' + this.ID + '" value=Unignore /></td></tr>';
    	else if (sListName == 'WordList')
            sListingText += '<tr><td align="center"><div style="word-wrap:break-word;width:200px">' + this.Word + '</div></td><td align="center">' + this.Type + '</td><td align="center">' + (this.Area != null ? this.Area : 'All') + '</td><td><input type=button id="RemoveWord' + index + '" value=Remove /></td></tr>';

	});

    sListingText += '</table>';

    $('#' + sListingDiv).append(sListingText);

    jQuery.each(CurrentList,function (index)
                {
                    if (sListName == 'IgnoredUserList')
                        $('#RemoveIgnoredUser' + this.ID).click({sCurrentID: this.ID, sListName: 'IgnoredUserList', sListDiv: 'IgnoredUserListing'}, RemoveIgnored);
	    	else if (sListName == 'IgnoreList')
        	            $('#RemoveRecentlyIgnored' + this.ID).click({sCurrentID: this.ID, sListName: 'IgnoreList', sListDiv: 'RecentlyIgnoredListing'}, RemoveIgnored);
    	else if (sListName == 'WordList')
                        $('#RemoveWord' + index).click({sCurrentID: this.Word, sListName: 'WordList', sListDiv: 'WordListing'}, RemoveIgnored);

                });
}


function RemoveIgnored(event) {
    IgnoreList = GetListFromLocalStorage(event.data.sListName);
    nCurrentIndex = containsObject(event.data.sCurrentID,IgnoreList);
    IgnoreList.splice(nCurrentIndex,1);
    localStorage.setItem(event.data.sListName, JSON.stringify(IgnoreList));

    UpdateListing(event.data.sListDiv,event.data.sListName);

    localStorage.setItem("LastUpdate",new Date());
   // CheckCloudUpdateNeeded();
}

function containsObject(id, list, addItem)
{
    if (list.length > 0)
    {
        if (list[0].hasOwnProperty('ID'))
            return binaryIndexOf(id,list,addItem);
        else
        {
	       for (var i = 0; i < list.length; i++)
                if (list[i].ID == id || list[i].Word == id)
                   return i;
        }
    }
    else if (typeof addItem === 'object')
    {
        list.splice(0, 0, addItem);
    }
   	return -1;
}


function binaryIndexOf(id,list,addItem) {
    'use strict';
    var minIndex = 0;
    var maxIndex = list.length - 1;
    var currentIndex;
    var currentElement;

    if (localStorage.getItem("IgnoredThreadsSorted") != "true")
    {
      list = list.sort(sortByID);
      localStorage.setItem("IgnoreList",JSON.stringify(list));
      localStorage.setItem("IgnoredThreadsSorted","true");
    }

    if ((parseInt(id) < parseInt(list[minIndex].ID) || parseInt(id) > parseInt(list[maxIndex].ID)) && typeof addItem === 'undefined')
       return -1;

    while (minIndex <= maxIndex) {
        currentIndex = (minIndex + maxIndex) / 2 | 0;
        currentElement = list[currentIndex].ID;

        if (parseInt(currentElement) < parseInt(id)) {
            minIndex = currentIndex + 1;
        }
        else if (parseInt(currentElement) > parseInt(id)) {
            maxIndex = currentIndex - 1;
        }
        else {
            if (typeof addItem === 'undefined')
                return currentIndex;
            else
            {
                list.splice(currentIndex,1);
                //localStorage.setItem('IgnoreList', JSON.stringify(list));
                writeignored(list);
                return currentIndex;
            }
        }
    }


    if (typeof addItem === 'undefined')
        return -1;
    else
    {
        list.splice(minIndex, 0, addItem);
    }
}

function writeignored(list)
{
    for (var i = 0; i < list.length; i++)
        console.log(list[i].ID);
}

function sortByID(a, b)
{
    return a.ID - b.ID;
}


function GetNextPage()
{
    var str = window.location.href;
	var res = str.match("page-[0-9]+");

    if (res)
        	return parseInt(res[0].replace("page-","")) + 1;
    else
            return 2;

}

function GetListFromLocalStorage(sListName)
{
     return localStorage.getItem(sListName) ? JSON.parse(localStorage.getItem(sListName)) : [];
}

function CheckExpiredThreads()
{
	if (localStorage.getItem("ThreadExpiration") == "true")
	{
        if (!localStorage.getItem("LastExpirationCheck"))
                localStorage.setItem("LastExpirationCheck",new Date());

        var checkexpirationdate = new Date(localStorage.getItem("LastExpirationCheck"));
        checkexpirationdate.setDate(checkexpirationdate.getDate() + 1);

        if (new Date() >= checkexpirationdate)
            {
                var madechange = false;
                var expirationdays = parseInt(localStorage.getItem("ExpirationDays"));
                var threadexpiration;

                ignoreList = GetListFromLocalStorage('IgnoreList');

                for (i = 0; i < ignoreList.length; i++)
                {
                    if (typeof ignoreList[i].AddDate === 'undefined')
                    {
                        ignoreList[i].AddDate = new Date();
                        madechange = true;
                    }
                    else
                    {
                        threadexpiration = new Date(ignoreList[i].AddDate);
                        threadexpiration.setDate(threadexpiration.getDate() + expirationdays);

                        if (new Date() >= threadexpiration)
                        {
                            ignoreList.splice(i,1);
                            madechange = true;
                        }
                    }
                }

                if (madechange == true)
                {
                    localStorage.setItem("IgnoreList",JSON.stringify(ignoreList));
                    SaveLastUpdate();
                    CheckCloudUpdateNeeded();
                }

                localStorage.setItem("LastExpirationCheck",new Date());
            }

	}
}

var Type = "POST";
var URL;
var URLPrefix = "";
var Data = {};
var ContentType = "application/json; charset=utf-8";
var DataType = "json";

function CheckCloudSync()
{
    if (localStorage.getItem("CloudSync") == "true" && localStorage.getItem("CloudSyncKey"))
    {
	CheckCloudUpdateNeeded();

        if (localStorage.getItem("CloudSyncFrequency") != 'Instant')
 	setInterval(CheckCloudUpdateNeeded, 1000 * 60);
    }
}

function GetCloudSyncDateSucceeded(result)
{
    if (!localStorage.getItem("CloudSyncFrequency"))
            localStorage.setItem("CloudSyncFrequency","5");

    currentDate = new Date();

    if (localStorage.getItem("CloudSyncFrequency") != 'Instant')
    {
    	nextDate = new Date(localStorage.getItem("CloudSyncDate"));
    	nextDate.setTime(nextDate.getTime() + parseInt(localStorage.getItem("CloudSyncFrequency")) * 60 * 1000);
    }
    else
        nextDate = currentDate;

    date2 = localStorage.getItem("CloudSyncDate") ? new Date(localStorage.getItem("CloudSyncDate")) : new Date();
    date1 = new Date(result);

    if (result != 'None')
    {
        CloudKeyFound();

        if (!result || (result && localStorage.getItem("CloudSyncDate") && date2 > date1) || (currentDate >= nextDate && new Date(localStorage.getItem("LastUpdate")) > new Date(localStorage.getItem("CloudSyncDate"))))
       	    SendInfoToCloud(new Date());
    	else if (!localStorage.getItem("CloudSyncDate") || (result && localStorage.getItem("CloudSyncDate") && date1 > date2))
    	    GetInfoFromCloud();
    }
    else if (localStorage.getItem("CloudSyncKey"))
        CloudKeyNotFound();

}

function ShowCloudSyncOptions()
{
    $('#CloudSyncOptions').css('display',$('#CloudSync').prop('checked') ? 'block' : 'none');

    if (!localStorage.getItem('CloudSyncFrequency'))
        localStorage.setItem('CloudSyncFrequency','5');

    $('#CloudSyncFrequency').val(localStorage.getItem('CloudSyncFrequency'));
}


function GetInfoFromCloud()
{
	URL = "GetHideForumThreadsInfoNew?Key=" + localStorage.getItem("CloudSyncKey");
        Data = "";
        CallService(GetHideForumThreadsInfo);
}

function GetHideForumThreadsInfo(result) {
    if (result.CloudSyncDate != null)
    {
    localStorage.setItem("CloudSyncDate",result.CloudSyncDate);
    localStorage.setItem("SearchAdditional",result.SearchAdditional);
    localStorage.setItem("ThreadFilter",result.ThreadFilter);
    localStorage.setItem("IgnoredThreadsSorted",result.IgnoredThreadsSorted);
    localStorage.setItem("ThreadExpiration",result.ThreadExpiration);
    localStorage.setItem("ExpirationDays",result.ExpirationDays);
    localStorage.setItem("LastExpirationCheck",result.LastExpirationCheck);
    localStorage.setItem("IgnoredUserList",result.IgnoredUserList);
    localStorage.setItem("IgnoreList",result.IgnoreList);
    localStorage.setItem("WordList",result.WordList);
    localStorage.setItem("HideLinkStyle",result.HideLinkStyle);

    console.log("info received from cloud",result);

    SetOptions();
    RemoveHideLinks();

    CloudKeyFound();
    }
    else
        CloudKeyNotFound();


}

function SaveLastUpdate()
{
	localStorage.setItem("LastUpdate",new Date());
}

function CloudKeyChanged(CurrentKey)
{
    localStorage.setItem("CloudSyncKey",CurrentKey);

    if (CurrentKey != '')
        GetInfoFromCloud();
    else
        CloudKeyNotFound();
}

function CloudKeyFound()
    {
        $('#CloudKeyNotFoundMessage').hide();
        ShowLastCloudUpdate();

    }

function CloudKeyNotFound()
    {
        $('#CloudKeyNotFoundMessage').show();
        $('#LastCloudUpdate').hide();
     }



function ShowLastCloudUpdate()
{
    document.getElementById("LastCloudUpdateTime").innerHTML = localStorage.getItem("CloudSyncDate");
    $('#LastCloudUpdate').show();
}

function GenerateCloudSyncKey()
{
    localStorage.setItem("CloudSyncKey","None");
    SendInfoToCloud(new Date());
}

function SendInfoToCloud(currentDate)
{
    localStorage.setItem("CloudSyncDate",currentDate);

$.ajax({
  url: URLPrefix + "UpdateHideForumThreadsInfoNew",
  type: "POST",
    data: {Key:localStorage.getItem("CloudSyncKey"),
           CloudSyncDate: currentDate,
           SearchAdditional: localStorage.getItem("SearchAdditional") ? localStorage.getItem("SearchAdditional") : "",
           ThreadFilter: localStorage.getItem("ThreadFilter") ? localStorage.getItem("ThreadFilter") : "",
           IgnoredThreadsSorted: localStorage.getItem("IgnoredThreadsSorted") ? localStorage.getItem("IgnoredThreadsSorted") : "",
           ThreadExpiration: localStorage.getItem("ThreadExpiration") ? localStorage.getItem("ThreadExpiration") : "",
           ExpirationDays: localStorage.getItem("ExpirationDays") ? localStorage.getItem("ExpirationDays") : "",
           LastExpirationCheck: localStorage.getItem("LastExpirationCheck") ? localStorage.getItem("LastExpirationCheck") : "",
           IgnoredUserList: localStorage.getItem("IgnoredUserList") ? localStorage.getItem("IgnoredUserList") : "[]",
           IgnoreList: localStorage.getItem("IgnoreList") ? localStorage.getItem("IgnoreList") : "[]",
           WordList: localStorage.getItem("WordList") ? localStorage.getItem("WordList") : "[]",
           HideLinkStyle: localStorage.getItem("HideLinkStyle") ? localStorage.getItem("HideLinkStyle") : "X",
           Username: GetUsername()},
  success: Success,
  dataType: "json",
  error: ServiceFailed

});

}

function GetUsername()
{
    Username = $('#usercptools').text().replace('Welcome ','');

    UsernamePattern = new RegExp("([A-Za-z0-9]+)");
   FoundUsername = UsernamePattern.exec(Username);

    if (FoundUsername != null)
    	return FoundUsername[0].toString();
    else
        return "None";
}

function Success(result)
{
    localStorage.setItem("CloudSyncKey", result);
    document.getElementById("CloudSyncKey").value = localStorage.getItem("CloudSyncKey");
    CloudKeyFound();
    console.log("info sent to cloud");
}

function CheckCloudUpdateNeeded()
{
    if (localStorage.getItem("CloudSync") == "true" && localStorage.getItem("CloudSyncKey"))
    {
        URL = "GetCloudSyncDate?Key=" + localStorage.getItem("CloudSyncKey");
        CallService(GetCloudSyncDateSucceeded);
    }
}

// Function to call WCF  Service
function CallService(succeededcallback) {
    $.ajax({
        type: Type, //GET or POST or PUT or DELETE verb
        url: URLPrefix + URL, // Location of the service
        contentType: ContentType, // content type sent to server
        dataType: DataType, //Expected data format from server
        data: Data,
        processdata: true, //True or False
        success: function(msg) {//On Successful service call
	indirectCaller(succeededcallback,msg);
        },
        error: ServiceFailed// When Service call fails
    });
}

function ServiceFailed(xhr) {
    console.log('error - ' + xhr.responseText);

    if (xhr.responseText) {
        var err = xhr.responseText;
        if (err)
            error(err);
        else
            error({ Message: "Unknown server error." })
    }
    return;
}

function indirectCaller(f,msg) {
    // Call `caller`, who will in turn call `f`
    f(msg);
}