';
$.each(AVE.Modules, function () {
if ($.inArray(this.ID, _this.Modules) === -1) {
_this.Modules.push(this.ID);
}
});
this.Modules.sort();
this.AppendToPage();
this.Listeners();
},
MngWinStyle: '',
MngWinHTML: '',
ModuleHTML: '',
Categories: ["General", "Subverse", "Thread", "Posts", "Domains", "Account", "Style", "Misc", "Manager", "ModTools"],//Available Categories to show
Modules: [],//List of modules
ModifiedModules: [],//Modules whose options have been modified and should be saved
AppendToPage: function () {
AVE.Utils.AddStyle(this.MngWinStyle);
var LinkHTML;
if ($("span.user:contains('Manage')").length > 0) {
LinkHTML = 'AVE| ';
$(LinkHTML).insertBefore("span.user:contains('Manage')");
} else { //If the user isn't logged in
LinkHTML = ' - AVE';
$(LinkHTML).insertAfter("span.user:first");
}
},
Listeners: function () {
var _this = this;
$("a[title='AVE Preference Manager']").on("click", function () {
if ($(".MngrWin").length > 0) {
$(".MngrWin").show();
}
else { _this.BuildManager(); }
$(".overlay").show();
$("body").css("overflow", "hidden");
});
$(window).on("keyup", function (e) {
if (e.which === 27 && $(".MngrWin#MngWin").is(":visible")) {
var val = $(e.target).attr("value");
if (!($(e.target).is(":button") && (val))) {
$("#CloseWinMngr").click();
}
}
});
},
BuildManager: function () {
var _this = this;
var MngWinHTML = _this.MngWinHTML.replace('@{version}', AVE.Utils.MetaData.version);
$(MngWinHTML).appendTo("body");
$(".MngrWin").show();
$.each(_this.Categories, function () {
//Make it into a function to be used more easily by the reset function
var cat = this;
//Create category togglers
$("section#ModuleSectionToggles").append('
' + cat + '
');
//Insert all category sections
$("section.ModulePref").append('');
$("form[cat='" + cat + "']").hide();
//And populate them
var module;
$.each(_this.Modules, function () {
module = AVE.Modules[this];
if (module.Category != cat) { return; }
_this.AddModule(module, cat);
});
});
$("div.ModuleToggle").on("click", function () {
$("div.ModuleToggle").each(function () {
$(this).css("border-top-right-radius", "");
$(this).css("border-bottom-right-radius", "");
$(this).css("border-right", "");
$(this).css("margin-right", "10px");
$("form[cat*='" + $(this).text() + "']").hide();
});
$(this).css("border-top-right-radius", "0px");
$(this).css("border-bottom-right-radius", "0px");
$(this).css("border-right", "0px");
$(this).css("margin-right", "0px");
$("form[cat*='" + $(this).text() + "']").show();
});
$("div.ModuleToggle:first").click();
//Show changelog when clicking the version number
$("span#AVE_Version").on("click", function () {
if (AVE.Modules['VersionNotifier'] && !$("div.VersionBox").is(":visible")) {
AVE.Modules['VersionNotifier'].Trigger = "changelog";
AVE.Modules['VersionNotifier'].Start();
$("p.VersionBoxToggle").click();
}
});
//Exit the prefMngr
$("#CloseWinMngr").on("click", function (event) {
if (_this.Options.LossChangeNotification.Value && $("div.TopButtons > a#SaveData").hasClass("btn-sub")) {
if (!confirm("You have unsaved changes.\n\nAre you sure you want to exit?"))
{ return; }
}
$(".MngrWin").hide();
$(".overlay").hide();
$("body").css("overflow", "");
event.stopPropagation();
});
//Save Data
$(".MngWinHeader > .TopButtons > a#SaveData").on("click", function () {
var moduleForms = $("form[cat] > div.ModuleBlock");
_this.SaveModule(moduleForms, 0);
});
//Close the pref Manager with a click outside of it.
$(".overlay").on("click", function (e) {
if ($(e.target).attr("class") === "overlay") {
$("#CloseWinMngr").click();
}
});
this.ChangeListeners();
},
ChangeListeners: function () {
var _this = this;
var JqId = $("section.ModulePref");
JqId.find(":input").on("change", function () {
_this.AddToModifiedModulesList($(this).parents("div.ModuleBlock:first").attr("id"));
_this.ToggleSaveButtonActive();
});
JqId.find("input").on("input", function () {
_this.AddToModifiedModulesList($(this).parents("div.ModuleBlock:first").attr("id"));
_this.ToggleSaveButtonActive();
});
JqId.find("a").on('click', function () {
_this.AddToModifiedModulesList($(this).parents("div.ModuleBlock:first").attr("id"));
_this.ToggleSaveButtonActive();
});
},
ToggleSaveButtonActive: function () {
if ($("div.TopButtons > a#SaveData").hasClass("btn-sub")) { return; }
//$("section.ModulePref").find("input").off("change"); //Can't use off here because it removes custom event listeners
$("div.TopButtons > a#SaveData").addClass("btn-sub")
.removeClass("btn-unsub");
//if save btn has btn-sub class prompt confirmation
},
AddToModifiedModulesList: function (ID) {
if ($.inArray(ID, this.ModifiedModules) === -1) {
this.ModifiedModules.push(ID);
}
},
SaveModule: function (ModuleFormsList, idx) {
var _this = this;
var module = ModuleFormsList[idx];
var ModKey = $(module).attr("id");
if (!ModKey) { return;}
if ($.inArray(ModKey, this.ModifiedModules) !== -1) {
$("div.TopButtons > a#SaveData").text("Saving " + ModKey);
var POST = {};
POST[ModKey] = {};
$(module).find(":input").each(function () {
var key = $(this).prop("id");
if ($(this).is("button")){return true;}
else if (key === AVE.Modules[ModKey].Name) {POST[ModKey].Enabled = $(this).is(":checked");}
else if (key === "") { /* continue/pass */ }
else if ($(this).attr("type") && $(this).attr("type").toLowerCase() === "checkbox") {
POST[ModKey][key] = $(this).is(":checked");
} else {
POST[ModKey][key] = $(this).val();
}
});
//Send new pref to module
if (AVE.Modules[ModKey] && typeof AVE.Modules[ModKey].SavePref === "function") {
AVE.Modules[ModKey].SavePref(POST);
} else { print("AVE: error saving module " + ModKey); }
}
idx++;
if (idx < ModuleFormsList.length) {
if ($.inArray(ModKey, this.ModifiedModules) !== -1) {
//Just enough delay to notice the saving process
setTimeout(function () { _this.SaveModule(ModuleFormsList, idx); }, 50);
} else {
//Don't set a time out if the previous module didn't need to be saved
_this.SaveModule(ModuleFormsList, idx);
}
} else {
this.ModifiedModules = [];
$("div.TopButtons > a#SaveData").text("Save Changes")
.removeClass("btn-sub")
.addClass("btn-unsub");
$("#CloseWinMngr").click();
}
},
AddModule: function (module, cat, pos) {
var _this = this;
var enabled, alwaysEnabled;
if (module.Options.Enabled) {
enabled = module.Options.Enabled.Value;
alwaysEnabled = false;
}
else {
//If Module.Enabled doesn't exist, that means it cannot be deactivated
enabled = true;
alwaysEnabled = true;
}
var html =
'
';
if (pos === undefined) {
$("form[cat='" + cat + "']").append(html);
} else {
if (pos > 0) { //if the position isn't first of its category
$(html).insertAfter("form[cat='" + cat + "'] > div.ModuleBlock:nth(" + (pos - 1) + ")");
} else {
if ($("form[cat='" + cat + "'] > div.ModuleBlock").length > 0) {
$(html).insertBefore("form[cat='" + cat + "'] > div.ModuleBlock:nth(0)");
} else { //if it is alone in its category
$(html).appendTo("form[cat='" + cat + "']");
}
}
}
//Get special form element from the modules themselves.
if (typeof module.AppendToPreferenceManager === "object") {
if (typeof module.AppendToPreferenceManager.html === "function") {
var JqId = $("form[cat='" + cat + "']").find("div[id='" + module.ID + "']");
JqId.append('');
try {
html = module.AppendToPreferenceManager.html();
JqId.find("div.AVE_ModuleCustomInput").append(html);
if (typeof module.AppendToPreferenceManager.callback === "function") {
module.AppendToPreferenceManager.callback();
}
}
catch (e) {
if(!AVE.Utils.DevMode){
print("AVE: PreferenceManager > Error importing custom settings for " + module.ID +"! Aborting.");
JqId.find("div.AVE_ModuleCustomInput").html('Error importing custom settings. Operation aborted.');
} else {
console.error(e);
}
}
}
}
if (typeof module.ResetPref === "function") {
//Event listener to reset the module's data
$("div.ModuleBlock[id='" + module.ID + "'] > a#ResetModule").on("click", function () {
var ID = $(this).parent().attr('id');
var position = $(this).parents(".ModuleBlock:first").index();
var category = $(this).parents("form:first").attr("cat");
$(this).parents(".ModuleBlock:first").remove();
AVE.Modules[ID].ResetPref();
//_this.SaveModule(ID);
_this.AddModule(AVE.Modules[ID], category, position);
});
}
$("div.ModuleBlock[id='" + module.ID + "'] > div.ModuleTitleBlock > input.ToggleEnable").change(function () {
var JqId = $(this).parent().find("span[class*='ModuleState']");
if (this.checked) {
JqId.addClass("Enabled");
JqId.removeClass("Disabled");
} else {
JqId.addClass("Disabled");
JqId.removeClass("Enabled");
}
});
},
AppendToPreferenceManager: {
html: function () {
var _this = AVE.Modules['PreferenceManager'];
var htmlStr = "";
htmlStr += ' ';
htmlStr += ' ';
htmlStr += ' Export all stored data as a JSON file: ';
htmlStr += ' Import settings/data from a JSON file: \
';
htmlStr += 'Reset all data stored: ';
htmlStr += ' ';
return htmlStr;
},
callback: function () {
var _this = AVE.Modules['PreferenceManager'];
$("input#AVE_DevMode").on("change", function () {
var v = $(this).is(":checked");
AVE.Storage.SetValue(AVE.Storage.Prefix+"DevMode", v ? "1": "0");
var lab = $(this).next("label:first");
lab.css("backgroundColor", "rgba(89, 204, 85, 0.5)");
setTimeout(function () {
lab.css("backgroundColor", "");
}, 1500);
});
$("input#AVE_ExportToJSON").on("click", function () {
_this.ExportToJSON();
});
$("input#AVE_ImportFromJSON").on("click", function () {
_this.ImportFromJSON();
});
$("input#AVE_ResetAllData").on("click", function () {
_this.RemoveAllData();
});
$("input#AVE_file_ImportFromJSON").on("change", function (e) {
//var DataReader = new FileReader();
var Data = "";
var f = e.target.files[0];
if (!f) {
return true;
} else if (f.name.substr(f.name.length - 4, 4) !== "json") {//Only plain text/JSON
_this.ShowInfo("The selected file\'s format isn\'t JSON", "failed");
return true;
}
var reader = new FileReader();
reader.addEventListener("load", function (event) {
var textFile = event.target;
Data = JSON.parse(textFile.result);
//trigger copy to Storage
var c = 0;
$.each(Data, function (k, v) {
c++;
if (k.substr(0, 3) !== "AVE") {
print("AVE: importing preferences -> Failed: " + k);
return true;
}
_this.Store.SetValue(k, v);
});
_this.ShowInfo(c + " values copied! Reload to see changes.", "success");
});
reader.readAsText(f);
});
},
},
RemoveAllData: function () {
if (confirm("Are you really sure you want to delete all data stored by AVE?")) {
for (var val in this.Store.Data) { this.Store.DeleteValue(val); }
if (this.Store.Data.length > 0) {
alert("AVE: Reset data > an error occured, not all data were removed.")
} else {
this.ShowInfo("Done!", "success");
}
}
},
ShowInfo: function (text, status) {
var JqId = $("span#AVE_Mng_Info");
JqId.finish();
JqId.show();
JqId.text(text);
JqId.css("color", status == "success" ? "#68C16B" : "#DD5454");
JqId.delay(5000).fadeOut(300);
},
ImportFromJSON: function () {
if (!window.File && !window.FileReader && !window.FileList && !window.Blob) {
alert("AVE: Importing settings and data is not supported by your browser.");
return;
}
$("input#AVE_file_ImportFromJSON").click();
},
ExportToJSON: function () {
try {
var isFileSaverSupported = !!new Blob;
} catch (e) { alert("AVE: Saving settings and data to JSON is not supported by your browser."); return; }
var _this = AVE.Modules['PreferenceManager'];
var data = {};
$.each(_this.Store.Data, function (k, v) { data[k] = v; });
var blob = new Blob([JSON.stringify(data)], { type: "application/json;charset=utf-8" });
saveAs(blob, "AVE_Data_" + (new Date().toLocaleDateString().replace(/\//g, "_")) + ".json");
}
};
/// END Preference manager ///
/// Version notifier: Show a short notification the first time a new version of AVE is used. ///
AVE.Modules['VersionNotifier'] = {
ID: 'VersionNotifier',
Name: 'Version notifier',
Desc: 'Show a short notification the first time a new version of AVE is used.',
Category: 'General',
Index: 0.5,
Enabled: false,
Store: {},
Options: {
Enabled: {
Type: 'boolean',
Value: true
}
},
SavePref: function (POST) {
var _this = this;
_this.Store.SetValue(_this.Store.Prefix + _this.ID, JSON.stringify(POST[_this.ID]));
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = _this.Store.GetValue(_this.Store.Prefix + _this.ID, "{}");
if (Opt != undefined) {
Opt = JSON.parse(Opt);
$.each(Opt, function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
}
_this.Enabled = _this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
//this.Store.DeleteValue(this.Store.Prefix + this.ID + "_Version")
if (this.Enabled) {
if (this.Store.GetValue(this.Store.Prefix + this.ID + "_Version") !== AVE.Utils.MetaData.version) {
this.Start();
}
}
},
Start: function () {
this.AppendToPage();
this.Listeners();
},
LabelNew: "New Version downloaded:",
LabelShow: "Changelog, version",
Trigger: "new",
ChangeLog: [
"V2.36.13.36",
" UpdateAfterLoadingMore:",
" Fixed bug",
" Forgot to remove debug info",
" ContributionDeltas:",
" Fixed bug",
" AccountSwitcher:",
" No longer shows the account you are currently logged-in with",
" General maintenance",
"V2.36.11.33",
" UserTag:",
" Implemented options to choose the vote balance gradient's lower and upper limits",
" Fixed bug with the colour gradient and negative vote balances",
" FixContainerWidth:",
" fixed issue in prefmngr where the width value wasn't displayed when loaded",
" HideSubmissions:",
" Fixed issue with the options that were supposed to hide posts right as they are maked hidden",
" HideUsername:",
" Now starts when the banner is ready",
" Firefox extension:",
" New tabs are opened in the background",
" Chromium extension:",
" Fixed issue in the communication between the main script and the content scripts",
" ToggleCustomStyle:",
" Fixed bug that happened when the MutationObserver was set up after the element of interest was added",
" UserInfoFixedPos:",
" Fixed issue where the user block's width was saved before other modules, that could modify it, were loaded",
"V2.36.9.26",
" IgnoreUsers:",
" Fixed bug in anonimized subverses",
" AppendQuote:",
" Fixed issue where the quote link would be added in the wrong list element",
" The quote link is now inserted as the second element in a post's flat-list",
" UserTag:",
" In the dashboard, the paging options aren't empty by default anymore (shows tags and ignored, but not all votes registered)",
" SelectPost:",
" Fixed critical bug related to the SetOptionsFromPref function",
" HttpWarning:",
" Submission's title attribute replaced with a warning",
" CSSEditor:",
" Fixed scrollbars not appearing",
" AccountSwitcher:",
" Is Enabled by default",
" The Voat icon will now be at the right of the username by default, but can be changed",
" Fixed bug related to a Jquery selector that wouldn't appropriately detect a div's class",
" The manager block element will now be positioned coherently below the account element when the latter is divided",
" The width of the manager block is now set to 200px",
" AccountSwitcher, UserInfoFixedPos, HeaderFixedPos:",
" Added conditonals to catch an error related to the CDN error page",
" Init:",
" Will look for error pages sooner (on head ready)",
"V2.36.8.14",
" PreferenceManager:",
" Fixed issue where buttons are considered inputs and were saved along with the actual options value",
" General:",
" Added a failsafe in the function responsible for loading settings for each module",
" SelectPost:",
" The shortcut I took in this case to save its options was not compatible anymore with the failsafe systems",
" Forgot to clean up after debugging",
"V2.36.8.10",
" Init:",
" If a module crashes when loading it will be automatically deactivated",
" UserTag:",
" Corrected an embarrassing bug that essentially would have prevented new users from using the beta version with a fresh install",
" Fixed an error with the way the migration value was saved (would reset occasionally)",
" HideSubmissions:",
" option to hide a submission after clicking its link",
" ShowSubmissionVoatBalance:",
" Finally working thanks to a script by /u/dubbelnougat",
" PreferenceManager:",
" If a module encounters an error when importing its custom options it will show an error instead of crashing the whole preference manager",
" It is now possible to enable/disable a module by clicking its title",
" ShortKeys:",
" Fixed interference with CSSEditor",
" New feature: CSSEditor",
" First modtool, edit your custom CSS stylesheets from within the page itself (by /u/j_ and /u/dubbelnougat)",
" New feature: httpWarning",
" This module shows a warning for submissions that link to HTTP URL instead of HTTPS(ecure)",
" Added option to choose to show a warning icon and/or change the titles' CSS style",
" Init:",
" Added loading step \"BannerReady\"",
" Moved AVE.Utils.LateSet() to be triggered as soon as Head is loaded",
" New feature: AccountSwitcher",
" Store information for several accounts and switch between them quickly",
" Will start when the header/banner is ready",
" HeaderFixedPos:",
" Fixed issue that prevented this module from working when the module InjectCustomStyle was disabled",
" Optimized JQuery's selectors",
" Will now be loaded when the banner element is ready",
" UserInfoFixedPos:",
" Added back an old feature:",
" The user block smoothly follows the scrolling from its original position,",
" It doesn't stick to the right side anymore, only to the top",
" It will adapt to custom style modifications",
" It will adapt to the window being resized",
" Optimized JQuery's selectors",
" Will now be loaded when the banner element is ready",
"V2.33.18.30",
" New module category: Modtools",
" Misc tools made for helping our dedicated mods (all disabled by default)",
" PreferenceManager:",
" Added category Modtools",
" Renamed category \"Fixes\" to \"Misc\"",
" NeverEndingVoat",
" Parses fetched page and updates the current mail status and CCP/SCP (Module ContributionDeltas is not updated with the new info)",
" \" or a NSFW random subverse\" part is no longer left behind",
" This module will now also activate in user-comments and user-submissions",
" RememberCommentCount:",
" Since user-comments pages can now be read with NeverEndingVoat the process can no longer be repeated twice for the same post ID",
" UpdateAfterLoadingMore:",
" Will now only start and update when the current page is a thread",
" Shortkey:",
" Pressing the expand key in a thread with the OP's self-text submission selected will toggle all media within it",
" Ctrl+Return can be used to submit comments (key non-configurable)",
"V2.33.14.26",
" Many linguistical improvements",
" by LudwikJaniuk",
" General:",
" Changed some print instances to use DevMode",
" FixContainerWidth:",
" Will now start at container DOM ready",
" Domaintag:",
" Forgot to implement the removeTag function",
" Updated code for links to subverse domains (used to be self.sub, now v/sub)",
" General:",
" Implemented DevMode console.log option",
" NeverEndingVoat:",
" Added support for POST info in general",
" Next loaded page will remember info like \"time\", \"page\", \"frontpage=guest\", etc.",
" Utils:",
" Implemented POST info parser",
"V2.33.13.20",
" General:",
" Added support for the new guest frontpage",
" HideSubmissions:",
" Added reference to the key used to hide posts in the preference manager",
" ShortKeys:",
" Added option to open external link with archive.is",
" ArchiveSubmission:",
" Enabled in threads",
"V2.33.11.18",
" ArchiveSubmission:",
" No link added to posts linking to archive.is",
" Added option (def.: false) to archive self-posts",
"V2.33.11.16",
" New feature: ThemeSwitcher",
" Switch between the light and dark themes without reloading",
" HeaderFixedPos & UserInfoFixedPos:",
" Changed rules choosing the best background colour (fallbacks in case it is transparent because of a custom style)",
" New feature: ArchiveSubmission",
" Add a link to open an archived version of the submission link",
" ShortKeys:",
" Linked with HideSubmissions to hide posts with the keyboard (def.: h)",
" Automatically select the next submission after hiding one",
" New feature: HideSubmissions",
" Hide submissions you voted on",
" Hide with H",
" Insert a \"hide\" button",
" If the submission isn't removed as soon as marked hidden, \"hide\" becomes \"unhide\"",
" New feature: SingleClickOpener",
" Adds '[l+c]' link to submissions, opens link and comment pages.",
" Usertags:",
" Dashboard:",
" Fixed issue with tags having no colour value (e.g. only an ignore value)",
" Added options to display data",
" Added vote colour gradient",
" Utils:",
" Fixed bug that prevented AVE from detecting the current page if it was a userpage of someone with an hyphen",
" DomainFilter:",
" Moved to the Domains tab in the prefmanager",
" Linked to the DomainTags module for the ignore feature",
" Enabled in user-submissions and saved pages",
" Shorcuts:",
" Dashboard support",
" Adding your first subverse into the list now replaces the default ones",
" DomainTags:",
" Dashboard support",
" Change box's position so that it doesn't get offscreen",
" Started implementing ignore option (not functional yet)",
" In: dashboard, box",
"V2.29.6.6",
" New feature: DomainTags",
" Choose tags to characterize domains",
" Added possibility to tag subverses too (i.e. domains like: self.whatever)",
" New tab in the PrefMngr: Domains",
" UserTag:",
" Only used data will be saved for optimization's sake. E.g. upvoting someone will no longer save a new and complete UserTagObj but a simple object containing a username and a votebalance",
" Context is a new element saved with the tag. When tagging a user, a link will now be added as context of the tag (permalink to submission or comment)",
" An empty votebalance span is not displayed anymore, this is so that it doesn't show an empty space after the tag/username",
" RememberCommentCount:",
" Comments made by the user will no longer be highlighted",
" Comments made by the user will automatically increment the comment count of the thread",
" Added comment count in user-comment pages (voat.co/user/username/comments)",
" Attempt at fixing a highlighting error related to Voat displaying comment's dates in CET (GMT+1) (can be disabled in the preferences)",
" Changed default highlight colour for the dark theme to #423C3C",
" Dashboard:",
" In the Usertags section, added context entry",
" Added dashboard for Domaintags (empty for the moment)",
" PreferenceManager:",
" You can no longer open several changelogs by clicking the version number multiple times",
" BuilDep.js files",
" Added callback option to SendMessage (postMessage) function",
" Utils:",
" Added new Jquery filter",
"V2.28.3.7",
" Usertag:",
" New option to add a background colour to vote balances (green to red)",
" Added a border radius of 2px to the previous background colour",
" Dashboard:",
" In the Usertags section, modifying the colour is now done with a colour palette",
"V2.28.2.5",
" Dashboard:",
" Displaying the dashboard changes the page's title",
" Usertag: fixed issue with arrow keys changing page even while editing a value",
"V2.28.2.3",
" UserInfoFixedPos:",
" Renamed module and changed its description to be more general",
" Added option to always hide contribution points in the userblock",
"V2.28.1.2",
" Dashboard:",
" Implemented a manager for the Usertag module",
"V2.28.0.2",
" New feature: Dashboard",
" Use it to manage your saved data",
" RememberCommentCount:",
" The purging function will now delete 1/8th of the maximum stored values at once every time this max is reached",
" VersionNotifier:",
" The changelog box can now be closed by pressing \"Escape\"",
"V2.27.0.2",
" RememberCommentCount:",
" Changed default highlight colour for the light theme to #ffffcf",
"V2.27.0.1",
" New feature: RememberCommentCount",
" For all visited threads show the number of new comments since the last time they were opened (and hilight them)",
" ContributionDelta:",
" Replaced browser-specific function with shared one",
"V2.26.1.14",
" ToggleMedia:",
" Fixed bug preventing the module from detecting any media in submissions' pages",
"V2.26.1.13",
" Filter modules:",
" Fixed bug where (starting with two filters) removing the first filter, reloading, adding a new one would have the now first one be erased.",
" Fixed issues with new or modified filters not triggering the PrefMngr's save function",
" NeverEndingVoat",
" Fixed typo that would stop the Load more button from working",
" ContributionDelta:",
" Fixed bug crashing AVE, relative to the use of the 'let' keyword",
"V2.26.1.9",
" FixContainerWidth:",
" Fixed bug that would set the container's width when opening the PrefMngr even when disabled",
" ContributionDeltas:",
" Fixed bug related to the PrefMngr trying to display values related to a user that didn't exist yet",
" UserTag:",
" Quick fix",
" ContributionDeltas:",
" Added option to show mutliple delta in tooltip (hour, day, week)",
"V2.26.0.6",
" New feature: ContributionDeltas",
" Show the difference in contribution points between now and X ago",
" Preference manager:",
" The mngr will now be displayed with full width and height",
" Scrolling is deactivated for the rest of the page while the manager is displayed",
" Press Escape to close the mngr",
" IgnoreUsers:",
" Small optimizations",
" Corrected a CSS value",
" FixContainerWidth:",
" Fixed bug in the setting that stopped the slider from updating the page's width live",
"V2.25.3.6",
" NeverEndingVoat:",
" Fixed a bug related to expando buttons not appearing in Chrome and preventing more modules from updating",
"V2.25.3.5",
" New feature: Domain filter",
" Use filters to remove submissions linking to particular domains",
" InjectCustomStyle:",
" Added option to inject style without removing the original subverse's custom style",
" Added option to inject the external style after the subverse's custom style",
" ToggleCustomStyle:",
" This module will now start when InjectCustomStyle is enabled but RemoveSubverseStyle is set to false",
" UserInfoFixedPost:",
" To reduce bugs and improve compatibility with custom styles the user block is now set once regardless of any scrolling by the user",
" ToggleMedia & NeverEndingVoat:",
" Fixed bug where media in new pages weren't expanded but those already expanded were toggled off and on",
" AppendQuote & ReplyWithQuote:",
" Didn't work anymore because a DOM id has changed and needed to be updated in the code",
" ShortKeys:",
" Expand key:",
" If the window is scrolled below a submission title and its media is being collapsed the view will scroll up just above the title",
" VersionNotifier:",
" Purged all previous changelog entries but the last three versions. Past entries can be found on GitHub",
"V2.24.6.6",
" InjectCustomStyle & ToggleCustomStyle:",
" Thanks to a fix by /u/FuzzyWords these modules will now identify custom styles way faster",
" FixExpandImage:",
" Added back fix for reply box's buttons positioned below the sidebar",
" Init:",
" AVE will now stop loading modules only if the page's title is exactly that of error pages",
" Beware: Choosing an error message as the title of a subverse would be a very efficient way of disabling AVE",
" UserTag:",
" Fixed bug where the vote balance would be updated for the first username found in the self-text when the submission is made in an anonymised subverse",
" Updated source with JSlint recommendations",
"V2.24.2.3",
" New feature: Inject custom style",
" Apply a custom style everywhere on Voat. Choose from a list or input your own CSS from an URL",
" FixExpandImage:",
" Trying a simpler solution to the CSS fix",
" UserInfoFixedPos & HeaderFixedPos",
" Those modules now have more possiblities available when trying to choose a background color.",
" ToggleMedia:",
" Fixed bug where, in threads, media that were expanded when the user loaded more content weren't detected by the module, thus couldn't be collapsed back.",
" FixContainerWidth:",
" The module used to update the container's width when starting the prefMngr even if disabled.",
"V2.23.2.2",
" New feature: Hide username",
" Options to hide or replace references to your username (not in posts)",
" PreferenceManager:",
" Added \"style\" tab",
" Added visual of the saving process",
" In order to save processing time, instead of saving all modules, only those which pref have been modified will be saved now",
" ToggleMedia",
" Corrected fix that prevented module from detecting media in self-text posts"],
AppendToPage: function () {
var CSSstyle = 'div.VersionBox' +
'{background-color: #' + (AVE.Utils.CSSstyle === "dark" ? "292929" : "F6F6F6") + ';' +
'border:1px solid black;' +
'z-index: 1000 ! important;' +
'position:fixed;' +
'right:0px;' +
'top:64px;' +
'width:250px;' +
'font-size:12px;' +
'}' +
'p.VersionBoxTitle' +
'{background-color: ' + (AVE.Utils.CSSstyle === "dark" ? "#575757" : "#D5D5D5") + ';' +
'color: ' + (AVE.Utils.CSSstyle === "dark" ? "#BFBFBF" : "535353") + ';' +
'border-bottom:1px solid ' + (AVE.Utils.CSSstyle === "dark" ? "#6E6E6E" : "#939393") + ';' +
'text-align: center;' +
'font-weight: bold;' +
'}' +
'p.VersionBoxInfo' +
'{' +
'color: ' + (AVE.Utils.CSSstyle === "dark" ? "#AAA" : "#565656") + ';' +
'margin-top: 5px;' +
'padding: 5px;' +
'}' +
'p.VersionBoxToggle' +
'{padding: 5px;}' +
'div.VersionBoxClose{' +
'border:1px solid #' + (AVE.Utils.CSSstyle === "dark" ? "5452A8" : "D1D0FE") + ';' +
'background-color:#' + (AVE.Utils.CSSstyle === "dark" ? "304757" : "F4FCFF") + ';' +
'font-size:12px;' +
'text-align: center;' +
'color:#6CA9E4;' +
'font-weight:bold;' +
'float: right;' +
'margin: 0 5px 5px 0;' +
'cursor: pointer;' +
'width:50px;' +
'}' +
'textarea.VersionBoxText{' +
'resize:none;' +
'border-bottom:1px solid ' + (AVE.Utils.CSSstyle === "dark" ? "#6E6E6E" : "#939393") + ';' +
'color: ' + (AVE.Utils.CSSstyle === "dark" ? "#BFBFBF" : "535353") + ';' +
'font-size:12px;' +
'font-weight:bold;' +
'width:100%;' +
'padding:10px;' +
'padding-bottom:10px;' +
'}';
var notifierHTML = '
Click on a value to modify it.'+
' Click the buttons on either sides to navigate through the table pages or use the arrow keys (+Ctrl to go to the first or last page)';
htmlStr += ' Context: ' +
' None: ' +
' Edit: ' +
' Peek: ' +
' Open link: ' +
'
';
return htmlStr;
},
callback: function () {
"use strict";
var _this = this;
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:last-child') //remove
.off()
.on("mouseover", function () {
$(this).parent().css("background", _this.MouseOverColours[1]);
})
.on("mouseleave", function () {
$(this).parent().css("background", "");
})
.on("click", function () {
var name = $(this).parent().attr("username");
if (confirm("Are you sure you want to delete "+name+"'s tag?")){
_this.module.RemoveTag(name);
$(_this.CSSselector).trigger("click");
}
});
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:nth-child(2)') //edit tag
.off()
.on("click", function (e, artificial) {
var tag = $(this).text() || $(this).find("input").val() || "";
if ($(this).find("input").length === 0){
$(this).html('');
var input = $(this).find("input");
input.focus().select();
input.one("focusout", function () {
input.val(input.attr("original"));
$(this).trigger("click", true);
});
} else {
if (!artificial) {return;}//we don't want to lose the focus because of a click in the same input text
$(this).find("input").off();
$(this).html(''+tag+'');
}
});
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:nth-child(3)') //edit colour
.off()
.on("click", function (e, artificial) {
var colour = $(this).text() || $(this).find("input").val();
if ($(this).find("input").length === 0){
var input = $("input#AVE_Dashboard_usertag_quickedit[type='color'][data='colour']");
input.attr("original", colour).attr("u", $(this).parent().attr("username")).val(colour);
input.one("change", function () {
_this.editTag(input, "colour");
});
input.show().css("opacity", "0"); //Because of Chrome which doesn't want to show the colour palette if the input is hidden ("display: none;")
input.trigger("click");
} else {
if (!artificial) {return;}//we don't want to lose the focus by a click in the same input text
$(this).find("input").off();
$(this).html(''+colour+'');
}
});
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:nth-child(4)') //edit ignore
.off()
.on("click", function () {
var ignore, newval;
ignore = $(this).text();
newval = ignore === "No" ? "Yes" : "No";
$(this).text(newval);
_this.editTag($(this), "ignore");
});
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:nth-child(6)') //Show context option (goto link, edit)
.off()
.on("mouseenter", function () { //Display option box
var JqId = $(this);
var boxHtml = ''; //Edit : Forward
var context = JqId.attr("title");
boxHtml += '';
if(context){
var url;
boxHtml += '';
if (!/^http/.test(context)) { url = "https://" + window.location.hostname + context; }
else{ url = context; }
boxHtml += '';
}
$(this).html(boxHtml)
.css("background-image", "none");
$("svg#editContext").on("click", function () {
var newcontext = prompt(context ? "Choose new context" : "Edit context", context);
if (newcontext === null){newcontext = context;}
JqId.attr("title", newcontext);
_this.editTag(JqId, "context");
});
})
.on("mouseleave", function () { //Hide option box
$("svg#editContext").off();
$(this).html("")
.css("background-image", "");
})
.on('dblclick', function() { //If a context exists try to open it in a new page
if($(this).is(":not([title])")){return;}
var url = $(this).attr("title");
if (!/^http/.test(url)) { url = "https://" + window.location.hostname + url; }
AVE.Utils.SendMessage({ request: "OpenInTab", url: url });
});
$('table#AVE_Dashboard_usertags_table > tbody > tr > td:nth-child(5)') //edit vote-balance
.off()
.on("click", function (e, artificial) {
var balance = $(this).text() || $(this).find("input").val();
if ($(this).find("input").length === 0){
$(this).html('');
var input = $(this).find("input");
input.focus().select();
input.one("focusout", function () {
input.val(input.attr("original"));
$(this).trigger("click", true);
});
} else {
if (!artificial) {return;}//we don't want to lose the focus by a click in the same input text
$(this).find("input").off();
$(this).html(balance);
}
});
$('a#AVE_Dashboard_navigate_tags') //navigate with buttons
.off()
.on("click", function () {
if ($(this).hasClass("btn-unsub")){return false;}
switch ($(this).attr('role')) {
case "prev":
_this.currpage--;
break;
case "next":
_this.currpage++;
break;
case "first":
_this.currpage = 0;
break;
case "last":
_this.currpage = Math.ceil((_this.usertags.length - _this.tagsperpage) / _this.tagsperpage);
break;
default:
return;
}
$(_this.CSSselector).trigger("click");
});
var JqIdOpt = $("fieldset#AVE_Dashboard_usertags_options");
JqIdOpt.find("legend").off().on("click", function () {
if ($(this).parent().find("input:first").is(':hidden')){
$(this).parent().find("*").show();
} else {
$(this).parent().find("*").hide();
}
$(this).show();
}).trigger("click");
JqIdOpt.find("a#save").off().on("click", function () {
_this.ShowVoteBalance = JqIdOpt.find("input#balance").is(":checked");
_this.ShowIgnore = JqIdOpt.find("input#ignore").is(":checked");
_this.ShowTag = JqIdOpt.find("input#tag").is(":checked");
_this.tagsperpage = parseInt(JqIdOpt.find("input#elperpage").val(), 10) || 20;
if (_this.tagsperpage < 1) {_this.tagsperpage = 20;}
_this.SaveOptions();
$(_this.CSSselector).trigger("click");
});
$(document)
.off()
.on("keyup", function (event) {
var ctrl, pos, input;
ctrl= event.ctrlKey;
input = $("input#AVE_Dashboard_usertag_quickedit:not([type='color'])");
if (input.length === 0){ //navigate with arrow keys
//We don't want to change page when a user is using the arrow key to edit a value
if (event.which === 37){
pos = (ctrl ? "first" : "prev");
} else if (event.which === 39){
pos = (ctrl ? "last" : "next");
}
if (pos){
$('a#AVE_Dashboard_navigate_tags[role="'+ pos +'"]:first').trigger("click");
}
}
if (event.which === 13){ //Press enter to confirm change
_this.editTag(input, input.attr("data"));
}
});
},
editTag: function (input, dtype) {
"use strict";
var _this = this;
if (input.length === 1){
if (input.attr("original") === input.val() && dtype !== "ignore"){input.trigger("click", true);return;}//No need to update nor reload if nothing changed
var root, tag, usertag;
if (dtype === "colour"){
var u = input.attr("u");
root = $("tr[username='"+u+"']");
} else {
root = input.parents("tr:first");
}
usertag = {};
usertag.username = root.attr("username");
usertag.i = root.find("td[data='ignore']").text() === "Yes";
usertag.con = root.find("td[data='context']").attr("title");
if (!usertag.con){delete usertag.con;}
if (dtype === "tag"){
usertag.t = input.val();
} else {
usertag.t = root.find("td[data='tag']").text();
}
if (dtype === "colour"){
usertag.col = input.val() || input.attr("original");
} else {
usertag.col = root.find("td[data='colour']").text();
}
if (dtype === "balance"){
var newval = input.val();
usertag.b = parseInt((isNaN(newval) || newval === "") ? input.attr("original") : input.val(), 10);
} else {
usertag.b = parseInt(root.find("td[data='balance']").text(), 10);
}
_this.module.SetTag(usertag); //save tag
$(_this.CSSselector).trigger("click"); //Reload-update
}
},
navbuttons: function () {
var htmlNavButtons = "";
htmlNavButtons += '
';
$(btnHTML).insertAfter(".disabled:last");
}
},
Listeners: function () {
var _this = this;
var isExpanded = false;
var JqId = $("a#GM_ExpandAllImages");
JqId.off("click");
JqId.on("click", function () {
if ($(this).hasClass("expanded")) {
$(this).text('View Media (' + _this.sel.length + ')');
$(this).removeClass("expanded");
isExpanded = false;
} else {
$(this).text('Hide Media (' + _this.sel.length + ')');
$(this).addClass("expanded");
isExpanded = true;
}
_this.ToggleMedia(isExpanded);
});
},
ToggleMedia: function (state) {
for (var el in this.sel.get()) {
if (
(state && this.sel.eq(el).parent().find(".expando,.link-expando").length == 0) ||
state === this.sel.eq(el).parent().find(".expando,.link-expando").first().is(':hidden')
)
{
//A click on a media that failed (e.g. error 404) will redirect instead of toggling the expando.
if (this.sel.eq(el).find("span.link-expando-type").text() !== "Error") {
this.sel[el].click();
}
}
}
},
AppendToPreferenceManager: {
html: function () {
var _this = AVE.Modules['ToggleMedia'];
var mediaTypes = ["Images", "Videos", "self-texts"];
var value = _this.Options.MediaTypes.Value;
var htmlString = '
';
for (var i in mediaTypes) {
htmlString += '' +
'' +
'' +
'';
}
return htmlString + '
';
}
}
};
/// END Toggle media ///
/// Hide submissions: Hide vote with the keyboard or automatically after voting on submissions. ///
AVE.Modules['HideSubmissions'] = {
ID: 'HideSubmissions',
Name: 'Hide submissions',
Desc: 'Hide vote with the keyboard or automatically after voting on submissions.',
Category: 'Subverse',
Index: 10, //early so that other modules don't do unnecessary processing on submissions that will get removed
Enabled: false,
Store: {},
RunAt: "container",
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
HideDownvoted: {
Type: 'boolean',
Desc: "Hide submissions you downvote.",
Value: false
},
HideUpvoted: {
Type: 'boolean',
Desc: "Hide submissions you upvote.",
Value: false
},
HideRightAway: {
Type: 'boolean',
Desc: "Hide the submission as soons as marked hidden by clicking the \"hide\" button or pressing the hide key",
Value: false
},
HideAfterVote: {
Type: 'boolean',
Desc: "Hide the submission right after the vote is registered.",
Value: false
},
HideAfterView: {
Type: 'boolean',
Desc: "Hide the submission after viewing it (opening its link).",
Value: false
},
AddHideButton: {
Type: 'boolean',
Desc: "Insert a \"hide\" button.",
Value: true
},
MaxStorage: {
Type: 'int',
Range: [1,5000],
Desc: "Max number of submissions to remember",
Value: 400
}
},
OriginalOptions: "",
StorageName: "",
HiddenPosts: [],
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
ResetPref: function () {
this.Options = JSON.parse(this.OriginalOptions);
//this.Store.SetValue(this.StorageName, "[]");
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if ($.inArray(AVE.Utils.currentPageType, ["frontpage", "set", "subverse", "search", "domain", "user-submissions", "saved"]) === -1) {
this.Enabled = false;
}
if (this.Enabled) {
this.StorageName = this.Store.Prefix + this.ID + "_Hidden";
this.HiddenPosts = JSON.parse(this.Store.GetValue(this.StorageName, "[]"));
this.Pruning();
this.Start();
}
},
Pruning: function(){
var count;
count =this.HiddenPosts.length - this.Options.MaxStorage.Value;
if (count < 1) {return;}
count += Math.ceil(this.Options.MaxStorage.Value / 8); //If over the limit we remove 1/8th of the total value
this.HiddenPosts.splice(0,count);
this.Store.SetValue(this.StorageName, JSON.stringify(this.HiddenPosts));
},
AddToHiddenList: function (id, vote) {
if ($.inArray(id.toString(), this.HiddenPosts) !== -1){this.RemoveFromHiddenList(id);return;}
this.HiddenPosts.push(id);
this.Store.SetValue(this.StorageName, JSON.stringify(this.HiddenPosts));
var JqId = $("div.submission.id-"+id.toString());
if ( (!vote && this.Options.HideRightAway.Value)
|| (vote && this.Options.HideAfterVote.Value)){
JqId.remove();
print("AVE: HideSubmissions > removing submission with id "+id);
} else if(this.Options.AddHideButton.Value) {
JqId.find("ul.flat-list.buttons").find("li > a#AVE_HideSubmissions_link").text("unhide");
}
print("AVE: HideSubmissions > hiding submission with id "+id);
},
RemoveFromHiddenList: function (id) {
this.HiddenPosts.splice(this.HiddenPosts.indexOf(id), 1);
this.Store.SetValue(this.StorageName, JSON.stringify(this.HiddenPosts));
if (this.Options.AddHideButton.Value){
$("div.submission.id-"+id.toString()).find("ul.flat-list.buttons").find("li > a#AVE_HideSubmissions_link").text("hide");
}
print("AVE: HideSubmissions > unhiding submission with id "+id);
},
Start: function () {
var _this = this;
$("div.submission").each(function () {
var id = $(this).attr("data-fullname");
if (id && $.inArray(id.toString(), _this.HiddenPosts) !== -1){
$(this).remove();
print("AVE: HideSubmissions > removing submission with id "+id);
}
});
if (this.Options.AddHideButton.Value){
this.AppendToPage();
}
this.Listeners();
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPage: function () {
"use strict";
$("ul.flat-list.buttons").each(function () {
if ($(this).find("li > a#AVE_HideSubmissions_link").length > 0) {return;}
$(this).append('
";
htmlStr += '';
htmlStr += ' - Post ';
htmlStr += '';
htmlStr += ' - Quote and Code ';
htmlStr += '';
htmlStr += ' - Vote box in submissions page ';
htmlStr += '';
htmlStr += ' - Context comment ';
return htmlStr;
},
callback: function () {//ContentColour QuoteCodeColour VoteCountBoxColour ContextColour
var _this = AVE.Modules['SelectPost'];
$("input[id='ContentColour'][Module='" + _this.ID + "']").on("keyup", function () {
$("div#Demo_ContentColour").css("background-color", $("input[id='ContentColour'][Module='" + _this.ID + "']").val());
}).trigger("keyup");
$("input[id='QuoteCodeColour'][Module='" + _this.ID + "']").on("keyup", function () {
$("div#Demo_QuoteCodeColour").css("background-color", $("input[id='QuoteCodeColour'][Module='" + _this.ID + "']").val());
}).trigger("keyup");
$("input[id='VoteCountBoxColour'][Module='" + _this.ID + "']").on("keyup", function () {
$("div#Demo_VoteCountBoxColour").css("background-color", $("input[id='VoteCountBoxColour'][Module='" + _this.ID + "']").val());
}).trigger("keyup");
$("input[id='ContextColour'][Module='" + _this.ID + "']").on("keyup", function () {
$("div#Demo_ContextColour").attr("style", "display:inline;padding-left:15x;padding-right:15px;margin-right:10px;" + $("input[id='ContextColour'][Module='" + _this.ID + "']").val());
}).trigger("keyup");
}
}
};
/// END Select posts ///
/// Shortcut keys: Use your keyboard to navigate Voat. Leave field empty for Enter/Return key. ///
AVE.Modules['ShortKeys'] = {
ID: 'ShortKeys',
Name: 'Shortcut keys',
Desc: 'Use your keyboard to navigate Voat. Leave field empty for Enter/Return key.',
Category: 'Posts',
Enabled: false,
Index: 20,
Store: {},
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
OpenInNewTab: {
Type: 'boolean',
Desc: 'Open comments and link pages in new tabs.',
Value: true
},
OpenInArchive: {
Type: 'boolean',
Desc: 'Open link page in archives.is.',
Value: false
},
UpvoteKey: {
Type: 'char',
Value: 'a'
},
DownvoteKey: {
Type: 'char',
Value: 'z'
},
NextKey: {
Type: 'char',
Value: 'j'
},
PrevKey: {
Type: 'char',
Value: 'k'
},
OpenCommentsKey: {
Type: 'char',
Value: 'c'
},
OpenLinkKey: {
Type: 'char',
Value: 'l'
},
OpenLCKey: {
Type: 'char',
Value: 'b'
},
ExpandKey: {
Type: 'char',
Value: 'x'
},
ToggleCommentChain: {
Type: 'char',
Value: ''
},
NavigateTop: {
Type: 'char',
Value: 'f'
},
NavigateBottom: {
Type: 'char',
Value: 'v'
},
HidePost: {
Type: 'char',
Value: 'h'
}
},
OriginalOptions: "",
SavePref: function (POST) {
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST[this.ID]));
},
ResetPref: function () {
this.Options = JSON.parse(_this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + _this.ID, "{}");
if (Opt != undefined) {
Opt = JSON.parse(Opt);
$.each(Opt, function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
}
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if (!AVE.Modules['SelectPost'] || !AVE.Modules['SelectPost'].Enabled) { this.Enabled = false; }
if (this.Enabled) {
this.Start();
}
},
Start: function () {
var _this = this;
var shift, ctrl,
up = this.Options.UpvoteKey.Value,
down = this.Options.DownvoteKey.Value,
next = this.Options.NextKey.Value,
previous = this.Options.PrevKey.Value,
OpenC = this.Options.OpenCommentsKey.Value,
OpenL = this.Options.OpenLinkKey.Value,
OpenLC = this.Options.OpenLCKey.Value,
Expand = this.Options.ExpandKey.Value,
TCC = this.Options.ToggleCommentChain.Value,
NavTop = this.Options.NavigateTop.Value,
NavBottom = this.Options.NavigateBottom.Value,
HidePost = this.Options.HidePost.Value;
$(document).keydown(function (event) {
shift = event.shiftKey;
ctrl = event.ctrlKey;
//Exit if the CSSEditor panel has the focus
if ($("style#custom_css.AVE_custom_css_editable").is(":focus")){return;}
//Exit if the focus is given to a text input
if ($(":input").is(":focus")) {
if (ctrl && event.which === 13){
var inp = $("textarea#Content.commenttextarea:focus");
if (inp.length === 0){return;}
var submitbtn = inp.nextAll("input#submitbutton:first"); //
if (submitbtn.length === 0){
submitbtn = inp.parent().parent().nextAll("input#submitbutton:first");
}
submitbtn.trigger("click");
}
return;
}
//Exit if a key modifier is pressed (ctrl, shift)
if (ctrl || shift) { return; }
var sel = AVE.Utils.SelectedPost;
var key;
if (event.key === undefined) { //Chrome
key = String.fromCharCode(event.keyCode).toUpperCase();
} else {
key = event.key.toUpperCase();
}
if (event.which === 13) { key = ""; } //Enter/Return key
if (key === NavTop.toUpperCase()) { // Navigate to the top of the page
//Scroll to top
//Set first post as selected
var obj = $("div.submission[class*='id']:first,div.comment[class*='id']:first").first();
if (AVE.Modules['SelectPost']) { AVE.Modules['SelectPost'].ToggleSelectedState(obj.find(".entry:first")); }
$(window).scrollTop(0);
} else if (key === NavBottom.toUpperCase()) { // Navigate to the bottom of the page
//Scroll to bottom
$(window).scrollTop($(document).height());
//Set last post as selected
var obj = $("div.comment[class*='id']:last");
if (obj.length === 0) { obj = $("div.submission[class*='id']:last"); }
if (AVE.Modules['SelectPost']) { AVE.Modules['SelectPost'].ToggleSelectedState(obj.find(".entry:first")); }
}
//All following keys need a post selected to work
if (!AVE.Utils.SelectedPost) { return; }
if (key === up.toUpperCase()) { // upvote
sel.parent().find(".midcol").find("div[aria-label='upvote']").first().click();
} else if (key === down.toUpperCase()) { // downvote
sel.parent().find(".midcol").find("div[aria-label='downvote']").first().click();
} else if (key === next.toUpperCase()) { // next post
if (sel.parent().hasClass("submission")) {
//Submissions
var _next = sel.parent().nextAll("div.submission[class*='id-']:first");
if (_next.length > 0) {
AVE.Modules['SelectPost'].ToggleSelectedState(_next.find("div.entry"));
_this.ScrollToSelectedSubmission();
} else if (AVE.Modules['NeverEndingVoat'] && AVE.Modules['NeverEndingVoat'].Enabled) {
//If the NeverEnding modules exists and is enabled, we load the next page.
AVE.Modules['NeverEndingVoat'].LoadMore();
}
} else {
//Comment
var id = sel.parent().prop("class").split(" ")[1];
// :visible because comments could be hidden, with the ToggleChildComment module
var a = sel.parent().find("div[class*='id-']:visible").get(0) || //Child
$("div." + id + " ~ div[class*='id-']:visible").get(0); //Sibling
if (!a) { //Not a direct parent
var tempSel = sel.parent();
var tempID = id;
var count = 0;
while (!a) {
tempSel = $(tempSel.parent("div[class*='id-']").get(0) ||
$("div." + tempID + " ~ div[class*='id-']:visible").get(0));
if (tempSel.length === 0) { break; }
if (tempSel.nextAll("div[class*='id-']:visible:last").length > 0) {
tempID = tempSel.nextAll("div[class*='id-']:visible:last").attr("class").split(" ")[1];
}
if (tempID !== id) {
a = $("div." + tempSel.nextAll("div[class*='id-']:visible:first").attr("class").split(" ")[1]);
break;
}
count++;
if (count > 30) { print("AVE: breaking endless loop > looking for next comment"); break; }
}
}
if (a) {
AVE.Modules['SelectPost'].ToggleSelectedState($(a).find("div.entry:first"));
_this.ScrollToSelectedComment();
} else { $("a#loadmorebutton").click(); }
}
} else if (key === previous.toUpperCase()) { // previous post
if (sel.parent().hasClass("submission")) { // select by page type not class
//Submissions
var prev = sel.parent().prevAll("div.submission[class*='id-']:first");
if (prev.length > 0) {
AVE.Modules['SelectPost'].ToggleSelectedState(prev.find("div.entry"));
_this.ScrollToSelectedSubmission();
}
} else {
//Comment
//var id = sel.parent().prop("class").split(" ")[1];
var a = sel.parent().prevAll("div[class*='id-']:visible:first").find("div[class*='id-']:visible:last").get(0) || //Parent's child
sel.parent().prevAll("div[class*='id-']:visible:first").get(0) || //Sibling
sel.parent().parent("div[class*='id-']:visible").get(0); //Parent
if (a) {
AVE.Modules['SelectPost'].ToggleSelectedState($(a).find("div.entry:first"));
_this.ScrollToSelectedComment();
}
//if (!a) No previous comment
}
} else if (key === OpenC.toUpperCase()) { // Open comment page
if (!sel.parent().hasClass("submission")) { return; }
var url = "https://" + window.location.hostname +sel.find("a.comments").attr("href");
if (_this.Options.OpenInNewTab.Value) {
AVE.Utils.SendMessage({ request: "OpenInTab", url: url });
} else {
window.location.href = url;
}
} else if (key === OpenL.toUpperCase()) { // Open link page
if (!sel.parent().hasClass("submission")) { return; }
var url = sel.find("a.title").attr("href");
if (!/^http/.test(url)) { url = "https://" + window.location.hostname + url; }
if (_this.Options.OpenInArchive.Value && !/^https?:\/\/archive\.is/.test(url)){
url = 'https://archive.is/?run=1&url='+encodeURIComponent(url);
}
if (_this.Options.OpenInNewTab.Value) {
AVE.Utils.SendMessage({ request: "OpenInTab", url: url });
} else {
window.location.href = url;
}
} else if (key === OpenLC.toUpperCase()) { // Open comment and link pages
if (!sel.parent().hasClass("submission")) { return; }
var url = [];
url.push(sel.find("a.title").attr("href"));
url.push("https://" + window.location.hostname + sel.find("a.comments").attr("href"));
if (!/^http/.test(url[0])) { url[0] = "https://" + window.location.hostname + url[0]; }
if (url[0] && url[0] === url[1]) {
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[0] });
} else {
if (_this.Options.OpenInArchive.Value && !/^https?:\/\/archive\.is/.test(url[0])){
url[0] = 'https://archive.is/?run=1&url='+encodeURIComponent(url[0]);
}
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[0] });
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[1] });
}
} else if (key === Expand.toUpperCase()) { // Expand media/self-text
var expand, media;
if ( sel.parent().hasClass("submission")) {
//In submissions
if (AVE.Utils.currentPageType === "thread" && sel.parent().hasClass("self")){
expand = true;
media = sel.find("div.md:visible").find("a[title]");
media.each(function () {
//Expand is false if at least one of the media is expanded
if ($(this).next(".link-expando:visible").length > 0)
{ expand = false; return false; }
});
media.each(function () {
if ($(this).find("span.link-expando-type").length > 0
&& expand !== $(this).next(".link-expando:visible").length > 0)
{ this.click(); }
});
} else {
sel.find("div.expando-button").click();
}
} else {
//In comments
expand = true;
media = sel.find("div.md:visible").find("a[title]");
media.each(function () {
//Expand is false if at least one of the media is expanded
if ($(this).next(".link-expando:visible").length > 0)
{ expand = false; return false; }
});
media.each(function () {
if ($(this).find("span.link-expando-type").length > 0
&& expand !== $(this).next(".link-expando:visible").length > 0)
{ this.click(); }
});
}
if (sel.offset().top < $(window).scrollTop() &&
sel.find("div.expando-button").hasClass("collapsed")){// and if it was expanded
$('html, body').animate({ scrollTop: AVE.Utils.SelectedPost.parent().offset().top - 50 }, 150);
}
} else if (key === TCC.toUpperCase()) { // Toggle comment chain or load more replies
if (sel.parent().hasClass("submission")) { return; }
if (sel.find("a.inline-loadcomments-btn:first").length > 0) {
//Load more comment if possible
sel.find("a.inline-loadcomments-btn:first")[0].click();
} else if (sel.find('a.expand:visible:first').length > 0) {
//Hide selected comment otherwise
sel.find('a.expand:visible:first')[0].click();
}
} else if (key === HidePost.toUpperCase()) { // Hide submission
if (!AVE.Modules['HideSubmissions'] || !AVE.Modules['HideSubmissions'].Enabled){
if(!confirm("You are trying to hide a post but the module \"HideSubmissions\" is disabled.\nDo you want to activate and load this module?")){
return;
} else {
var Opt = JSON.parse(_this.Store.GetValue(_this.Store.Prefix + AVE.Modules['HideSubmissions'].ID, "{}"));
Opt.Enabled = true;
_this.Store.SetValue(_this.Store.Prefix + AVE.Modules['HideSubmissions'].ID, JSON.stringify(Opt));
AVE.Modules['HideSubmissions'].Load();
print("AVE: DomainFilter > enabled and started");
}
}
var id = sel.parent().attr("data-fullname");
//Select the next submission
var _next = sel.parent().nextAll("div.submission[class*='id-']:first");
if (_next.length > 0) {
AVE.Modules['SelectPost'].ToggleSelectedState(_next.find("div.entry"));
_this.ScrollToSelectedSubmission();
} else if (AVE.Modules['NeverEndingVoat'] && AVE.Modules['NeverEndingVoat'].Enabled) {
//If the NeverEnding modules exists and is enabled, we load the next page.
AVE.Modules['NeverEndingVoat'].LoadMore();
}
AVE.Modules['HideSubmissions'].AddToHiddenList(id);
}
});
},
ScrollToSelectedSubmission: function () {
$('html, body').finish();
//Scroll to selected item if out of screen
if ($(window).scrollTop() > AVE.Utils.SelectedPost.parent().offset().top - AVE.Utils.SelectedPost.parent().height()) {
$('html, body').animate({ scrollTop: AVE.Utils.SelectedPost.parent().offset().top - 50 }, 150);
} else if ($(window).scrollTop() + $(window).height() < AVE.Utils.SelectedPost.parent().offset().top + AVE.Utils.SelectedPost.parent().height() + 50) {
$('html, body').animate({ scrollTop: AVE.Utils.SelectedPost.parent().offset().top - $(window).height() + AVE.Utils.SelectedPost.parent().height() + 50 }, 150);
}
},
ScrollToSelectedComment: function () {
$('html, body').finish();
//Scroll to selected item if out of screen
if ($(window).scrollTop() > AVE.Utils.SelectedPost.parent().offset().top - AVE.Utils.SelectedPost.height()) {
$('html, body').animate({ scrollTop: AVE.Utils.SelectedPost.parent().offset().top - 50 }, 150);
} else if ($(window).scrollTop() + $(window).height() < AVE.Utils.SelectedPost.parent().offset().top + AVE.Utils.SelectedPost.height() + 50) {
$('html, body').animate({ scrollTop: AVE.Utils.SelectedPost.parent().offset().top - $(window).height() + AVE.Utils.SelectedPost.height() + 50 }, 150);
}
},
AppendToPreferenceManager: {
html: function () {
var _this = AVE.Modules['ShortKeys'];
var htmlStr = "";
//Up and Down vote
htmlStr += '
';
htmlStr += '
';
htmlStr += '
Upvote:
';
htmlStr += '
Downvote:
';
//Next and previous post
htmlStr += '
Next post:
';
htmlStr += '
Previous post:
';
htmlStr += '
';
//Open Link, Comments, Comments & Link
htmlStr += '
';
htmlStr += '
Open Link:
';
htmlStr += '
Open comments: ';
htmlStr += '
Open L&C:
';
//Toggle expand media
htmlStr += '
Toggle expand: ';
htmlStr += '
';
//Toggle expand comment
htmlStr += '
';
htmlStr += '
Toggle comment: ';
//Navigate to Top and Bottom of the page
htmlStr += '
Top of the page: ';
htmlStr += '
Bottom of the page:
';
//Hide submission
htmlStr += '
Hide post:
';
htmlStr += '
';
htmlStr += '
';
htmlStr += ' ';
htmlStr += ' ';
return htmlStr;
},
callback: function () {
}
}
};
/// END Shortcut keys ///
/// Inject custom style: Apply your custom CSS style of choice everywhere on Voat. For the best result check "Disable custom subverse styles" in your preferences. ///
AVE.Modules['InjectCustomStyle'] = {
ID: 'InjectCustomStyle',
Name: 'Inject custom style',
Desc: 'Apply your custom CSS style of choice everywhere on Voat. For the best result check "Disable custom subverse styles" in your preferences.',
Category: 'Style',
Index: 50,
Enabled: false,
Store: {},
RunAt: "start",
Options: {
Enabled: {
Type: 'boolean',
Value: false
},
CustomStyleName: {
Type: 'string',
Value: ""
},
CustomStyleUrl: {
Type: 'string',
Desc: 'Enter URL of a custom CSS file:',
Value: ""
},
ApplyEverywhere: {
Type: 'boolean',
Desc: 'Also insert the custom style in non-subverse pages (e.g. user page, moderator page, ...). The custom styles generaly aren\'t compatible with them.',
Value: false
},
RemoveSubverseStyle: {
Type: 'boolean',
Desc: 'Remove the subverse\'s custom style if any is found.',
Value: true
},
InjectLate: {
Type: 'boolean',
Desc: 'Insert the new CSS file after the original custom style.',
Value: false
}
},
OriginalOptions: "",
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
ResetPref: function () {
this.Options = JSON.parse(this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if (!this.Options.ApplyEverywhere.Value) {
if ($.inArray(AVE.Utils.currentPageType,
["frontpage", "set", "subverse", "thread",
"domain", "search", "saved", "user-submissions", "user-comments"]) === -1) {
this.Enabled = false;
}
}
//No need to start if no external custom style was selected
if (this.Options.CustomStyleName.Value === "None" &&
this.Options.CustomStyleUrl.Value === "") {
this.Enabled = false;
}
if (this.Enabled) {
this.Start();
}
},
CustomStyles: {
None: "",
Cashmere: "https://cdn.rawgit.com/mijowa/Cashmere/master/css/cashmere.min.css?AVE",
Flatron: "https://cdn.rawgit.com/Gyyyn/Flatron-Voat/master/flatron.css?AVE", //buggy (see block info) Doesn't like big usernames
Scribble: "https://cdn.rawgit.com/ScribbleForVoat/Scribble/master/base.min.css?AVE",
Simplegoats: "https://cdn.rawgit.com/relaxedzombie/simplegoats/master/simplegoats.min.css?AVE",
SlimDark: "https://cdn.rawgit.com/KinOfMany/SlimDark/master/style.css?AVE",
Typogra: "https://cdn.rawgit.com/Nurdoidz/Typogra-Voat/master/Typogra.min.css?AVE"
},
CustomCSSContainerCount: 0,
Start: function () {
var _this = this;
var theme = AVE.Utils.CSSstyle || ~document.cookie.indexOf('theme=dark') ? "Dark" : "Light";
/*
BUG:
if you log-in on voat.co then switch to www.voat.co, the theme info cookie (queried above) doesn't exist
this module needs to start as soon as possible and the cookie is the earliest way to get that info
*/
var obsCustomCSS = new OnNodeChange($(document.documentElement), function (m) {
//By /u/FuzzyWords: voat.co/v/AVEbeta/comments/448708/2133227
if(m.addedNodes) {
for(var i = 0; i < m.addedNodes.length; i++) {
var n = m.addedNodes[i];
if (_this.Options.RemoveSubverseStyle.Value || !_this.Options.InjectLate.Value) {
if ($(n).is("link[href^='/Content/" + theme + "?v=']")){$(n).remove();}
}
if (_this.Options.RemoveSubverseStyle.Value) {
if(n.parentNode && n.nodeName.toUpperCase() === "STYLE" && n.id == "custom_css") {
n.parentNode.removeChild(n);
//We want to disconnect the observer once it has done its job. But remember that a custom style is added twice in threads.
// Actually this is no longer the case (the limit is set to 1 now)
obsCustomCSS.disconnect();
}
}
}
}
});
obsCustomCSS.observe();
//If a custom style was added before our Observer could start, we delete it manually
//This will happen with slow computers or extensions (very rarely with userscripts)
$("style#custom_css").remove();
var URL;
if (this.Options.CustomStyleName.Value &&
this.CustomStyles[this.Options.CustomStyleName.Value]) {
URL = this.CustomStyles[this.Options.CustomStyleName.Value];
} else if (this.Options.CustomStyleUrl.Value) {
URL = this.Options.CustomStyleUrl.Value;
}
if (URL) {
if (this.Options.InjectLate.Value && !this.Options.RemoveSubverseStyle.Value) {
$(document).ready(function () {
$("body").append('');
});
} else {
$("head").append('')
.append('');
}
//If I use the following method, someone could easily inject javascript code and mess with the user.
//$.ajax({
// url: URL,
// cache: true,
//}).done(function (data, status, request) {
// $("head").append('';
if (!_this.Options.CustomStyleName.Value)
{ htmlStr += ''; }
$.each(Object.keys(_this.CustomStyles), function () {
htmlStr += '';
});
htmlStr += '';
htmlStr += '
' + _this.Options.CustomStyleUrl.Desc + ' ';
htmlStr += ' Check';
htmlStr += ' Try a usertstyle: add ".css" at the end of the userstyle\'s url and paste it above.';
htmlStr += ' ';
htmlStr += ' ';
htmlStr += '
';
htmlStr += '
Panic Mode: If you added a custom style that messes everything up and you cannot change back, do Ctrl+Shift+Insert to disable this module and reload the page.
';
return htmlStr;
},
callback: function () {
var _this = this;
$("input#RemoveSubverseStyle").change(function () {
$("input#InjectLate").attr("disabled", $("input#RemoveSubverseStyle").is(":checked"));
});
$("a#AVE_CheckCSSFile").on("click", function () {
var URL = $("div.AVE_ModuleCustomInput > input#CustomStyleUrl").val();
if (URL) {
$.ajax({
url: URL,
cache: true
}).done(function (data, status, request) {
if (request.getResponseHeader('Content-type').split(";")[0] === "text/css") {
_this.ShowInfo("It's Ok! The file can be loaded as CSS!", "#68c16b");
} else {
_this.ShowInfo("Not Ok! The file isn't sent as a CSS file (MIME type).", "#dd5454");
}
})
.fail(function () {
_this.ShowInfo("Error while loading CSS file. Check the URL", "#dd5454");
});
}
});
},
ShowInfo: function (message, color) {
var JqId = $("span#CustomStyleUrl_InfoStr");
if (JqId.length === 0) {
$(' ').insertAfter("a#AVE_CheckCSSFile");
JqId = $("span#CustomStyleUrl_InfoStr");
}
$(JqId).show();
$(JqId).text(message);
if (color) { $("span#CustomStyleUrl_InfoStr").css("color", color); }
$(JqId).delay(3000).fadeOut(300);
setTimeout(function() { //Because "text" isn't a queued function
$(JqId).text("");
}, 3300);
}
},
//If the applied custom style messed everything up, so much that you can't toggle the module off:
PanicMode: function () {
var _this = this;
var POST = {};
POST[this.ID] = {
Enabled: false,
CustomStyleName: _this.Options.CustomStyleName.Value,
CustomStyleUrl: _this.Options.CustomStyleUrl.Value,
ApplyEverywhere: _this.Options.ApplyEverywhere.Value,
InjectLate: _this.Options.InjectLate.Value,
RemoveSubverseStyle: _this.Options.RemoveSubverseStyle.Value
};
this.SavePref(POST);
window.location.reload();
}
};
/// END Inject custom style ///
/// Toggle subverse custom style: Adds a checkbox to enable/disable custom styles on a per subverse basis. This module is automatically disabled if "Inject custom style" is enabled or set to remove custom styles. ///
AVE.Modules['ToggleCustomStyle'] = {
ID: 'ToggleCustomStyle',
Name: 'Toggle subverse custom style',
Desc: 'Adds a checkbox to enable/disable custom styles on a per subverse basis. This module is automatically disabled if "Inject custom style" is enabled or set to remove custom styles.',
Category: 'Style',
Index: 51,
Enabled: false,
Store: {},
RunAt: "start",
Options: {
Enabled: {
Type: 'boolean',
Value: true
}
},
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.SetOptionsFromPref();
if (this.Enabled && (!AVE.Modules['InjectCustomStyle'].Enabled || !AVE.Modules['InjectCustomStyle'].Options.RemoveSubverseStyle.Value)) {
var sel = $("style#custom_css");
if (sel.length > 0){
this.CustomCSS = sel.text();
this.Start();
} else {
var _this = this;
var obsCustomCSS = new OnNodeChange($(document.documentElement), function (m) {
//By /u/FuzzyWords: voat.co/v/AVEbeta/comments/448708/2133227
if(m.addedNodes) {
for(var i = 0; i < m.addedNodes.length; i++) {
var n = m.addedNodes[i];
if(n.parentNode && n.nodeName.toUpperCase() === "STYLE" && n.id === "custom_css") {
if (!_this.CustomCSS){
_this.CustomCSS = $(n).text();
}
if (_this.CustomCSSContainerCount === 1 && $.trim(_this.CustomCSS).length > 0){
_this.Start();
obsCustomCSS.disconnect();
}
}
}
}
});
obsCustomCSS.observe();
}
}
},
CustomCSS: "",
StorageName: null,
DisabledCSS: false, //If present we disable the custom CSS
Start: function () {
this.StorageName = this.Store.Prefix + this.ID + "_DisabledCSS";
//print(this.Store.GetValue(this.StorageName, "[]"));
//this.Store.DeleteValue(this.StorageName);
this.DisabledCSS = $.inArray(AVE.Utils.subverseName, JSON.parse(this.Store.GetValue(this.StorageName, "[]"))) === -1;
this.ToggleCSSPref(this.DisabledCSS);
this.AppendToPage();
this.Listeners();
},
AppendToPage: function () {
$(' ').insertAfter("h1.hover.whoaversename");
},
Listeners: function () {
var _this = this;
$("input#AVE_ToggleCustomStyle").on("change", function () {
if ($(this).is(":checked")) {
_this.ToggleCSSPref(true);
} else {
_this.ToggleCSSPref(false);
}
});
},
ToggleCSSPref: function (status) {
var CSSlist = JSON.parse(this.Store.GetValue(this.StorageName, "[]")),
JqId = $("style#custom_css");
if (status) { //Enable
if ($.inArray(AVE.Utils.subverseName, CSSlist) !== -1) {
// If exists in stored list of disabled CSS
var idx = CSSlist.indexOf(AVE.Utils.subverseName);
CSSlist.splice(idx, 1);
this.Store.SetValue(this.StorageName, JSON.stringify(CSSlist));
}
//Don't add the CSS if we didn't remove it previously
if ($.trim(JqId.text()).length === 0) {
JqId.append(this.CustomCSS);
}
} else { // Disable
if ($.inArray(AVE.Utils.subverseName, CSSlist) === -1) {
// If doesn't exist in stored list of disabled CSSw
CSSlist.push(AVE.Utils.subverseName);
this.Store.SetValue(this.StorageName, JSON.stringify(CSSlist));
}
JqId.text("");
}
$(window).scrollTop(0);
},
AppendToDashboard: {
initialized: false,
CSSselector: "",
module: {},
init: function () {
this.module = AVE.Modules['ToggleCustomStyle'];
this.CSSselector = "a[id^='AVE_Dashboard_Show'][name='"+this.module.ID+"']";
this.initialized = true;
},
html: function () {
if (!this.initialized){this.init();}
var htmlStr;
htmlStr = '
Dashboard functionalities for '+this.module.ID+' are not yet implemented.
';
return htmlStr;
},
callback: function () {
"use strict";
}
}
};
/// END Toggle subverse custom style ///
/// Fix header position: Set the subverse list header position as fixed. ///
AVE.Modules['HeaderFixedPos'] = {
ID: 'HeaderFixedPos',
Name: 'Fix header position',
Desc: 'Set the subverse list header position as fixed.',
Category: 'Misc',
Index: 99,
Enabled: false,
Store: {},
RunAt: 'banner',
Options: {
Enabled: {
Type: 'boolean',
Value: true
}
},
SavePref: function (POST) {
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST[this.ID]));
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = _this.Store.GetValue(_this.Store.Prefix + _this.ID, "{}");
if (Opt != undefined) {
Opt = JSON.parse(Opt);
$.each(Opt, function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
}
_this.Enabled = _this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.SetOptionsFromPref();
if (this.Enabled) {
this.Start();
}
},
Start: function () {
$(window).resize(function () {
AVE.Utils.ListHeaderHeight = $('#sr-header-area').height();
});
AVE.Utils.ListHeaderHeight = $('#sr-header-area').height(); //23
this.SetAltBackground();
},
SetAltBackground: function () {
// I don't remember why I added this exit condition...
//if(!AVE.Modules['InjectCustomStyle'] || !AVE.Modules['InjectCustomStyle'].Enabled){return;}
var bg, border, JqId;
JqId = $("#sr-header-area");
if(JqId.length === 0) {
print("AVE: HeaderFixedPos > the header account element couldn't be found. Is this an error page?");
return;
}
//Subverse list bg
bg = JqId.css("background-color");
//If alpha channel isn't 1
if ( bg === "transparent" ||
bg[3] === "a" &&
parseInt(bg.replace(")", "").split(",")[3], 10) !== 1){
//general header background
bg = $("div#header[role='banner']").css("background-color");
if (bg === "transparent") {
//If there is no colour nor any image set, we set it by default
bg = AVE.Utils.CSSstyle === "dark" ? "rgba(41, 41, 41, 0.80)" : "rgba(246, 246, 246, 0.80)";
}
}
border = JqId.css("borderBottomWidth") + " " +
JqId.css("borderBottomStyle") + " " +
JqId.css("borderBottomColor");
JqId = $('.width-clip');
JqId.css('position', 'fixed')
.css("z-index", "1000")
.css('border-bottom', border)//'1px solid ' + (AVE.Utils.CSSstyle == "dark" ? "#222" : "#DCDCDC"))
.css("height", AVE.Utils.ListHeaderHeight + "px")
.css("background-color", bg);//AVE.Utils.CSSstyle == "dark" ? "#333" : "#FFF");
JqId.find("br:last").remove();//Chrome
//If you have so many subscriptions that the "my subverses" list goes out of the screen, this is for you.
JqId = $("ul.whoaSubscriptionMenu > li > ul:first");
var li_Height = JqId.find("li > a").outerHeight();
if (($(window).height() - AVE.Utils.ListHeaderHeight - li_Height) < JqId.height()) {
var li_Width = JqId.find("li > a").outerWidth(),
elPerCol = parseInt(($(window).height() - AVE.Utils.ListHeaderHeight) / li_Height, 10) - 1,
columns = JqId.find("li").length / elPerCol - 1,
el;
for (var col = 0; col < columns; col++) {
el = $("ul.whoaSubscriptionMenu > li > ul:nth(" + col + ")").find("li:gt(" + (elPerCol - 1) + ")");
$('
')
.insertAfter("ul.whoaSubscriptionMenu > li > ul:nth(" + col + ")")
.append(el);
}
}
}
};
/// END Fix header position ///
/// Comment Filter: Choose keywords to filter comments by hiding or removing them. ///
AVE.Modules['CommentFilter'] = {
ID: 'CommentFilter',
Name: 'Comment Filter',
Desc: 'Choose keywords to filter comments by hiding or removing them.',
Category: 'Thread',
Index: 100,
Enabled: false,
Store: {},
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
Filters: {
Type: 'array',
Desc: "Example of filter",
Value: []
},
RemoveFiltered: {
Type: 'boolean',
Desc: "Remove the comment and its child comments altogether.",
Value: false
}
},
Filter: function (id, keyword, sub) {
this.Id = id || 0;
this.Keywords = keyword || []; //List of keywords
this.ApplyToSub = sub || []; //List of subs
},
Processed: [], //Ids of comments that have already been processed
OriginalOptions: "",
SavePref: function (POST) {
var _this = this;
POST = POST[this.ID];
var id, kw, sub, tV;
this.Options.Filters.Value = [];
$.each(POST, function (k, v) {
tV = k.split("-");
if (tV.length === 2) {
id = parseInt(tV[0], 10);
} else { return true; } //if this isn't a filter value: continue
if (tV[1] === "kw") {
if (v.length === 0) { return true; } //If no kw were specified: continue
//else
_this.Options.Filters.Value.push(new _this.Filter(id, v.toLowerCase().split(","), []));
} else if (tV[1] === "sub") {
var inArr = $.grep(_this.Options.Filters.Value, function (e) { return e.Id === id; });
if (inArr.length === 0) {
//if there is no filter with this ID: continue
return true;
} else if (v.length !== 0) {
var idx = $.inArray(inArr[0], _this.Options.Filters.Value);
_this.Options.Filters.Value[idx].ApplyToSub = v.toLowerCase().split(",");
}
}
});
this.Store.SetValue(this.Store.Prefix + this.ID,
JSON.stringify(
{
Enabled: POST.Enabled,
RemoveFiltered: POST.RemoveFiltered,
Filters: this.Options.Filters.Value
}
)
);
},
ResetPref: function () {
var _this = this;
_this.Options = JSON.parse(_this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = _this.Store.GetValue(_this.Store.Prefix + _this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
_this.Enabled = _this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if ($.inArray(AVE.Utils.currentPageType, ["thread"]) === -1) {
this.Enabled = false;
}
if (this.Enabled) {
this.Start();
}
},
Start: function () {
var _this = this;
//When a Comment is filtered it is removed, so no need to check anyting special when the update method is triggered.
var re, found;
$("div.comment").each(function () {
var authorStr = $(this).find("a.author.userinfo").attr("data-username");
var commentRef = $(this);
var commentStr = commentRef.find("div.md:first").text().toLowerCase();
if ($.inArray($(this).find("input#CommentId").val(), _this.Processed) !== -1)
{ return true; }
//else
_this.Processed.push($(this).find("input#CommentId").val());
$.each(_this.Options.Filters.Value, function () {
found = false;
if (this.ApplyToSub.length === 0 || $.inArray(AVE.Utils.subverseName, this.ApplyToSub) !== -1) {
$.each(this.Keywords, function () {
if (this.length === 0) { return true; }//Just in case
re = new RegExp(this);
if (re.test(commentStr)) {
if (_this.Options.RemoveFiltered.Value) {
print("AVE: removed Comment by \"" + authorStr + "\" (kw: \"" + this + "\")");
commentRef.remove();
} else {
print("AVE: hid Comment by \"" + authorStr + "\" (kw: \"" + this + "\")");
commentRef.find("div.md:first").hide();
var commentContainer = commentRef.find("div.md:first").parent();//div.usertext-body#commentContent-id
commentContainer.append('Comment filtered (kw: "' + this + '"). Click to display.');
commentContainer.find("a[AVE='HiddenComment']")
.css("font-size", "10px")
.css("margin-left", "20px")
.css("font-weight", "bold");
}
found = true; //no point in continuing since the Comment has already been removed/hidden
return false; //break
}
});
}
if (found) { return false; } //break (out of kw loop)
});
if (found) { return true; } //continue (to next submission)
});
this.Listeners();
},
Listeners: function () {
if ($("a[AVE='HiddenComment']").length > 0) {
$("a[AVE='HiddenComment']").off("click").on("click", function () {
$(this).parent().find("div.md").show();
$(this).remove();
});
}
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPreferenceManager: {
htmlNewFilter: '',
html: function () {
var _this = AVE.Modules['CommentFilter'];
var Pref_this = this;
var htmlStr = "";
this.htmlNewFilter = '\
Keyword(s) \
\
Subverse(s) \
\
\
-';
htmlStr += ' ';
htmlStr += ' Example: "ex" matches "rex", "example" and "bexter". Separate keywords and subverse names by a comma. ';
var count = 0;
$.each(_this.Options.Filters.Value, function () {
var filter = Pref_this.htmlNewFilter + " ";
filter = filter.replace(/\{@id}/ig, count);
filter = filter.replace("{@keywords}", this.Keywords.join(","));
filter = filter.replace("{@subverses}", this.ApplyToSub.join(","));
count++;
htmlStr += filter;
});
htmlStr += 'Add new filter';
return htmlStr;
},
callback: function () {
var Pref_this = this;
$("div#CommentFilter > div.AVE_ModuleCustomInput > a#AddNewFilter").on("click", function () {
var html = Pref_this.htmlNewFilter + " ";
html = html.replace(/\{@id\}/ig, parseInt($("div#CommentFilter > div.AVE_ModuleCustomInput > span.AVE_Comment_Filter:last").attr("id"), 10) + 1);
html = html.replace("{@keywords}", "");
html = html.replace("{@subverses}", "");
$(html).insertBefore("div#CommentFilter > div.AVE_ModuleCustomInput > a#AddNewFilter");
$("div#CommentFilter > div.AVE_ModuleCustomInput > a.RemoveFilter").off("click")
.on("click", function () {
$(this).next("br").remove();
$(this).prev("span.AVE_Comment_Filter").remove();
$(this).remove();
});
AVE.Modules.PreferenceManager.ChangeListeners();
});
$("div#CommentFilter > div.AVE_ModuleCustomInput > a.RemoveFilter").off("click")
.on("click", function () {
$(this).next("br").remove();
$(this).prev("span.AVE_Comment_Filter").remove();
$(this).remove();
AVE.Modules.PreferenceManager.AddToModifiedModulesList("CommentFilter");
});
},
},
};
/// END Comment Filter ///
/// Toggle display child comments: Adds "Hide child comments" link to hide a chain of comments ///
AVE.Modules['ToggleChildComment'] = {
ID: 'ToggleChildComment',
Name: 'Toggle display child comments',
Desc: 'Adds "Hide child comments" link to hide a chain of comments',
Category: 'Thread',
Index: 100,
Enabled: false,
Store: {},
Options: {
Enabled: {
Type: 'boolean',
Value: true
}
},
LabelHide: "hide child comments",
LabelShow: "show child comments",
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = _this.Store.GetValue(_this.Store.Prefix + _this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
_this.Enabled = _this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.SetOptionsFromPref();
if (AVE.Utils.currentPageType !== "thread") { this.Enabled = false; }
if (this.Enabled) {
this.Start();
}
},
Start: function () {
this.AppendToPage();
this.Listeners();
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPage: function () {
var _this = this;
$("ul[class*='flat-list']").each(function () {
if ($(this).find("a#AVE_ToggleChildComment").length > 0) { return true; }
if ($(this).parents("div[class*='comment']:first").children("div[class*='child'][class*='comment']").length === 0) { return true; }
$('
';
$(button).insertBefore($(".titlebox:last").parent());
}
},
Listeners: function () {
var _this = this,
sel = "style#custom_css";
$("a#AVE_CSSEditor_button").off().on("click", function () {
var s = $(sel);
if (s.hasClass("AVE_custom_css_editable")) {
if (s.is(":hidden")){ s.show(); } else { s.hide(); }
} else {
if (s.length === 0)// This element may have been removed by one of the style modules
{ $("body").append(''); s = $(sel); }
var Vpos = _this.Options.Position.All[0][_this.Options.Position.Value[0]].split(":"),
Hpos = _this.Options.Position.All[1][_this.Options.Position.Value[1]].split(":");
s.attr("style", "display:block;position:fixed;z-index:2000;max-height:"+_this.Options.Size.Value[1]+";max-width:"+_this.Options.Size.Value[0]+";min-height:"+_this.Options.Size.Value[1]+";min-width:"+_this.Options.Size.Value[0]+";background:rgba(255,255,255,.9);color:#000;opacity:.5;font:10px/1.1 monospace;white-space:pre;overflow:scroll;padding:4px;-webkit-user-modify:read-write-plaintext-only;")
.css(Vpos[0], Vpos[1])
.css(Hpos[0], Hpos[1])
.attr("contentEditable", true)
.attr("onfocus", "this.style.opacity=1")
.attr("onblur", "this.style.opacity=.35")
.addClass("AVE_custom_css_editable")
.on("keyup", function (e) {
if (e.which === 27) {s.hide().trigger("blur");} //Escape key
});
}
s.focus();
});
},
AppendToPreferenceManager: {
html: function () {
var _this = AVE.Modules['CSSEditor'],
htmlStr = '';
htmlStr += ''+_this.Options.Position.Desc+' ';
htmlStr += 'Vertical: ';
htmlStr += 'Horizontal:
';
});
htmlStr += '';
return htmlStr;
},
callback: function () {
"use strict";
var _this = this;
var JqId = $("section[role='AVE_Dashboard'][module='Shortcuts']");
var input = JqId.parent().find("input");
JqId.find("a[role='append']").off().on("click", function () {
var newset = $.trim(input.val().replace(/\s/g, '')).split(",");
var newsubs = _this.module.GetSubversesList();
for (var i = 0; i < newset.length; i++){
if (!newset[i] || $.inArray(newset[i], newsubs) !== -1){continue;}
newsubs.push(newset[i]);
}
if (newsubs.length === 0) {return;}
_this.module.Store.SetValue(_this.module.StorageName, newsubs.join(","));
_this.Reload();
});
JqId.find("a[role='set']").off().on("click", function () {
var newset = $.trim(input.val().replace(/\s/g, '')).split(",");
var newsubs = [];
for (var i = 0; i < newset.length; i++){
if (!newset[i] || $.inArray(newset[i], newsubs) !== -1){continue;}
newsubs.push(newset[i]);
}
if (newsubs.length === 0) {return;}
_this.module.Store.SetValue(_this.module.StorageName, newsubs.join(","));
_this.Reload();
});
JqId.find("a[role='export']").off().on("click", function () {
prompt("Copy the string below", _this.module.GetSubversesListRaw());
});
JqId.find("svg[role='add']").off().on("click", function () {
var subname = $.trim(prompt("Enter below the subverse's name you want to add"));
if (subname === ""){return false;}
_this.module.AddToShortcuts(subname);
_this.Reload();
});
JqId.find("svg[role='remove']").off().on("click", function () {
var subname = $(this).parent().attr("subname");
if (!confirm("Are you sure you want to remove \""+subname+"\" from your shortcuts?")){return false;}
_this.module.RemoveFromShortcuts(subname);
_this.Reload();
});
JqId.find("svg[role='edit']").off().on("click", function () {
var oldsubname = $(this).parent().attr("subname");
var newsubname = $.trim(prompt("Edit below the subverse's name.", oldsubname));
if (newsubname === ""){return false;}
_this.module.EditShortcut(oldsubname, newsubname);
_this.Reload();
});
JqId.find("svg[role='down']").off().on("click", function () {
if ($(this).css("cursor") !== "pointer"){return;}
var subversesArr = _this.module.GetSubversesList();
var idx = $(this).parent().index() -1;
AVE.Utils.move(subversesArr, idx, idx+1);
_this.module.Store.SetValue(_this.module.StorageName, subversesArr.join(","));
_this.Reload();
});
JqId.find("svg[role='up']").off().on("click", function () {
if ($(this).css("cursor") !== "pointer"){return;}
var subversesArr = _this.module.GetSubversesList();
var idx = $(this).parent().index() -1;
AVE.Utils.move(subversesArr, idx, idx-1);
_this.module.Store.SetValue(_this.module.StorageName, subversesArr.join(","));
_this.Reload();
});
},
Reload: function () {
this.module.DisplayCustomSubversesList();
$(this.CSSselector).trigger("click"); //Reload-update
}
}
};
/// END Subverse and Set shortcuts ///
/// Archive submissions: Add a link to an archived version of the submission ///
AVE.Modules['ArchiveSubmission'] = {
ID: 'ArchiveSubmission',
Name: 'Archive submissions',
Desc: 'Add a link to an archived version of the submission',
Category: 'Subverse',
Index: 101,
Enabled: false,
Store: {},
RunAt: "container",
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
ArchiveSelfposts: {
Type: 'boolean',
Desc: "Archive self-posts as well.",
Value: false
},
WebArchive: {
Type: 'obj',
Desc: 'What archiving website do you want to use?',
Websites:
{'org': 'archive.org', // https://web.archive.org/web/*/URL
'is' : 'archive.is'}, // https://archive.is/?run=1&url=URL
// Add google-cache?
Value: "is"
}
},
OriginalOptions: "", //If ResetPref is used
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
ResetPref: function () {
this.Options = JSON.parse(this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if ($.inArray(AVE.Utils.currentPageType, ["frontpage", "set", "subverse", "thread", "domain", "user-submissions", "user-comments", "saved", "search"]) === -1) {
this.Enabled = false;
}
if (this.Enabled) {
this.Start();
}
},
Start: function () {
this.AppendToPage();
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPage: function () {
"use strict";
var _this = this;
$("ul.flat-list.buttons").each(function () {
if($(this).find("li > a#AVE_ArchiveSubmission_link").length>0) {return;} //Not already added
if(!_this.Options.ArchiveSelfposts.Value && $(this).parents("div.submission:first").hasClass("self")){return;} //Not a self-post
if($(this).find("li:first > a ").text()==="permalink"){return false;} //Not a comment (will break the loop if it is)
var url;
url = $(this).parents("div.entry:first").find("p.title > a.title").attr("href");
//If link to self-post: return. The only case where the archive link will be added to a self-post submissions is with stickies.
if (!/^http/.test(url)) { //if self-post
if (_this.Options.ArchiveSelfposts.Value)//recreate URL if chose to archive self-posts
{ url = "https://" + window.location.hostname + url; }
else //return here otherwise. Even though the function should have exited already by that point (only if not a sticky)
{ return; }
}
if (/^https?:\/\/archive\.is/.test(url)) {return;}
url = 'https://archive.is/?run=1&url='+encodeURIComponent(url);
$(this).append('
');
});
},
AppendToPreferenceManager: { //Use to add custom input to the pref Manager
html: function () {
var _this = AVE.Modules['ArchiveSubmission'];
var htmlStr = '';
htmlStr += '
The archiving website used is "archive.is". After opening a new page to archive.is, you may need to wait a second or two before being redirected to the archived page. If you are the first to open a particular page looking for an archived version, you will need to wait for it to be processed. Please let this process finish as it will help other users after you.
';
htmlStr += '';
return htmlStr;
}
}
};
/// END Archive submissions ///
/// Domain filter: Use filters to remove submissions linking to particular domains. ///
AVE.Modules['DomainFilter'] = {
ID: 'DomainFilter',
Name: 'Domain filter',
Desc: 'Use filters to remove submissions linking to particular domains.',
Category: 'Domains',
Index: 101,
Enabled: false,
Store: {},
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
Filters: {
Type: 'array',
Desc: "Example of filter",
Value: [] //not JSONified
}
},
filters: [],
Filter: function (id, keyword, sub) {
this.Id = id || 0;
this.Keywords = keyword || []; //List of keywords
this.ApplyToSub = sub || []; //List of subs
},
OriginalOptions: "",
SavePref: function (POST) {
var _this = this;
POST = POST[this.ID];
var id, kw, sub, tV;
this.Options.Filters.Value = [];
$.each(POST, function (k, v) {
tV = k.split("-");
if (tV.length === 2) {
id = parseInt(tV[0], 10);
} else { return true; } //if this isn't a filter value: continue
if (tV[1] === "kw") {
if (v.length === 0) { return true; } //If no kw were specified: continue
else {
_this.Options.Filters.Value.push(new _this.Filter(id, v.toLowerCase().split(","), []));
}
} else if (tV[1] === "sub") {
var inArr = $.grep(_this.Options.Filters.Value, function (e) { return e.Id === id; });
if (inArr.length === 0) {
//if there is no filter with this ID: continue
return true;
} else if (v.length !== 0) {
var idx = $.inArray(inArr[0], _this.Options.Filters.Value);
_this.Options.Filters.Value[idx].ApplyToSub = v.toLowerCase().split(",");
}
}
});
//print(JSON.stringify( _this.Options.Filters.Value));
this.Store.SetValue(this.Store.Prefix + this.ID,
JSON.stringify(
{
Enabled: POST.Enabled,
Filters: this.Options.Filters.Value
}
)
);
},
ResetPref: function () {
var _this = this;
_this.Options = JSON.parse(_this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = _this.Store.GetValue(_this.Store.Prefix + _this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
_this.Enabled = _this.Options.Enabled.Value;
},
Load: function () {
var _this = this;
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if ($.inArray(AVE.Utils.currentPageType, ["frontpage", "set", "subverse", "search", "domain", "user-submissions", "saved"]) === -1) {
this.Enabled = false;
}
if (this.Enabled) {
this.filters = jQuery.extend([], _this.Options.Filters.Value);
if (AVE.Modules['DomainTags'].Enabled){
var id = _this.Options.Filters.Value.length;
$.each(AVE.Modules['DomainTags'].DomainTags, function (name, tag) {
if (tag.i){
_this.filters.push(new _this.Filter(id++, [name.toLowerCase()]));
}
});
}
this.Start();
}
},
Start: function () {
var _this = this;
//When a submission is filtered it is simply removed, so no need to check anything special when the update method is triggered.
var re, found;
$("div.entry > p.title > span.domain > a").each(function () {
var DomainRef = $(this);
var DomainStr = DomainRef.text().toLowerCase(); //if str == self.(SubName) continue
$.each(_this.filters, function () {
found = false;
if (this.ApplyToSub.length === 0 || $.inArray(AVE.Utils.subverseName, this.ApplyToSub) !== -1) {
$.each(this.Keywords, function () {
if (this.length === 0) { return true;}//Just in case
// ((Start of string OR preceded by a period) OR (End of line OR followed by a period))
re = new RegExp("(^|\\.)"+this+"($|\\.)");
// An issue could arise if a filter matches a subdomain's name. Unfortunately, I cannot check to see if an TLD always follows.
if (re.test(DomainStr)) {
print("AVE: removed submission from domain \"" + DomainStr + "\" (kw: \"" + this + "\")");
DomainRef.parents("div.submission:first").remove();
found = true; //no point in continuing since the submission no longer exists
return false; //break
}
});
}
if (found) { return false; } //break
});
if (found) { return true; } //continue
});
},
Update: function () {//Use if this module needs to be update by UpdateAfterLoadingMore or NeverEndingVoat, remove otherwise
if (this.Enabled) {
this.Start();
}
},
AppendToPreferenceManager: { //Use to add custom input to the pref Manager
htmlNewFilter: '',
html: function () {
var _this = AVE.Modules['DomainFilter'];
var Pref_this = this;
var htmlStr = "";
this.htmlNewFilter = '\
Keyword(s) \
\
Subverse(s) \
\
\
-';
htmlStr += ' Example: "abc" matches "abc.com", "en.abc.com" but not "abcd.com". Separate keywords and subverse names by a comma. ';
var count = 0;
$.each(_this.Options.Filters.Value, function () {
var filter = Pref_this.htmlNewFilter + " ";
filter = filter.replace(/\{@id}/ig, count);
filter = filter.replace("{@keywords}", this.Keywords.join(","));
filter = filter.replace("{@subverses}", this.ApplyToSub.join(","));
count++;
htmlStr += filter;
});
htmlStr += 'Add new filter';
return htmlStr;
},
callback: function () {
var Pref_this = this;
var JqId = $("div#DomainFilter > div.AVE_ModuleCustomInput > a.RemoveFilter");
$("div#DomainFilter > div.AVE_ModuleCustomInput > a#AddNewFilter").on("click", function () {
var html = Pref_this.htmlNewFilter + " ";
html = html.replace(/\{@id\}/ig, parseInt($("div#DomainFilter > div.AVE_ModuleCustomInput > span.AVE_Domain_Filter:last").attr("id"), 10) + 1);
html = html.replace("{@keywords}", "");
html = html.replace("{@subverses}", "");
$(html).insertBefore("div#DomainFilter > div.AVE_ModuleCustomInput > a#AddNewFilter");
$("div#DomainFilter > div.AVE_ModuleCustomInput > a.RemoveFilter").off("click")
.on("click", function () {
print("Remove link: " + $(this).attr("id"), true);
print("Remove span: " + $(this).prev("span.AVE_Domain_Filter").attr("id"), true);
$(this).next("br").remove();
$(this).prev("span.AVE_Domain_Filter").remove();
$(this).remove();
});
AVE.Modules.PreferenceManager.ChangeListeners();
});
JqId.off("click");
JqId.on("click", function () {
$(this).next("br").remove();
$(this).prev("span.AVE_Domain_Filter").remove();
$(this).remove();
AVE.Modules.PreferenceManager.AddToModifiedModulesList("DomainFilter");
});
}
}
};
/// END Domain filter ///
/// Single click opener: Add "[l+c]" link to submission, opens link and comment pages. ///
AVE.Modules['SingleClickOpener'] = {
ID: 'SingleClickOpener',
Name: 'Single click opener',
Desc: 'Add "[l+c]" link to submission, opens link and comment pages.',
Category: 'Subverse',
Index: 102,
Enabled: false,
Store: {},
RunAt: "load",
Options: {
Enabled: {
Type: 'boolean',
Value: true
},
OpenInArchive: {
Type: 'boolean',
Desc: 'Open external link in archives.is.',
Value: false
}
},
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.SetOptionsFromPref();
if ($.inArray(AVE.Utils.currentPageType, ["frontpage", "set", "subverse", "search", "domain", "user-submissions", "saved"]) === -1) {
this.Enabled = false;
}
if (this.Enabled) {
this.Start();
}
},
Start: function () {
this.AppendToPage();
this.Listeners();
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPage: function () {
"use strict";
$("ul.flat-list.buttons").each(function () {
if ($(this).find("li > a#AVE_SingleClickOpener_link").length > 0) {return;}
if($(this).parents("div.submission:first").hasClass("self")){return;} //Not a self-post
$(this).append('
');
});
},
Listeners: function () {
"use strict";
var _this = this;
$("li > a#AVE_SingleClickOpener_link").off().on("click", function () {
var url = [];
url.push($(this).parents("div.entry:first").find("p.title > a.title").attr("href"));
url.push("https://" + window.location.hostname + $(this).parent().parent().find(":first-child > a.comments").attr("href"));
if (!/^http/.test(url[0])) { url[0] = "https://" + window.location.hostname + url[0]; }
if (_this.Options.OpenInArchive.Value && !/^https?:\/\/archive\.is/.test(url[0])){
url[0] = 'https://archive.is/?run=1&url='+encodeURIComponent(url[0]);
}
if (url[0] && url[0] === url[1]) {
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[0] });
} else {
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[0] });
AVE.Utils.SendMessage({ request: "OpenInTab", url: url[1] });
}
});
},
AppendToPreferenceManager: { //Use to add custom input to the pref Manager
html: function () {
var _this = AVE.Modules['SingleClickOpener'];
return ' ';
}
}
};
/// END Single click opener ///
/// Hide username: Options to hide or replace references to your username (not in posts). ///
AVE.Modules['HideUsername'] = {
ID: 'HideUsername',
Name: 'Hide username',
Desc: 'Options to hide or replace references to your username (not in posts).',
Category: 'Account',
//Should be loaded after the usertag module
Index: 150,
Enabled: false,
Store: {},
RunAt: "banner",
Options: {
Enabled: {
Type: 'boolean',
Value: false
},
NewName: {
Type: 'string',
Desc: "Replace with: ",
Value: ""
},
ReplaceEverywhere: {
Type: 'boolean',
Desc: 'Replace all references to your username.',
Value: false
},
RemoveInLoginBlock: {
Type: 'boolean',
Desc: 'Remove your username from the user info block.',
Value: false
}
},
OriginalOptions: "",
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
ResetPref: function () {
this.Options = JSON.parse(this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options); //If ResetPref is used
this.SetOptionsFromPref();
if (this.Enabled) {
this.Start();
}
},
Start: function () {
if (AVE.Utils.CurrUsername() === null) {return;}
if (this.Options.RemoveInLoginBlock.Value) {
$(".logged-in > .user > a[title='Profile']").remove();
} else if (!this.Options.ReplaceEverywhere.Value) {
$(".logged-in > .user > a[title='Profile']").text(this.Options.NewName.Value);
}
if (this.Options.ReplaceEverywhere.Value) {
$("a[href='/user/" + AVE.Utils.CurrUsername() + "'],a[href='/u/" + AVE.Utils.CurrUsername() + "']")
.not("#upvoatsGiven").filter(":parents(li.selected)")
.text(this.Options.NewName.Value);
}
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPreferenceManager: {
html: function () {
var _this = AVE.Modules['HideUsername'];
var htmlStr = '';
htmlStr += '';
htmlStr += ' ';
htmlStr += ' ' + _this.Options.NewName.Desc + '';
return htmlStr;
},
callback: function () {
}
}
};
/// END Hide username ///
/// Domain tags: Choose tags to characterize domains. ///
AVE.Modules['DomainTags'] = {
ID: 'DomainTags',
Name: 'Domain tags',
Desc: 'Choose tags to characterize domains.',
Category: 'Domains',
Index: 200,
Enabled: false,
Store: {},
RunAt: "container",
Options: {
Enabled: {
Type: 'boolean',
Value: false
}
},
Style: "",
DomainTags: "",
StorageName: "",
Processed: [],
DomainTagObj: function (tag, colour, ignore) {
this.t = tag.toString();
this.c = colour.toString();
this.i = !!ignore;
},
OriginalOptions: "",
SavePref: function (POST) {
POST = POST[this.ID];
this.Store.SetValue(this.Store.Prefix + this.ID, JSON.stringify(POST));
},
ResetPref: function () {
this.Options = JSON.parse(this.OriginalOptions);
},
SetOptionsFromPref: function () {
var _this = this;
var Opt = this.Store.GetValue(this.Store.Prefix + this.ID, "{}");
$.each(JSON.parse(Opt), function (key, value) {
if (!_this.Options.hasOwnProperty(key)) {print("AVE: loading "+_this.ID+" > option key " +key+" doesn't exist", true);return true;}
_this.Options[key].Value = value;
});
this.Enabled = this.Options.Enabled.Value;
},
Load: function () {
this.Store = AVE.Storage;
this.OriginalOptions = JSON.stringify(this.Options);
this.SetOptionsFromPref();
if (this.Enabled) {
this.style =
'div.AVE_Domain_tag {' +
' margin-left: 5px;' +
' cursor: pointer;' +
' display: inline-block;' +
'}' +
'div.AVE_Domaintag_box > span {' +
' cursor: pointer;' +
' font-size: 14px;' +
' margin-left: 2px;' +
' margin-right: 2px;' +
'}' +
'div.AVE_Domaintag_box > div#ColourDot {' +
' width: 15px;' +
' height: 15px;' +
' border-radius: 10px;' +
' display: inline;' +
' float: right;' +
' margin: 2px 8px 2px 0px;' +
' border: 2px solid #' + (AVE.Utils.CSSstyle === "dark" ? "000" : "AAA") + ';' +
' cursor: pointer;' +
'/* overrides */' +
//' width: 20px;' +
//' height: 20px;' +
//' border-radius: 0px 10px 10px 0px;' +
//' display: inline;' +
//' float: right;' +
//' margin: 0px 5px 0px 0px;' +
//' border: 2px solid #' + (AVE.Utils.CSSstyle === "dark" ? "000" : "AAA") + ';' +
//' cursor: pointer;' +
//' min-width: 10px;' +
//' border-width: 0px 2px 0px 1px;' +
'}' +
'div.AVE_Domaintag_box > input[type="text"] {' +
' height: 20px;' +
' width: 220px;' +
' border: none;' +
' border-left: 1px solid #' + (AVE.Utils.CSSstyle === "dark" ? "000" : "AAA") + ';' +
' border-right: 1px solid #' + (AVE.Utils.CSSstyle === "dark" ? "000" : "AAA") + ';' +
' padding-left: 5px;' +
' background-color: #' + (AVE.Utils.CSSstyle === "dark" ? "414141" : "F8F8F8") + ';' +
'}' +
'div.AVE_Domaintag_box {' +
'background-color: #' + (AVE.Utils.CSSstyle === "dark" ? "333" : "FFF") + ';' +
(AVE.Utils.CSSstyle === "dark" ? "" : "color: #707070;") +
'z-index: 1000 !important;' +
'position:absolute;' +
'left:0px;' +
'top:0px;' +
'border: 2px solid #' + (AVE.Utils.CSSstyle === "dark" ? "000" : "AAA") + ';' +
'border-radius:3px;' +
'width:320px;' +
'}' +
'div.AVE_Domain_tag > svg {' +
' vertical-align: middle;' +
'}' +
'div.AVE_Domaintag_box > svg {' +
' vertical-align: middle;' +
' margin-left: 2px;' +
'}';
AVE.Utils.AddStyle(this.style);
this.StorageName = this.Store.Prefix + this.ID + "_Tags";
this.DomainTags = JSON.parse(this.Store.GetValue(this.StorageName, "{}"));
this.Start();
}
},
Start: function () {
this.AppendToPage();
this.Listeners();
},
Update: function () {
if (this.Enabled) {
this.Start();
}
},
AppendToPage: function () {
"use strict";
var _this = this;
$("p.title > span.domain > a").each(function () {
var id = $(this).parents("div.submission[class*='id-']:first").attr("data-fullname");
if ($.inArray(id, _this.Processed) !== -1){return true;}
else {_this.Processed.push(id);}
var domain;
var tag, colour;
domain = $(this).text();
if (_this.DomainTags[domain]) {
tag = _this.DomainTags[domain].t;
colour = _this.DomainTags[domain].c;
}
//Commented out so that we can tag subverses too (self-text submissions).
//if (/self\.[a-zA-Z0-9]?/.test(domain)){return true;}
if ($(this).parent().find("div.AVE_Domain_tag").length === 0) {
$('').insertAfter($(this));
var el = $(this).parent().find("div.AVE_Domain_tag");
if (!tag && !colour) {
el.html('');
el.attr("title", "Click to create a new tag");
} else {
if (!tag) { tag = "No tag"; }
else if (!colour) { colour = (AVE.Utils.CSSstyle === "dark" ? "777" : "BBB"); }
el.attr("title", tag);
el.html('');
}
}
});
},
Listeners: function () {
"use strict";
var _this = this;
$("div.AVE_Domain_tag").off().on("click", function (e) {
//e.stopPropagation();
var domain, box;
var tag, colour, ignore;
domain = $(this).parent().find("a").text();
if (_this.DomainTags[domain]) {
tag = _this.DomainTags[domain].t;
colour = _this.DomainTags[domain].c;
ignore = _this.DomainTags[domain].i;
}
box = $("div.AVE_Domaintag_box");
if (box.length === 0){
var boxHtml;
boxHtml = '' +
'
' +
' ' +
' ' +
' ' +
' ✖' +
' ✔' +
' ' +
'
'; //Weird css values for the colour input because of Chrome not wanting to trigger it if hidden with "display:none;"
$("body").append(boxHtml);
box = $("div.AVE_Domaintag_box");
box.find("div#ColourDot").on("click", function () {
var dot = $(this);
dot.parent().find("input[type='color']")
.trigger("click")
.on("change", function () {
dot.css("background-color", $(this).val());
dot.parent().find("svg:first").find("path").css("fill", $(this).val());
});
});
box.find("input[type='text']").on("input", function () {
box.find("svg:first").attr("title", $(this).val() || "No tag");
});
box.find("svg:last").off().on("click", function () {
var Opt;
if (!AVE.Modules['DomainFilter'].Enabled){
if (!confirm("This feature relies on DomainFilter to work, but this module is disabled.\nDo you want to activate it?")){
return;
} else {
Opt = JSON.parse(_this.Store.GetValue(_this.Store.Prefix + AVE.Modules['DomainFilter'].ID, "{}"));
Opt.Enabled = true;
_this.Store.SetValue(_this.Store.Prefix + AVE.Modules['DomainFilter'].ID, JSON.stringify(Opt));
print("AVE: DomainFilter > Enabled by DomainTag");
}
}
var poly = $(this).find("polyline");
poly.css("stroke-width", poly.css("stroke-width") !== "2px" ? "2px" : "0px");
});
box.find("span#cancel").off().on("click", function () {
box.hide();
});
box.find("span#submit").off().on("click", function () {
domain = box.attr("domain");
tag = box.find("input[type='text']").val();
colour = box.find("input[type='color']").val();
ignore = box.find("svg > polyline").css("stroke-width") === "2px";
_this.setTag(domain, tag, colour, ignore);
_this.updateTag(domain);
box.hide();
});
box.hide();
}
var position = $(this).offset();
position.top -= 5;
position.left = Math.max(position.left - 280, 20);
box.css(position)
.show();
box.attr("domain", domain);
box.find("input[type='text']").val(tag).select();
box.find("input[type='color']").val(colour || (AVE.Utils.CSSstyle === "dark" ? "#438BB7" : "#4AABE7"));
box.find("div#ColourDot").css("background-color", colour || (AVE.Utils.CSSstyle === "dark" ? "#438BB7" : "#4AABE7"));
box.find("svg:first").find("path").css("fill", colour || (AVE.Utils.CSSstyle === "dark" ? "#438BB7" : "#4AABE7"));
box.find("svg:first").attr("title", tag || "No tag");
box.find("svg:last > polyline").css("stroke-width", ignore ? "2px" : "0px");
});
$(document).on("keyup", function (e) {
var box = $("div.AVE_Domaintag_box");
if (box.is(":visible")){
//print(e.key + " - "+e.which);
if (e.which === 13) { //enter
if ($(e.target).attr("id") === "AVE_Domaintag_box_textinput") {
box.find("span#submit").trigger("click");
}
}
else if (e.which === 27) { //escape
box.find("span#cancel").trigger("click");
}
}
});
},
updateTag: function (domain) {
"use strict";
var _this = this;
$("p.title > span.domain > a:textEquals("+domain+")").each(function(){
var tag, colour, ignore;
if (_this.DomainTags[domain]) {
tag = _this.DomainTags[domain].t;
colour = _this.DomainTags[domain].c;
ignore = _this.DomainTags[domain].i || false;
}
var el = $(this).parent().find("div.AVE_Domain_tag");
if(!el){return;}
if (!tag && !colour) {
el.html('');
el.attr("title", "Click to create a new tag");
} else {
if (!tag) { tag = "No tag"; }
else if (!colour) { colour = (AVE.Utils.CSSstyle === "dark" ? "777" : "BBB"); }
el.attr("title", tag);
el.html('');
}
});
},
setTag: function (domain, tag, colour, ignore) {
"use strict";
var obj = new this.DomainTagObj(tag, colour, ignore);
if(!obj.t && !obj.c){return;}
this.DomainTags[domain] = obj;
//print(JSON.stringify(this.DomainTags[domain]));
this.Store.SetValue(this.StorageName, JSON.stringify(this.DomainTags));
},
removeTag: function (domain) {
"use strict";
delete this.DomainTags[domain];
this.Store.SetValue(this.StorageName, JSON.stringify(this.DomainTags));
},
AppendToPreferenceManager: {
html: function () {
"use strict";
var _this = AVE.Modules['DomainTags'];
var htmlStr = '' +
'' +
' Click the default icon () to display the tagbox and create a new tag.' +
' Move your mouse over the I icon () to see the tag, click this icon to edit the current tag.' +
' You don\'t have to choose a tag label to create a new domainTag; a colour alone is enough.';
if (_this.Enabled){
var len = Object.keys(_this.DomainTags).length;
htmlStr += '
Click on a value to modify it.'+
' Click the buttons on either sides to navigate through the table pages or use the arrow keys (+Ctrl to go to the first or last page)';
return htmlStr;
},
callback: function () {
"use strict";
var _this = this;
$('table#AVE_Dashboard_domaintags_table > tbody > tr > td:last-child') //remove
.off()
.on("mouseover", function () {
$(this).parent().css("background", _this.MouseOverColours[1]);
})
.on("mouseleave", function () {
$(this).parent().css("background", "");
})
.on("click", function () {
var name = $(this).parent().attr("domain");
if (confirm("Are you sure you want to delete the tag attached to \""+name+"\"?")){
_this.module.removeTag(name);
$(_this.CSSselector).trigger("click");
}
});
$('table#AVE_Dashboard_domaintags_table > tbody > tr > td:nth-child(2)') //edit tag
.off()
.on("click", function (e, artificial) {
var tag = $(this).text() || $(this).find("input").val() || "";
if ($(this).find("input").length === 0){
$(this).html('');
var input = $(this).find("input");
input.focus().select();
input.one("focusout", function () {
input.val(input.attr("original"));
$(this).trigger("click", true);
});
} else {
if (!artificial) {return;}//we don't want to lose the focus because of a click in the same input text
$(this).find("input").off();
$(this).html(''+tag+'');
}
});
$('table#AVE_Dashboard_domaintags_table > tbody > tr > td:nth-child(3)') //edit colour
.off()
.on("click", function (e, artificial) {
var colour = $(this).text() || $(this).find("input").val();
if ($(this).find("input").length === 0){
var input = $("input#AVE_Dashboard_domaintags_quickedit[type='color'][data='colour']");
input.attr("original", colour).attr("u", $(this).parent().attr("domain")).val(colour);
input.one("change", function () {
_this.editTag(input, "colour");
});
input.show().css("opacity", "0"); //Because of Chrome which doesn't want to show the colour palette if the input is hidden ("display: none;")
input.trigger("click");
} else {
if (!artificial) {return;}//we don't want to lose the focus by a click in the same input text
$(this).find("input").off();
$(this).html(''+colour+'');
}
});
$('table#AVE_Dashboard_domaintags_table > tbody > tr > td:nth-child(4)') //edit ignore
.off()
.on("click", function () {
var ignore, newval;
ignore = $(this).text();
newval = ignore === "No" ? "Yes" : "No";
$(this).text(newval);
_this.editTag($(this), "ignore");
});
$('a#AVE_Dashboard_navigate_tags') //navigate with buttons
.off()
.on("click", function () {
if ($(this).hasClass("btn-unsub")){return false;}
switch ($(this).attr('role')) {
case "prev":
_this.currpage--;
break;
case "next":
_this.currpage++;
break;
case "first":
_this.currpage = 0;
break;
case "last":
_this.currpage = Math.ceil((_this.domaintags.length - _this.tagsperpage) / _this.tagsperpage);
break;
default:
return;
}
$(_this.CSSselector).trigger("click");
});
$(document)
.off()
.on("keyup", function (event) {
var ctrl, pos, input;
ctrl= event.ctrlKey;
input = $("input#AVE_Dashboard_domaintags_quickedit:not([type='color'])");
if (input.length === 0){ //navigate with arrow keys
//We don't want to change page when a user is using the arrow key to edit a value
if (event.which === 37){
pos = (ctrl ? "first" : "prev");
} else if (event.which === 39){
pos = (ctrl ? "last" : "next");
}
if (pos){
$('a#AVE_Dashboard_navigate_tags[role="'+ pos +'"]:first').trigger("click");
}
}
if (event.which === 13){ //Press enter to confirm change
_this.editTag(input, input.attr("data"));
}
});
},
editTag: function (input, dtype) {
"use strict";
var _this = this;
if (input.length === 1){
if (input.attr("original") === input.val() && dtype !== "ignore"){input.trigger("click", true);return;}//No need to update nor reload if nothing changed
var root, tag, colour;
if (dtype === "colour"){
var u = input.attr("u");
root = $("tr[domain='"+u+"']");
} else {
root = input.parents("tr:first");
}
var domain = root.attr("domain");
var ignore = root.find("td[data='ignore']").text() === "Yes";
if (dtype === "tag"){
tag = input.val();
} else {
tag = root.find("td[data='tag']").text();
}
if (dtype === "colour"){
colour = input.val() || input.attr("original");
} else {
colour = root.find("td[data='colour']").text();
}
_this.module.setTag(domain, tag, colour, ignore); //save tag
$(_this.CSSselector).trigger("click"); //Reload-update
}
},
navbuttons: function () {
var htmlNavButtons = "";
htmlNavButtons += '
';
return htmlNavButtons;
},
paging: function (start, nb) {
var colour, r, g, b, bestColour;
var htmlStr = "";
var obj = {};
var direct = false;
for (var i=start; i <= start+nb-1; i++){
if (i >= this.domaintags.length){break;}
obj = JSON.parse(this.domaintags[i]);
colour = AVE.Utils.GetRGBvalues(obj.c);
r = colour[0]; g = colour[1]; b = colour[2];
bestColour = AVE.Utils.GetBestFontColour(r, g, b);
direct = /v\/[a-zA-Z0-9]?/.test(obj.name);
htmlStr += '
' +
'DO NOT FORGET that your account information are stored unencrypted in AVE\'s data when you export it to a JSON file!';
return htmlStr;
}
}
};
/// END Account Switcher ///
/// AVE\'s dashboard: Use it to manage your saved data. ///
AVE.Modules['Dashboard'] = {
ID: 'Dashboard',
Name: 'AVE\'s dashboard',
Desc: 'Use it to manage your saved data.',
Category: null,
//Category set to null will make this module invisible to the pref-mngr
Index: 1000,
Enabled: false,
Store: {},
RunAt: "container",
Modules: {
"UserTag": "User tags",
"DomainTags": "Domain tags",
"Shortcuts": "Subverse shortcuts",
"ToggleCustomStyle": "Custom style permissions"},
Load: function () {
if (AVE.Utils.currentPageType === "user-manage"){
this.Enabled = true;
}
if (this.Enabled){
this.Start();
}
},
Start: function () {
this.AppendToPage();
this.Listeners();
if(location.hash === "#dashboard"){
$("a#AVE_ShowDashboard:first").trigger("click");
}
},
AppendToPage: function () {
"use strict";
var TempHtml;
var _this = this;
if ($("a#AVE_ShowDashboard").length === 0){
TempHtml = '
Show dashboard';
$.each(_this.Modules, function (id, name) {
/*
Subverse list (rearrange, delete, update, add(list",")
ToggleCustomStyle (stored subverse and if show or hide)
*/
//Replace buttons with a droplist
TempHtml += ''+name+'';
});
TempHtml += '
Click one of the buttons above to display the data associated with it. ';
TempHtml += ' Nota Bene: stored data aren\'t cached; they are retrieved and processed every time you click one of the button to always display the most up to date values.
';
TempHtml +='';
JqId.append(TempHtml);
}
},
Listeners: function () {
var _this = this;
$("a#AVE_ShowDashboard")
.off("click")
.on("click", function () {_this.ToggleMainContent();});
$("a[id^='AVE_Dashboard_Show']")
.off("click")
.on("click", function () {
"use strict";
_this.ToggleContent($(this).attr("name"), $(this).text());
});
},
ToggleContent: function (module, name) {
if (AVE.Modules[module].AppendToDashboard !== undefined) {
if (typeof AVE.Modules[module].AppendToDashboard.html === "function") {
var html;
html = '
'+name+'
';
html += '';
html += AVE.Modules[module].AppendToDashboard.html();
html +='';
$('div.content#AVE_Dashboard_content[role="default"] > div.row.nomargin').html(html);
} else {print("AVE: Dashboard > Module \""+module+"\" doesn't implement function \"AppendToPreferenceManager.html()\"");return;}
if (typeof AVE.Modules[module].AppendToDashboard.callback === "function") {
AVE.Modules[module].AppendToDashboard.callback();
}
} else {print("AVE: Dashboard > Module \""+module+"\" doesn't implement asso. array \"AppendToPreferenceManager\"");}
},
ToggleMainContent: function(){
"use strict";
var JqMain = $('div.content[role="main"]:first');
var JqNew = $('div.content#AVE_Dashboard_content[role="default"]');
if (JqMain.is(":visible")){
JqMain.hide();
JqNew.show();
$("a[id^='AVE_Dashboard_Show']").show();
$("a#AVE_ShowDashboard").text("Hide Dashboard");
document.title = "Manage AVE's Data";
location.hash = "#dashboard";
} else {
JqMain.show();
JqNew.hide();
$("a[id^='AVE_Dashboard_Show']").hide();
$("a#AVE_ShowDashboard").text("Show Dashboard");
document.title = "Manage Account";
location.hash = "";
}
}
};
/// END AVE\'s dashboard ///
/// Build Dependent ///
AVE.Utils.SendMessage = function (Obj, callback) {
switch (Obj.request) {
case "Storage":
switch (Obj.type) {
case "SetValue":
GM_setValue(Obj.key, Obj.value);
break;
case "DeleteValue":
GM_deleteValue(Obj.key);
break;
case "Update":
AVE.Storage.Data = {};
$.each(GM_listValues(), function () {
AVE.Storage.Data[this] = GM_getValue(this.toString());
});
break;
}
break;
case 'OpenInTab':
GM_openInTab(Obj.url);
break;
}
if (Obj.hasOwnProperty("callback")){
Obj.callback();
}
};
AVE.Utils.MetaData = { version: GM_info.script.version, name: GM_info.script.name };
AVE.Utils.SendMessage({ request: "Storage", type: "Update"});
AVE.Init.Start();
/// END Build Dependent ///