"use strict";
// libavtools /REQUIRES/ a modern browser. IE won't cut it.
// It may be possible to remove references to caching code in the future, but the cache provides a massive load-time save.
// Replace all for .. in .. with
// for (let [key, value] of Object.entries(...))
if (window.avtools === undefined) {
let avt = {};
window.avtools = avt;
avt.Edit = class {
constructor(editor, target_page, net_change, revision_id, timestamp, prev_revision_id, diff) {
this.editor = editor; /* String */
this.target_page = target_page; /* String */
this.net_change = net_change; /* Integer */
this.revision_id = revision_id; /* Integer */
this.timestamp = timestamp;
this.prev_revision_id = prev_revision_id; /* Integer */
this.diff = diff /* ?????? TODO: figure out diff format to use. */
}
};
avt.programmatic_filters = {};
avt.programmatic_filters.is_mostly_caps = function (_, target) {
const len = target.match(/[A-Z]/gu);
return { "is_match": ((len ? len.length : 0) > (target.length/4)), "progfilt_results": {} }; // if over half of target is caps, it's a match.
}
avt.MatchFilter = class {
constructor(name, config) {
if (config.regex && config.programmatic_check) {
throw new Error("Cannot match " + name + "using both regex and programmatic check!");
}
if (config.regex) {
this.regex = new RegExp(config.regex, config.flags ? config.flags : "gui");
} else if (config.programmatic_check) {
this.check_func = avt.programmatic_filters[config.programmatic_check];
if (!this.check_func) {
throw new Error(name + "specifies an invaild programmatic check!");
}
} else {
/* ignore, likely a placeholder. */
}
this.show_matches = config.show_matches;
this.severity = config.severity;
}
match(target) {
let match = {};
if (this.regex) {
let nreg = new RegExp(this.regex); // duplicate..
let m;
match.regex_results = [];
while ((m = nreg.exec(target)) !== null) {
match.regex_results.push({res: m, index: m.index, lastIndex: nreg.lastIndex});
}
if (match.regex_results[0] !== undefined) {
match.is_match = true;
} else {
match.is_match = false;
}
if (this.show_matches === false) {
match.regex_results = undefined;
}
} else {
match = this.check_func(this.flags, target);
}
return match;
}
}
avt.avtools_central_config = "User:Moonythedwarf/libavtools/global_config.json";
avt.avtools_user_config = "Special:MyPage/libavtools/config.json";
avt.load_json_file = async function (wikilink) {
let req = new Request(`${mw.util.wikiScript("index")}?title=${wikilink}&action=raw&ctype=text/json`);
let res = await avt.__cache.match(req);
// JS error handling much?
if (res === undefined ) {
let resp = await fetch(req);
await avt.__cache.put(req, resp);
return (await avt.__cache.match(req)).text();
}
return res.text()
}
avt.load_multiple_json_files = async function (links) {
let loaded_files = [];
for (const i in links) {
loaded_files.push(avt.load_json_file(links[i]));
}
return (Promise.all(loaded_files)).then(a => a.filter(val => val !== "" ? true : false));
}
avt.load_avtools_config = async function () {
if (avt.config !== undefined) {
return;
}
const global_config = JSON.parse(await avt.load_json_file(avt.avtools_central_config));
const lc_data = await avt.load_json_file(avt.avtools_user_config);
const local_config = JSON.parse(lc_data? lc_data : "{}");
let final_config = {};
//FIX: Crude. Will need proper precedence rules later.
for (const i in global_config) {
if (local_config[i] !== undefined) {
final_config[i] = local_config[i];
} else {
final_config[i] = global_config[i];
}
}
avt.config = final_config;
}
avt.load_filters = function (list) {
let filters = {};
for (let fname in list) {
for (let i in list[fname]) {
filters[i] = new avt.MatchFilter(fname, list[fname][i]);
}
}
return filters;
}
avt.match_against_filters = function (filters, target) {
let matches = {};
let severity = 0;
for (const filtname in filters) {
const filtmatches = filters[filtname].match(target);
if (filtmatches.is_match) {
matches[filtname] = filtmatches;
severity += filters[filtname].severity;
}
}
return { matches, severity };
}
avt.load_username_filters = async function () {
let loaded_files = (await avt.load_multiple_json_files(avt.config.username_filters)).map(i => JSON.parse(i));
avt.username_filters = avt.load_filters(loaded_files);
}
avt.load_content_filters = async function () {
let loaded_files = (await avt.load_multiple_json_files(avt.config.content_filters)).map(i => JSON.parse(i));
avt.content_filters = avt.load_filters(loaded_files);
}
avt.load_summary_filters = async function () {
let loaded_files = (await avt.load_multiple_json_files(avt.config.summary_filters)).map(i => JSON.parse(i));
avt.summary_filters = avt.load_filters(loaded_files);
}
avt.load_all_filters = async function (config) {
return Promise.all([
avt.load_summary_filters(),
avt.load_content_filters(),
avt.load_username_filters(),
]);
}
avt.wipe_cache = async function () {
for (let v of await avt.__cache.keys()) {
await avt.__cache.delete(v); //snip!
}
}
avt.load_libavtools_core = async function () {
avt.__cache = await caches.open("avtcache");
await avt.load_avtools_config();
};
avt.load_libavtools_filters = async function () {
if (avt.config === undefined) {
throw new Error("Attempted to load libavtools filters before core!");
}
await avt.load_all_filters();
}
$(async () => {
try {
await avt.load_libavtools_core();
} catch (e) {
mw.notify(e)
}
})
}