ResetEra - Hide Forum Threads

Hides threads on resetera.com

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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);
}