Skip to content

Instantly share code, notes, and snippets.

@camilstaps
Last active June 13, 2021 04:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save camilstaps/40b62910f0206ef97d50822014870884 to your computer and use it in GitHub Desktop.
Save camilstaps/40b62910f0206ef97d50822014870884 to your computer and use it in GitHub Desktop.
Stack Exchange HTML math editor
// ==UserScript==
// @name Stack Exchange HTML math editor
// @author Camil Staps <info@camilstaps.nl>
// @namespace nl.camilstaps.htmlmath
// @description Adds a math bar to the Stack Exchange editor
// @include /^https?:\/\/(.*\.)?stackoverflow\.com/.*$/
// @include /^https?:\/\/(.*\.)?serverfault\.com/.*$/
// @include /^https?:\/\/(.*\.)?superuser\.com/.*$/
// @include /^https?:\/\/(.*\.)?stackexchange\.com/.*$/
// @include /^https?:\/\/(.*\.)?askubuntu\.com/.*$/
// @include /^https?:\/\/(.*\.)?mathoverflow\.com/.*$/
// @include /^https?:\/\/discuss\.area51\.stackexchange\.com/.*$/
// @include /^https?:\/\/stackapps\.com/.*$/
// @version 1.0.0
// @grant none
// ==/UserScript==
var script = document.createElement('script');
script.setAttribute('src', 'https://unpkg.com/stack-exchange-html-math-editor/math_editor.js');
document.head.appendChild(script);
var insertOrSurroundWith = function(field, prefix, suffix) {
return function() {
if (document.selection) {
field.focus();
var sel = document.selection.createRange();
sel.text = prefix + sel.text + suffix;
} else if (field.selectionStart || field.selectionStart == '0') {
var start = field.selectionStart;
var end = field.selectionEnd;
field.value = field.value.substring(0, start)
+ prefix + field.value.substring(start, end) + suffix
+ field.value.substring(end, field.value.length);
field.selectionStart = start + prefix.length;
field.selectionEnd = end + prefix.length;
} else {
field.value += prefix + suffix;
}
field.onpaste();
field.focus();
};
};
var insert = function(field, text) {
return function() {
if (document.selection) {
field.focus();
var sel = document.selection.createRange();
sel.text = text;
} else if (field.selectionStart || field.selectionStart == '0') {
var start = field.selectionStart;
var end = field.selectionEnd;
field.value = field.value.substring(0, start)
+ text + field.value.substring(end, field.value.length);
field.selectionStart = start + text.length;
field.selectionEnd = start + text.length;
} else {
field.value += text;
}
field.onpaste();
field.focus();
};
};
var addButton = function(row, label, title, func) {
var button = $('<li></li>')
.addClass('wmd-button')
.attr('title', title)
.css('padding', '4px')
.css('height', 'inherit')
.html(label)
.click(func);
row.append(button);
};
var addSpacer = function(row) {
var spacer = $('<li></li>')
.addClass('wmd-spacer')
.css('height', 'inherit');
row.append(spacer);
};
var addMathEditor = function(id) {
var bar = $('#wmd-button-bar' + (typeof id == 'undefined' ? '' : '-' + id));
var row = bar.find('.wmd-button-row');
if (row.length == 0)
return;
var bar = row.parent();
var field = bar.parent().find('.wmd-input')[0];
clearInterval(mathEditorTimer);
var button_math = $('<li></li>')
.attr('id', 'wmd-math-button')
.addClass('wmd-button')
.attr('title', 'Show math toolbar')
.css('left', '400px')
.html('&radic;x')
.click(function(){
bar.css('height', 'auto');
var newRow = function() {
return $('<ul></ul>')
.addClass('wmd-button-row')
.css('height', 24)
.css('justify-content', 'flex-start')
.appendTo(bar);
}
var rows = [newRow(), newRow(), newRow()];
addButton(rows[0], '&ne;', 'Not equal to', insert(field, '&ne;'));
addButton(rows[0], '&le;', 'Less than or equal to', insert(field, '&le;'));
addButton(rows[0], '&ge;', 'Greater than or equal to', insert(field, '&ge;'));
addSpacer(rows[0]);
addButton(rows[0], 'x<sup>2</sup>', 'Superscript', insertOrSurroundWith(field, '<sup>', '</sup>'));
addButton(rows[0], 'x<sub>2</sub>', 'Subscript', insertOrSurroundWith(field, '<sub>', '</sub>'));
addSpacer(rows[0]);
addButton(rows[0], '&sum;', 'Sum', insert(field, '&sum;'));
addButton(rows[0], '&prod;', 'Product', insert(field, '&prod;'));
addSpacer(rows[0]);
addButton(rows[0], '&naturals;', 'Naturals', insert(field, '&naturals;'));
addButton(rows[0], '&integers;', 'Integers', insert(field, '&integers;'));
addButton(rows[0], '&rationals;', 'Rationals', insert(field, '&rationals;'));
addButton(rows[0], '&reals;', 'Reals', insert(field, '&reals;'));
addSpacer(rows[0]);
addButton(rows[0], '&mid;', 'Divides', insert(field, '&mid;'));
addButton(rows[0], '&nmid;', 'Does not divide', insert(field, '&nmid;'));
addButton(rows[0], '&radic;', 'Radic', insert(field, '&radic;'));
addButton(rows[0], '&infin;', 'Infinity', insert(field, '&infin;'));
addButton(rows[1], '&empty;', 'Empty set', insert(field, '&empty;'));
addButton(rows[1], '&isin;', 'Element of', insert(field, '&isin;'));
addButton(rows[1], '&notin;', 'Not an element of', insert(field, '&notin;'));
addButton(rows[1], '&cap;', 'Intersection', insert(field, '&cap;'));
addButton(rows[1], '&cup;', 'Union', insert(field, '&cup;'));
addButton(rows[1], '&sube;', 'Subset of', insert(field, '&sube;'));
addButton(rows[1], '&supe;', 'Superset of', insert(field, '&supe;'));
addButton(rows[1], '&sub;', 'Strict subset of', insert(field, '&sub;'));
addButton(rows[1], '&sup;', 'Strict superset of', insert(field, '&sup;'));
addButton(rows[1], '&nsube;', 'Not a subset of', insert(field, '&nsube;'));
addButton(rows[1], '&nsupe;', 'Not a superset of', insert(field, '&nsupe;'));
addButton(rows[1], '&nsub;', 'Not a strict subset of', insert(field, '&nsub;'));
addButton(rows[1], '&nsup;', 'Not a strict superset of', insert(field, '&nsup;'));
addSpacer(rows[1]);
addButton(rows[1], '&forall;', 'For all', insert(field, '&forall;'));
addButton(rows[1], '&exist;', 'There exists', insert(field, '&exist;'));
addButton(rows[1], '&nexist;', 'There does not exist', insert(field, '&nexist;'));
addButton(rows[2], '&not;', 'Negation', insert(field, '&not;'));
addButton(rows[2], '&rarr;', 'Implication', insert(field, '&rarr;'));
addButton(rows[2], '&harr;', 'Equivalence', insert(field, '&harr;'));
addButton(rows[2], '&and;', 'Conjunction', insert(field, '&and;'));
addButton(rows[2], '&or;', 'Disjunction', insert(field, '&or;'));
addSpacer(rows[2]);
addButton(rows[2], '&equiv;', 'Equivalent to', insert(field, '&equiv;'));
addButton(rows[2], '&nequiv;', 'Not equivalent to', insert(field, '&nequiv;'));
addSpacer(rows[2]);
addButton(rows[2], '&vdash;', 'Entails', insert(field, '&vdash;'));
addButton(rows[2], '&vDash;', 'Tautology', insert(field, '&vDash;'));
addButton(rows[2], '&top;', 'Down tee', insert(field, '&top;'));
addButton(rows[2], '&bot;', 'Up tee', insert(field, '&bot;'));
addSpacer(rows[2]);
addButton(rows[2], '&square;', 'Necessarily', insert(field, '&square;'));
addButton(rows[2], '&loz;', 'Possibly', insert(field, '&loz;'));
var spacer = $('<li></li>').addClass('wmd-spacer wmd-spacer-max');
rows[2].append(spacer);
var credits = $('<li></li>')
.addClass('wmd-button')
.css('padding', '0 3em 0 0');
var link = $('<a></a>')
.attr('href', 'https://gist.github.com/camilstaps/40b62910f0206ef97d50822014870884/')
.attr('title', 'See source code')
.attr('target', '_blank')
.text('source');
credits.append(link);
rows[2].append(credits);
$(this).remove();
field.focus();
});
var spacer = $('<li></li>')
.addClass('wmd-spacer');
var maxspacer = row.find('.wmd-spacer-max');
spacer.insertBefore(maxspacer);
button_math.insertBefore(maxspacer);
};
var bar = $('.wmd-button-bar');
if (bar.length)
var mathEditorTimer = setInterval(addMathEditor, 100);
$('a.edit-post').click(function(){
var id = /\/posts\/(\d+)\/edit/.exec($(this).attr('href'))[1];
mathEditorTimer = setInterval(addMathEditor, 100, id);
});
{
"name": "stack-exchange-html-math-editor",
"version": "1.0.0",
"description": "Stack Exchange HTML math editor",
"main": "HTML_math_editor.user.js",
"repository": {
"type": "git",
"url": "git+https://gist.github.com/40b62910f0206ef97d50822014870884.git"
},
"keywords": [
"StackExchange",
"Stack",
"Exchange",
"userscript",
"HTML",
"math",
"mathematics",
"symbols"
],
"author": "",
"license": "UNLICENSED",
"homepage": "https://gist.github.com/40b62910f0206ef97d50822014870884"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment