Untitled diff

Created Diff never expires
// ==UserScript==
// ==UserScript==
// @name Stack-Exchange-Editor-Toolkit
// @name Stack-Exchange-Editor-Toolkit
// @author Cameron Bernhardt (AstroCB)
// @author Cameron Bernhardt (AstroCB)
// @developer Jonathan Todd (jt0dd)
// @developer Jonathan Todd (jt0dd)
// @developer sathyabhat
// @developer sathyabhat
// @contributor Unihedron
// @contributor Unihedron
// @contributor Tiny Giant
// @contributor Tiny Giant
// @contributor Mogsdad
// @contributor Mogsdad
// @grant none
// @grant none
// @license MIT
// @license MIT
// @namespace http://github.com/AstroCB
// @namespace http://github.com/AstroCB
// @version 1.5.2.4
// @version 1.5.2.5
// @description Fix common grammar/usage annoyances on Stack Exchange posts with a click
// @description Fix common grammar/usage annoyances on Stack Exchange posts with a click
// @include *://*.stackexchange.com/questions/*
// @include *://*.stackexchange.com/questions/*
// @include *://stackoverflow.com/questions/*
// @include *://stackoverflow.com/questions/*
// @include *://stackoverflow.com/review/helper/*
// @include *://stackoverflow.com/review/helper/*
// @include *://meta.stackoverflow.com/questions/*
// @include *://meta.stackoverflow.com/questions/*
// @include *://serverfault.com/questions/*
// @include *://serverfault.com/questions/*
// @include *://meta.serverfault.com/questions/*
// @include *://meta.serverfault.com/questions/*
// @include *://superuser.com/questions/*
// @include *://superuser.com/questions/*
// @include *://meta.superuser.com/questions/*
// @include *://meta.superuser.com/questions/*
// @include *://askubuntu.com/questions/*
// @include *://askubuntu.com/questions/*
// @include *://meta.askubuntu.com/questions/*
// @include *://meta.askubuntu.com/questions/*
// @include *://stackapps.com/questions/*
// @include *://stackapps.com/questions/*
// @include *://*.stackexchange.com/posts/*
// @include *://*.stackexchange.com/posts/*
// @include *://stackoverflow.com/posts/*
// @include *://stackoverflow.com/posts/*
// @include *://meta.stackoverflow.com/posts/*
// @include *://meta.stackoverflow.com/posts/*
// @include *://serverfault.com/posts/*
// @include *://serverfault.com/posts/*
// @include *://meta.serverfault.com/posts/*
// @include *://meta.serverfault.com/posts/*
// @include *://superuser.com/posts/*
// @include *://superuser.com/posts/*
// @include *://meta.superuser.com/posts/*
// @include *://meta.superuser.com/posts/*
// @include *://askubuntu.com/posts/*
// @include *://askubuntu.com/posts/*
// @include *://meta.askubuntu.com/posts/*
// @include *://meta.askubuntu.com/posts/*
// @include *://stackapps.com/posts/*
// @include *://stackapps.com/posts/*
// @include *://*.stackexchange.com/review/*
// @include *://*.stackexchange.com/review/*
// @include *://stackoverflow.com/review/*
// @include *://stackoverflow.com/review/*
// @include *://meta.stackoverflow.com/review/*
// @include *://meta.stackoverflow.com/review/*
// @include *://serverfault.com/review/*
// @include *://serverfault.com/review/*
// @include *://meta.serverfault.com/review/*
// @include *://meta.serverfault.com/review/*
// @include *://superuser.com/review/*
// @include *://superuser.com/review/*
// @include *://meta.superuser.com/review/*
// @include *://meta.superuser.com/review/*
// @include *://askubuntu.com/review/*
// @include *://askubuntu.com/review/*
// @include *://meta.askubuntu.com/review/*
// @include *://meta.askubuntu.com/review/*
// @include *://stackapps.com/review/*
// @include *://stackapps.com/review/*
// @exclude *://*.stackexchange.com/questions/tagged/*
// @exclude *://*.stackexchange.com/questions/tagged/*
// @exclude *://stackoverflow.com/questions/tagged/*
// @exclude *://stackoverflow.com/questions/tagged/*
// @exclude *://meta.stackoverflow.com/questions/tagged/*
// @exclude *://meta.stackoverflow.com/questions/tagged/*
// @exclude *://serverfault.com/questions/tagged/*
// @exclude *://serverfault.com/questions/tagged/*
// @exclude *://meta.serverfault.com/questions/*
// @exclude *://meta.serverfault.com/questions/*
// @exclude *://superuser.com/questions/tagged/*
// @exclude *://superuser.com/questions/tagged/*
// @exclude *://meta.superuser.com/questions/tagged/*
// @exclude *://meta.superuser.com/questions/tagged/*
// @exclude *://askubuntu.com/questions/tagged/*
// @exclude *://askubuntu.com/questions/tagged/*
// @exclude *://meta.askubuntu.com/questions/tagged/*
// @exclude *://meta.askubuntu.com/questions/tagged/*
// @exclude *://stackapps.com/questions/tagged/*
// @exclude *://stackapps.com/questions/tagged/*
// ==/UserScript==
// ==/UserScript==
var main = function() {
var main = function() {
// Define app namespace
// Define app namespace
function EditorToolkit(targetID) {
function EditorToolkit(inline, targetID) {
if (!(this instanceof EditorToolkit)) return false;
if (!(this instanceof EditorToolkit)) return false;


var App = this;
var App = this;


// Place edit items here
// Place edit items here
App.items = [];
App.items = [];


// Place selected jQuery items here
// Place selected jQuery items here
App.selections = {};
App.selections = {};


// Place "global" app data here
// Place "global" app data here
App.globals = {};
App.globals = {};


// Place "helper" functions here
// Place "helper" functions here
App.funcs = {};
App.funcs = {};


//Preload icon alt
//Preload icon alt
var SEETicon = new Image();
var SEETicon = new Image();


SEETicon.src = '//i.imgur.com/d5ZL09o.png';
SEETicon.src = '//i.imgur.com/d5ZL09o.png';


// Define variables for later use
// Define variables for later use
App.globals.barReady = false;
App.globals.barReady = false;
App.globals.editsMade = false;
App.globals.editsMade = false;
App.globals.editCount = 0;
App.globals.editCount = 0;
App.globals.infoContent = '';
App.globals.infoContent = '';


// Check if there was an ID passed (if not, use question ID from URL);
// Check if there was an ID passed (if not, use question ID from URL);
if (!targetID) targetID = window.location.href.match(/\/(\d+)\//g)[0].split("/").join("");
if (!targetID) targetID = window.location.href.match(/\/(\d+)\//g)[0].split("/").join("");
App.globals.targetID = targetID;
App.globals.targetID = targetID;
App.globals.inline = inline;


App.globals.spacerHTML = '<li class="wmd-spacer wmd-spacer3" id="wmd-spacer3-' + App.globals.targetID + '" style="left: 400px !important;"></li>';
App.globals.spacerHTML = '<li class="wmd-spacer wmd-spacer3" id="wmd-spacer3-' + App.globals.targetID + '" style="left: 400px !important;"></li>';


App.selections.buttonWrapper = $('<div class="ToolkitButtonWrapper"/>');
App.selections.buttonWrapper = $('<div class="ToolkitButtonWrapper"/>');
App.selections.buttonFix = $('<button class="wmd-button ToolkitFix" />');
App.selections.buttonFix = $('<button class="wmd-button ToolkitFix" />');
App.selections.buttonInfo = $('<div class="ToolkitInfo">');
App.selections.buttonInfo = $('<div class="ToolkitInfo">');


App.selections.buttonWrapper.append(App.selections.buttonFix);
App.selections.buttonWrapper.append(App.selections.buttonFix);
App.selections.buttonWrapper.append(App.selections.buttonInfo);
App.selections.buttonWrapper.append(App.selections.buttonInfo);


App.globals.reasons = [];
App.globals.reasons = [];
App.globals.numReasons = 0;
App.globals.numReasons = 0;


App.globals.replacedStrings = {
App.globals.replacedStrings = {
"block": [],
"block": [],
"inline": []
"inline": []
};
};
App.globals.placeHolders = {
App.globals.placeHolders = {
"block": "_xCodexBlockxPlacexHolderx_",
"block": "_xCodexBlockxPlacexHolderx_",
"inline": "_xCodexInlinexPlacexHolderx_"
"inline": "_xCodexInlinexPlacexHolderx_"
};
};
App.globals.checks = {
App.globals.checks = {
"block": /( )+.*/gm,
"block": /( )+.*/gm,
"inline": /`.*`/gm
"inline": /`.*`/gm
};
};


// Assign modules here
// Assign modules here
App.globals.pipeMods = {};
App.globals.pipeMods = {};


// Define order in which mods affect here
// Define order in which mods affect here
App.globals.order = ["omit", "edit", "replace"];
App.globals.order = ["omit", "edit", "replace"];




// Define edit rules
// Define edit rules
App.edits = {
App.edits = {
i: {
i: {
expr: /(^|\s|\()i(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
expr: /(^|\s|\()i(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
replacement: "$1I$2",
replacement: "$1I$2",
reason: "in English, the personal pronoun is 'I'"
reason: "in English, the personal pronoun is 'I'"
},
},
so: {
so: {
expr: /(^|\s)[Ss]tack\s*overflow|StackOverflow(.|$)/gm,
expr: /(^|\s)[Ss]tack\s*overflow|StackOverflow(.|$)/gm,
replacement: "$1Stack Overflow$2",
replacement: "$1Stack Overflow$2",
reason: "'Stack Overflow' is the legal name"
reason: "'Stack Overflow' is the legal name"
},
},
se: {
se: {
expr: /(^|\s)[Ss]tack\s*exchange|StackExchange(.|$)/gm,
expr: /(^|\s)[Ss]tack\s*exchange|StackExchange(.|$)/gm,
replacement: "$1Stack Exchange$2",
replacement: "$1Stack Exchange$2",
reason: "'Stack Exchange' is the legal name"
reason: "'Stack Exchange' is the legal name"
},
},
expansionSO: {
expansionSO: {
expr: /(^|\s)SO(\s|,|\.|!|\?|;|\/|\)|$)/gm,
expr: /(^|\s)SO(\s|,|\.|!|\?|;|\/|\)|$)/gm,
replacement: "$1Stack Overflow$2",
replacement: "$1Stack Overflow$2",
reason: "'SO' expansion"
reason: "'SO' expansion"
},
},
expansionSE: {
expansionSE: {
expr: /(^|\s)SE(\s|,|\.|!|\?|;|\/|\)|$)/gm,
expr: /(^|\s)SE(\s|,|\.|!|\?|;|\/|\)|$)/gm,
replacement: "$1Stack Exchange$2",
replacement: "$1Stack Exchange$2",
reason: "'SE' expansion"
reason: "'SE' expansion"
},
},
javascript: {
javascript: {
expr: /(^|\s)[Jj]ava\s*[Ss]cript(.|$)/gm,
expr: /(^|\s)[Jj]ava\s*[Ss]cript(.|$)/gm,
replacement: "$1JavaScript$2",
replacement: "$1JavaScript$2",
reason: "'JavaScript' is the proper capitalization"
reason: "'JavaScript' is the proper capitalization"
},
},
jsfiddle: {
jsfiddle: {
expr: /(^|\s)[Jj][Ss]\s*[Ff]iddle(.|$)/gm,
expr: /(^|\s)[Jj][Ss]\s*[Ff]iddle(.|$)/gm,
replacement: "$1JSFiddle$2",
replacement: "$1JSFiddle$2",
reason: "'JSFiddle' is the currently accepted capitalization"
reason: "'JSFiddle' is the currently accepted capitalization"
},
},
caps: {
caps: {
expr: /^(?!https?)([a-z])/gm,
expr: /^(?!https?)([a-z])/gm,
replacement: "$1",
replacement: "$1",
reason: "copy edited"
reason: "copy edited"
},
},
jquery: {
jquery: {
expr: /(^|\s)[Jj][Qq]uery(.|$)/gm,
expr: /(^|\s)[Jj][Qq]uery(.|$)/gm,
replacement: "$1jQuery$2",
replacement: "$1jQuery$2",
reason: "'jQuery' is the proper capitalization"
reason: "'jQuery' is the proper capitalization"
},
},
html: {
html: {
expr: /(^|\s)[Hh]tml([5]?)\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Hh]tml([5]?)\b(\S|)(?!\S)/gm,
replacement: "$1HTML$2$3",
replacement: "$1HTML$2$3",
reason: "HTML stands for HyperText Markup Language"
reason: "HTML stands for HyperText Markup Language"
},
},
css: {
css: {
expr: /(^|\s)[Cc]ss\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Cc]ss\b(\S|)(?!\S)/gm,
replacement: "$1CSS$2",
replacement: "$1CSS$2",
reason: "CSS stands for Cascading Style Sheets"
reason: "CSS stands for Cascading Style Sheets"
},
},
json: {
json: {
expr: /(^|\s)[Jj]son\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Jj]son\b(\S|)(?!\S)/gm,
replacement: "$1JSON$2",
replacement: "$1JSON$2",
reason: "JSON stands for JavaScript Object Notation"
reason: "JSON stands for JavaScript Object Notation"
},
},
ajax: {
ajax: {
expr: /(^|\s)ajax\b(\S|)(?!\S)/gm,
expr: /(^|\s)ajax\b(\S|)(?!\S)/gm,
replacement: "$1AJAX$2",
replacement: "$1AJAX$2",
reason: "AJAX stands for Asynchronous JavaScript and XML"
reason: "AJAX stands for Asynchronous JavaScript and XML"
},
},
angular: {
angular: {
expr: /[Aa]ngular[Jj][Ss]/g,
expr: /[Aa]ngular[Jj][Ss]/g,
replacement: "AngularJS",
replacement: "AngularJS",
reason: "'AngularJS is the proper capitalization"
reason: "'AngularJS is the proper capitalization"
},
},
thanks: {
thanks: {
expr: /(thanks|pl(?:ease|z|s)\s+h[ea]lp|cheers|regards|thx|thank\s+you|my\s+first\s+question|kindly\shelp).*$/gmi,
expr: /(thanks|pl(?:ease|z|s)\s+h[ea]lp|cheers|regards|thx|thank\s+you|my\s+first\s+question|kindly\shelp).*$/gmi,
replacement: "",
replacement: "",
reason: "'$1' is unnecessary noise"
reason: "'$1' is unnecessary noise"
},
},
commas: {
commas: {
expr: /,([^\s])/g,
expr: /,([^\s])/g,
replacement: ", $1",
replacement: ", $1",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
},
},
php: {
php: {
expr: /(^|\s)[Pp]hp\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Pp]hp\b(\S|)(?!\S)/gm,
replacement: "$1PHP$2",
replacement: "$1PHP$2",
reason: "PHP stands for PHP: Hypertext Preprocessor"
reason: "PHP stands for PHP: Hypertext Preprocessor"
},
},
hello: {
hello: {
expr: /(?:^|\s)(hi\s+guys|hi|hello|good\s(?:evening|morning|day|afternoon))(?:\.|!|\ )/gmi,
expr: /(?:^|\s)(hi\s+guys|hi|hello|good\s(?:evening|morning|day|afternoon))(?:\.|!|\ )/gmi,
replacement: "",
replacement: "",
reason: "greetings like '$1' are unnecessary noise"
reason: "greetings like '$1' are unnecessary noise"
},
},
edit: {
edit: {
expr: /(?:^\**)(edit|update):?(?:\**):?/gmi,
expr: /(?:^\**)(edit|update):?(?:\**):?/gmi,
replacement: "",
replacement: "",
reason: "Stack Exchange has an advanced revision history system: 'Edit' or 'Update' is unnecessary"
reason: "Stack Exchange has an advanced revision history system: 'Edit' or 'Update' is unnecessary"
},
},
voting: {
voting: {
expr: /([Dd]own|[Uu]p)[\s*\-]vot/g,
expr: /([Dd]own|[Uu]p)[\s*\-]vot/g,
replacement: "$1vote",
replacement: "$1vote",
reason: "the proper spelling (despite the tag name) is '$1vote' (one word)"
reason: "the proper spelling (despite the tag name) is '$1vote' (one word)"
},
},
mysite: {
mysite: {
expr: /mysite\./g,
expr: /mysite\./g,
replacement: "example.",
replacement: "example.",
reason: "links to mysite.domain are not allowed: use example.domain instead"
reason: "links to mysite.domain are not allowed: use example.domain instead"
},
},
c: {
c: {
expr: /(^|\s)c(#|\++|\s|$)/gm,
expr: /(^|\s)c(#|\++|\s|$)/gm,
replacement: "$1C$2",
replacement: "$1C$2",
reason: "C$2 is the proper capitalization"
reason: "C$2 is the proper capitalization"
},
},
java: {
java: {
expr: /(^|\s)java\b(\S|)(?!\S)/gmi,
expr: /(^|\s)java\b(\S|)(?!\S)/gmi,
replacement: "$1Java$2",
replacement: "$1Java$2",
reason: "Java should be capitalized"
reason: "Java should be capitalized"
},
},
sql: {
sql: {
expr: /(^|\s)[Ss]ql\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Ss]ql\b(\S|)(?!\S)/gm,
replacement: "$1SQL$2",
replacement: "$1SQL$2",
reason: "SQL is the proper capitalization"
reason: "SQL is the proper capitalization"
},
},
sqlite: {
sqlite: {
expr: /(^|\s)[Ss]qlite([0-9]*)\b(\S|)(?!\S)/gm,
expr: /(^|\s)[Ss]qlite([0-9]*)\b(\S|)(?!\S)/gm,
replacement: "$1SQLite$2$3",
replacement: "$1SQLite$2$3",
reason: "SQLite is the proper capitalization"
reason: "SQLite is the proper capitalization"
},
},
android: {
android: {
expr: /(^|\s)android\b(\S|)(?!\S)/gmi,
expr: /(^|\s)android\b(\S|)(?!\S)/gmi,
replacement: "$1Android$2",
replacement: "$1Android$2",
reason: "Android should be capitalized"
reason: "Android should be capitalized"
},
},
oracle: {
oracle: {
expr: /(^|\s)oracle\b(\S|)(?!\S)/gmi,
expr: /(^|\s)oracle\b(\S|)(?!\S)/gmi,
replacement: "$1Oracle$2",
replacement: "$1Oracle$2",
reason: "Oracle should be capitalized"
reason: "Oracle should be capitalized"
},
},
windows: {
windows: {
expr: /(win|windows(?:\ ?)(\s[0-9]+))\b(\S|)(?!\S)/igm,
expr: /(win|windows(?:\ ?)(\s[0-9]+))\b(\S|)(?!\S)/igm,
replacement: "Windows$2$3",
replacement: "Windows$2$3",
reason: "Windows should be capitalized"
reason: "Windows should be capitalized"
},
},
windowsXP: {
windowsXP: {
expr: /(win|windows(?:\ ?)(\sxp))\b(\S|)(?!\S)/igm,
expr: /(win|windows(?:\ ?)(\sxp))\b(\S|)(?!\S)/igm,
replacement: "Windows XP$3",
replacement: "Windows XP$3",
reason: "Windows XP should be capitalized"
reason: "Windows XP should be capitalized"
},
},
windowsVista: {
windowsVista: {
expr: /(win|windows(?:\ ?)(\svista))\b(\S|)(?!\S)/igm,
expr: /(win|windows(?:\ ?)(\svista))\b(\S|)(?!\S)/igm,
replacement: "Windows Vista$3",
replacement: "Windows Vista$3",
reason: "Windows Vista should be capitalized"
reason: "Windows Vista should be capitalized"
},
},
ubuntu: {
ubuntu: {
expr: /(ubunto|ubunut|ubunutu|ubunu|ubntu|ubutnu|ubanto[o]+|unbuntu|ubunt|ubutu)\b(\S|)(?!\S)/igm,
expr: /(ubunto|ubunut|ubunutu|ubunu|ubntu|ubutnu|ubanto[o]+|unbuntu|ubunt|ubutu)\b(\S|)(?!\S)/igm,
replacement: "Ubuntu$2",
replacement: "Ubuntu$2",
reason: "corrected Ubuntu spelling"
reason: "corrected Ubuntu spelling"
},
},
linux: {
linux: {
expr: /(linux)\b(\S|)(?!\S)/igm,
expr: /(linux)\b(\S|)(?!\S)/igm,
replacement: "Linux$2",
replacement: "Linux$2",
reason: "Linux should be capitalized"
reason: "Linux should be capitalized"
},
},
apostrophes: {
apostrophes: {
expr: /(^|\s)(can|doesn|don|won|hasn|isn|didn)t(\s|$)/gmi,
expr: /(^|\s)(can|doesn|don|won|hasn|isn|didn)t(\s|$)/gmi,
replacement: "$1$2't$3",
replacement: "$1$2't$3",
reason: "English contractions use apostrophes"
reason: "English contractions use apostrophes"
},
},
ios: {
ios: {
expr: /\b(?:ios|iOs|ioS|IOS|Ios|IoS|ioS)\b(\S|)(?!\S)/gm,
expr: /\b(?:ios|iOs|ioS|IOS|Ios|IoS|ioS)\b(\S|)(?!\S)/gm,
replacement: "iOS$1",
replacement: "iOS$1",
reason: "the proper usage is 'iOS'"
reason: "the proper usage is 'iOS'"
},
},
iosnum: {
iosnum: {
expr: /\b(?:ios|iOs|ioS|IOS|Ios|IoS|ioS)([0-9]?)\b(\S|)(?!\S)/gm,
expr: /\b(?:ios|iOs|ioS|IOS|Ios|IoS|ioS)([0-9]?)\b(\S|)(?!\S)/gm,
replacement: "iOS $1$2",
replacement: "iOS $1$2",
reason: "the proper usage is 'iOS' followed by a space and the version number"
reason: "the proper usage is 'iOS' followed by a space and the version number"
},
},
yell: {
yell: {
expr: /^((?=.*[A-Z])[^a-z]*)$/g,
expr: /^((?=.*[A-Z])[^a-z]*)$/g,
replacement: "$1",
replacement: "$1",
reason: "no need to yell"
reason: "no need to yell"
},
},
wordpress: {
wordpress: {
expr: /[Ww]ordpress/g,
expr: /[Ww]ordpress/g,
replacement: "WordPress",
replacement: "WordPress",
reason: "'WordPress' is the proper capitalization"
reason: "'WordPress' is the proper capitalization"
},
},
google: {
google: {
expr: /(google)\b(\S|)(?!\S)/igm,
expr: /(google)\b(\S|)(?!\S)/igm,
replacement: "Google$2",
replacement: "Google$2",
reason: "Google is the proper capitalization"
reason: "Google is the proper capitalization"
},
},
mysql: {
mysql: {
expr: /(mysql)\b(\S|)(?!\S)/igm,
expr: /(mysql)\b(\S|)(?!\S)/igm,
replacement: "MySQL$2",
replacement: "MySQL$2",
reason: "MySQL is the proper capitalization"
reason: "MySQL is the proper capitalization"
},
},
apache: {
apache: {
expr: /(apache)\b(\S|)(?!\S)/igm,
expr: /(apache)\b(\S|)(?!\S)/igm,
replacement: "Apache$2",
replacement: "Apache$2",
reason: "Apache is the proper capitalization"
reason: "Apache is the proper capitalization"
},
},
git: {
git: {
expr: /(^|\s)(git|GIT)\b(\S|)(?!\S)/gm,
expr: /(^|\s)(git|GIT)\b(\S|)(?!\S)/gm,
replacement: "$1Git$3",
replacement: "$1Git$3",
reason: "Git is the proper capitalization"
reason: "Git is the proper capitalization"
},
},
harddisk: {
harddisk: {
expr: /(hdd|harddisk)\b(\S|)(?!\S)/igm,
expr: /(hdd|harddisk)\b(\S|)(?!\S)/igm,
replacement: "hard disk$2",
replacement: "hard disk$2",
reason: "Hard disk is the proper capitalization"
reason: "Hard disk is the proper capitalization"
},
},
github: {
github: {
expr: /\b([gG]ithub|GITHUB)\b(\S|)(?!\S)/gm,
expr: /\b([gG]ithub|GITHUB)\b(\S|)(?!\S)/gm,
replacement: "GitHub$2",
replacement: "GitHub$2",
reason: "GitHub is the proper capitalization"
reason: "GitHub is the proper capitalization"
},
},
facebook: {
facebook: {
expr: /\b([fF]acebook|FACEBOOK)\b(\S|)(?!\S)/gm,
expr: /\b([fF]acebook|FACEBOOK)\b(\S|)(?!\S)/gm,
replacement: "Facebook$2",
replacement: "Facebook$2",
reason: "Facebook is the proper capitalization"
reason: "Facebook is the proper capitalization"
},
},
python: {
python: {
expr: /(^|\s)[Pp]ython(.|$)/gm,
expr: /(^|\s)[Pp]ython(.|$)/gm,
replacement: "$1Python$2",
replacement: "$1Python$2",
reason: "'Python' is the proper capitalization"
reason: "'Python' is the proper capitalization"
},
},
im: {
im: {
expr: /(^|\s|\()im(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
expr: /(^|\s|\()im(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
replacement: "$1I'm$2",
replacement: "$1I'm$2",
reason: "in English, the personal pronoun is 'I'"
reason: "in English, the personal pronoun is 'I'"
},
},
ive: {
ive: {
expr: /(^|\s|\()ive(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
expr: /(^|\s|\()ive(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
replacement: "$1I've$2",
replacement: "$1I've$2",
reason: "in English, the personal pronoun is 'I'"
reason: "in English, the personal pronoun is 'I'"
},
},
ur: {
ur: {
expr: /(^|\s|\()ur(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
expr: /(^|\s|\()ur(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
replacement: "$1you are$2",
replacement: "$1you are$2",
reason: "de-text"
reason: "de-text"
},
},
u: {
u: {
expr: /(^|\s|\()u(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
expr: /(^|\s|\()u(\s|,|\.|!|\?|;|\/|\)|'|$)/gm,
replacement: "$1you$2",
replacement: "$1you$2",
reason: "de-text"
reason: "de-text"
},
},
allways: {
allways: {
expr: /(^|\s|\()(a)llways(\s|,|\.|!|\?|;|\/|\)|'|$)/gmi,
expr: /(^|\s|\()(a)llways(\s|,|\.|!|\?|;|\/|\)|'|$)/gmi,
replacement: "$1$2lways$3",
replacement: "$1$2lways$3",
reason: "spelling"
reason: "spelling"
},
},
appreciated: {
appreciated: {
expr: /(?:[\s-,']\w*)*(help|suggestion|advice).*(?:appreciated).*/gmi,
expr: /(?:[\s-,']\w*)*(help|suggestion|advice).*(?:appreciated).*/gmi,
replacement: "",
replacement: "",
reason: "$1 requests are unnecessary noise"
reason: "$1 requests are unnecessary noise"
},
},
hopeMaybeHelps: {
hopeMaybeHelps: {
expr: /(?:[\s-,']\w*)*(maybe|hope)+(?:[\s-,']\w*)*\s(help[s]*)(?:[\s-,']\w*)*[\.!?]/gmi,
expr: /(?:[\s-,']\w*)*(maybe|hope)+(?:[\s-,']\w*)*\s(help[s]*)(?:[\s-,']\w*)*[\.!?]/gmi,
replacement: "",
replacement: "",
reason: "$1...$2 is unnecessary noise"
reason: "$1...$2 is unnecessary noise"
},
},
regex: {
regex: {
expr: /regex(p)?/gmi,
expr: /regex(p)?/gmi,
replacement: function(match,p){ return "RegEx"+((p === undefined)?"":p).toLowerCase(); },
replacement: function(match,p){ return "RegEx"+((p === undefined)?"":p).toLowerCase(); },
reason: "RegEx or RegExp are the correct capitalizations"
reason: "RegEx or RegExp are the correct capitalizations"
},
},
multiplesymbols: {
multiplesymbols: {
expr: /\?\?+/gm,
expr: /\?\?+/gm,
replacement: "?",
replacement: "?",
reason: "One question mark for one question"
reason: "One question mark for one question"
},
},
// Whitespace compression comes last
// Whitespace compression comes last
multiplespaces: {
multiplespaces: {
expr: /(\S) +(\S)/gm,
expr: /(\S) +(\S)/gm,
replacement: "$1 $2",
replacement: "$1 $2",
reason: "One space at a time"
reason: "One space at a time"
},
},
spacesbeforepunctuation: {
spacesbeforepunctuation: {
expr: / +([.,:;?!])/g,
//expr: / +([.,:;?!])/g,
expr: / +([.,:;?!])[^\w]/g,
replacement: "$1 ",
replacement: "$1 ",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
},
},
spacesafterpunctuation: {
spacesafterpunctuation: {
expr: /([.,:;?!]) +/g,
expr: /([.,:;?!]) +/g,
replacement: "$1 ",
replacement: "$1 ",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
},
},
leadingspace: {
leadingspace: {
expr: /^ +(\S)/gm,
expr: /^ +(\S)/gm,
replacement: "$1",
replacement: "$1",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
},
},
blanklines: {
blanklines: {
expr: /(?:\s*[\r\n]){3,}/gm,
expr: /(?:\s*[\r\n]){3,}/gm,
replacement: "\n\n",
replacement: "\n\n",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
},
},
endblanklines: {
endblanklines: {
expr: /[\s\r\n]+$/g,
expr: /[\s\r\n]+$/g,
replacement: "",
replacement: "",
reason: "punctuation & spacing"
reason: "punctuation & spacing"
}
}
};
};


// Populate funcs
// Populate funcs
App.popFuncs = function() {
App.popFuncs = function() {
// This is where the magic happens: this function takes a few pieces of information and applies edits to the post with a couple exceptions
// This is where the magic happens: this function takes a few pieces of information and applies edits to the post with a couple exceptions
App.funcs.fixIt = function(input, expression, replacement, reasoning) {
App.funcs.fixIt = function(input, expression, replacement, reasoning) {
// If there is nothing to search, exit
// If there is nothing to search, exit
if (!input) return false;
if (!input) return false;
// Scan the post text using the expression to see if there are any matches
// Scan the post text using the expression to see if there are any matches
var match = input.search(expression);
var match = input.search(expression);
// If so, increase the number of edits performed (used later for edit summary formation)
// If so, increase the number of edits performed (used later for edit summary formation)
if (match !== -1) {
if (match !== -1) {


// Later, this will store what is removed for the first case
// Later, this will store what is removed for the first case
var phrase;
var phrase;


// Then, perform the edits using replace()
// Then, perform the edits using replace()
// What follows is a series of exceptions, which I will explain below; I perform special actions by overriding replace()
// What follows is a series of exceptions, which I will explain below; I perform special actions by overriding replace()
// This is used for removing things entirely without giving a replacement; it matches the expression and then replaces it with nothing
// This is used for removing things entirely without giving a replacement; it matches the expression and then replaces it with nothing
if (replacement === "") {
if (replacement === "") {
var phrase2; // Hack on a hack - allow 2 replacements
var phrase2; // Hack on a hack - allow 2 replacements
input = input.replace(expression, function(data, match1, match2) {
input = input.replace(expression, function(data, match1, match2) {
// Save what is removed for the edit summary (see below)
// Save what is removed for the edit summary (see below)
phrase = match1;
phrase = match1;
phrase2 = match2;
phrase2 = match2;




// Replace with nothing
// Replace with nothing
return "";
return "";
});
});


// This is an interesting tidbit: if you want to make the edit summaries dynamic, you can keep track of a match that you receive
// This is an interesting tidbit: if you want to make the edit summaries dynamic, you can keep track of a match that you receive
// from overriding the replace() function and then use that in the summary
// from overriding the replace() function and then use that in the summary
reasoning = reasoning.replace("$1", phrase)
reasoning = reasoning.replace("$1", phrase)
.replace("$2", phrase2);
.replace("$2", phrase2);




// This allows me to combine the upvote and downvote replacement schemes into one
// This allows me to combine the upvote and downvote replacement schemes into one
} else if (replacement == "$1vote") {
} else if (replacement == "$1vote") {
input = input.replace(expression, function(data, match1) {
input = input.replace(expression, function(data, match1) {
phrase = match1;
phrase = match1;
return phrase + "vot";
return phrase + "vot";
});
});
reasoning = reasoning.replace("$1", phrase.toLowerCase());
reasoning = reasoning.replace("$1", phrase.toLowerCase());


// Fix all caps
// Fix all caps
} else if (reasoning === "no need to yell") {
} else if (reasoning === "no need to yell") {
input = input.replace(expression, function(data, match1) {
input = input.replace(expression, function(data, match1) {
return match1.substring(0, 1).toUpperCase() + match1.substring(1).toLowerCase();
return match1.substring(0, 1).toUpperCase() + match1.substring(1).toLowerCase();
});
});
// This is used to capitalize letters; it merely takes what is matched, uppercases it, and replaces what was matched with the uppercased version
// This is used to capitalize letters; it merely takes what is matched, uppercases it, and replaces what was matched with the uppercased version
} else if (replacement === "$1") {
} else if (replacement === "$1") {
input = input.replace(expression, function(data, match1) {
input = input.replace(expression, function(data, match1) {
return match1.toUpperCase();
return match1.toUpperCase();
});
});


// I can use C, C#, and C++ capitalization in one rule
// I can use C, C#, and C++ capitalization in one rule
} else if (replacement === "$1C$2") {
} else if (replacement === "$1C$2") {
var newPhrase;
var newPhrase;
input = input.replace(expression, function(data, match1, match2) {
input = input.replace(expression, function(data, match1, match2) {
newPhrase = match2;
newPhrase = match2;
return match1 + "C" + match2;
return match1 + "C" + match2;
});
});
reasoning = reasoning.replace("$2", newPhrase);
reasoning = reasoning.replace("$2", newPhrase);


// iOS numbering/spacing fixes
// iOS numbering/spacing fixes
} else if (replacement === "iOS $2") {
} else if (replacement === "iOS $2") {
input = input.replace(expression, function(data, match1) {
input = input.replace(expression, function(data, match1) {
if (match1.match(/\d/)) { // Is a number
if (match1.match(/\d/)) { // Is a number
return "iOS " + match1;
return "iOS " + match1;
}
}


return "iOS" + match1;
return "iOS" + match1;
});
});


// Default: just replace it with the indicated replacement
// Default: just replace it with the indicated replacement
} else {
} else {
input = input.replace(expression, replacement);
input = input.replace(expression, replacement);
}
}


// Return a dictionary with the reasoning for the fix and what is edited (used later to prevent duplicates in the edit summary)
// Return a dictionary with the reasoning for the fix and what is edited (used later to prevent duplicates in the edit summary)
return {
return {
reason: reasoning,
reason: reasoning,
fixed: input
fixed: input
};
};
} else {
} else {
// If nothing needs to be fixed, return null
// If nothing needs to be fixed, return null
return null;
return null;
}
}
};
};


// Omit code
// Omit code
App.funcs.omitCode = function(str, type) {
App.funcs.omitCode = function(str, type) {
str = str.replace(App.globals.checks[type], function(match) {
str = str.replace(App.globals.checks[type], function(match) {
App.globals.replacedStrings[type].push(match);
App.globals.replacedStrings[type].push(match);
return App.globals.placeHolders[type];
return App.globals.placeHolders[type];
});
});
return str;
return str;
};
};


// Replace code
// Replace code
App.funcs.replaceCode = function(str, type) {
App.funcs.replaceCode = function(str, type) {
for (var i = 0; i < App.globals.replacedStrings[type].length; i++) {
for (var i = 0; i < App.globals.replacedStrings[type].length; i++) {
str = str.replace(App.globals.placeHolders[type],
str = str.replace(App.globals.placeHolders[type],
App.globals.replacedStrings[type][i]);
App.globals.replacedStrings[type][i]);
}
}
return str;
return str;
};
};


// Eliminate duplicates in array (awesome method I found on SO, check it out!)
// From AstroCB: the original structure of the edit formation prevents duplicates.
// Unless you changed that structure somehow, this shouldn't be needed.
App.funcs.eliminateDuplicates = function(arr) {
var i, len = arr.length,
out = [],
obj = {};

for (i = 0; i < len; i++) {
obj[arr[i]] = 0;
}
for (i in obj) {
if (obj.hasOwnProperty(i)) { // Prevents messiness of for..in statements
out.push(i);
}
}
return out;
};

App.funcs.applyListeners = function() { // Removes default Stack Exchange listeners; see https://github.com/AstroCB/Stack-Exchange-Editor-Toolkit/issues/43
App.funcs.applyListeners = function() { // Removes default Stack Exchange listeners; see https://github.com/AstroCB/Stack-Exchange-Editor-Toolkit/issues/43
function removeEventListeners(e) {
function removeEventListeners(e) {
if (e.which === 13) {
if (e.which === 13) {
if (e.metaKey || e.ctrlKey) {
if (e.metaKey || e.ctrlKey) {
// CTRL/CMD + Enter -> Activate the auto-editor
// CTRL/CMD + Enter -> Activate the auto-editor
App.selections.buttonFix.click();
App.selections.buttonFix.click();
this.focus();
this.focus();
} else {
} else {
// It's impossible to remove the event listeners, so we have to clone the element without any listeners
// It's impossible to remove the event listeners, so we have to clone the element without any listeners
var elClone = this.cloneNode(true);
var elClone = this.cloneNode(true);
this.parentNode.replaceChild(elClone, this);
this.parentNode.replaceChild(elClone,
this);
App.selections.submitButton.click();
App.selections.submitButton.click();
}
}
}
}
}
}


// Tags box
// Tags box
App.selections.tagField.keydown(removeEventListeners);
App.selections.tagField.keydown(removeEventListeners);


// Edit summary box
// Edit summary box
App.selections.summaryBox.keydown(removeEventListeners);
App.selections.summaryBox.keydown(removeEventListeners);
};
};


// Wait for relevant dynamic content to finish loading
// Wait for relevant dynamic content to finish loading
App.funcs.dynamicDelay = function(callback) {
App.funcs.dynamicDelay = function(callback) {
setTimeout(function() {
if (App.globals.inline) { // Inline editing
App.selections.buttonBar = $('#wmd-button-bar-' + App.globals.targetID);
App.selections.buttonBar.unbind();
setTimeout(function() {
setTimeout(function() {
callback();
App.selections.buttonBar = $('#wmd-button-bar-' + App.globals.targetID);
}, 0);
App.selections.buttonBar.unbind();
}, 500);
setTimeout(function() {
};
callback();

}, 0);
// Populate or refresh DOM selections
}, 500);
App.funcs.popSelections = function() {
} else { // Question page editing
var targetID = App.globals.targetID;
App.selections.
var scope = $('div[data-questionid="' + targetID + '"]');
if (!scope.length) scope = $('div[data-answerid="' + targetID + '"]');
if (!scope.length) scope = '';
App.selections.redoButton = $('#wmd-redo-button-' + targetID, scope);
App.selections.bodyBox = $("#wmd-input-" + targetID, scope);
App.selections.titleBox = $('[class*="title-field"]', scope);
App.selections.summaryBox = $("#edit-comment-" + targetID, scope);
App.selections.tagField = $($(".tag-editor")[0], scope);
App.selections.submitButton = $("#submit-button-" + targetID, scope);
};

// Populate edit item sets from DOM selections
App.funcs.popItems = function() {
App.items[0] = {
title: String(App.selections.titleBox.v