forked from cben/mathdown
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmathdown.js
More file actions
184 lines (166 loc) · 6.6 KB
/
mathdown.js
File metadata and controls
184 lines (166 loc) · 6.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// Main code running in every mathdown document (all shown via index.html).
"use strict";
// Prevent errors on IE. Might not actually log.
function log() {
try { console.log.apply(console, arguments); } catch (err) {}
}
// Send MathJax messages to log.
log("MJ:", MathJax.Message.Log());
var origFilterText = MathJax.Message.filterText;
MathJax.Message.filterText = function(text, n, msgType) {
// Exclude non-informative "Processing/Typesetting math: 0% / 100%".
if(msgType != "ProcessMath" && msgType != "TypesetMath") {
log("MJ:", text, "[" + msgType + "]");
}
return origFilterText(text, n, msgType);
}
function locationQueryParams() {
/* If more is needed, use https://github.com/medialize/URI.js */
var queryParts = window.location.search.replace(/^\?/g, "").split("&");
var params = {};
for(var i = 0; i < queryParts.length; i++) {
var keyval = queryParts[i].split("=");
params[decodeURIComponent(keyval[0])] = decodeURIComponent(keyval[1] || "");
}
return params;
}
// Return an int in [0, 62).
var random62 = (window.crypto && window.crypto.getRandomValues) ?
function() {
var buf = new Uint8Array(1);
var n;
do {
window.crypto.getRandomValues(buf);
n = (buf[0] % 64);
} while(n >= 62);
return n;
}
:
function() {
// Math.random is pathetic on most browsers, though some initialize
// with secure seed: http://stackoverflow.com/a/18507748/239657
return Math.floor(Math.random() * 62);
};
function randomBase62(length) {
var base62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
var text = "";
for(var i=0; i < length; i++)
text += base62.charAt(random62());
return text;
}
function newPad() {
var doc = randomBase62(11); // 62**11 ~= 2**65.
window.open("?doc=" + doc, "_blank");
}
var doc = locationQueryParams()["doc"];
if(!doc) {
window.location.search = "?doc=about";
}
var firepadsRef = new Firebase("https://mathdown.firebaseIO.com/firepads");
var firepadRef = firepadsRef.child(doc);
log("firebase ref:", firepadRef.toString());
// Stolen from CodeMirror/addon/edit/trailingspace.js.
CodeMirror.defineOption("showLeadingSpace", false, function(cm, val, prev) {
if (prev == CodeMirror.Init) prev = false;
if (prev && !val)
cm.removeOverlay("leadingspace");
else if (!prev && val)
cm.addOverlay({
token: function(stream) {
if (stream.sol() && stream.eatSpace()) {
return "leadingspace";
} else {
stream.skipToEnd();
return null;
}
},
name: "leadingspace"
});
});
// To add vertical margin to headers, the .cm-header[N] classes must apply to
// <pre> and not the <span>. Wrap the mode to achieve this.
CodeMirror.defineMode("gfm_header_line_classes", function(cmConfig, modeCfg) {
modeCfg.name = "gfm";
modeCfg.highlightFormatting = true;
var mode = CodeMirror.getMode(cmConfig, modeCfg);
var origToken = mode.token;
// We use GFM mostly for URLs but don't want GitHub-specific formatting that
// makes `0123456789` a link. TODO: add mode option of gfm.js.
var shaOrIssueRE = /^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40})|b^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+$/;
mode.token = function(stream, state) {
var classes = origToken(stream, state) || "";
if (shaOrIssueRE.test(stream.current())) {
classes = classes.replace(/(^| )link( |$)/, " ");
}
classes = classes.replace(/(^| )(header\S*)/g, "$1line-cm-$2");
return /^\s*$/.test(classes) ? null : classes;
}
return mode;
});
// Defaults are insert \t / reindent. Indent / dedent are more expected & useful.
CodeMirror.keyMap["default"]["Tab"] = "indentMore";
CodeMirror.keyMap["default"]["Shift-Tab"] = "indentLess";
var editor = CodeMirror.fromTextArea(document.getElementById("code"),
{foldGutter: true,
gutters: ["CodeMirror-foldgutter"],
indentUnit: 4,
lineNumbers: false,
lineWrapping: true,
mode: "gfm_header_line_classes",
showLeadingSpace: true});
// Indent soft-wrapped lines. Based on CodeMirror/demo/indentwrap.html.
var leadingSpaceAndListBullets = /^\s*([*+-]\s+|\d+\.\s+)?/;
editor.on("renderLine", function(cm, line, elt) {
// Would like to measure real sizes of /leadingspace|formatting-list/ styled
// spans, but can't do that without inserting them into the DOM.
var leading = (leadingSpaceAndListBullets.exec(line.text) || [""])[0];
var off = CodeMirror.countColumn(leading, leading.length, cm.getOption("tabSize"));
// Using "ex" is a bit better than cm.defaultCharWidth() — it picks up
// increased font if applied to whole line, i.e. in header lines
// (not that it makes sense to indent headers).
elt.style.textIndent = "-" + off + "ex";
elt.style.paddingLeft = off + "ex";
});
editor.refresh();
// Keep title and url #hash part in sync with first line of document.
function updateTitle() {
var text = editor.getLine(0); // TODO: find first # Title line?
text = text.replace(/^\s*#+\s*/, "");
document.title = text + " | mathdown";
window.location.hash = text.replace(/\W+/g, "-").replace(/^-/, "").replace(/-$/, "");
}
CodeMirror.on(editor.getDoc(), "change", function(doc, changeObj) {
if (changeObj.from.line == 0) {
updateTitle();
}
});
CodeMirror.hookMath(editor, MathJax);
var firepad = Firepad.fromCodeMirror(firepadRef, editor);
firepad.on("ready", function() {
if (firepad.isHistoryEmpty()) {
firepad.setText(
"# Untitled\n" +
"Bookmark this page — the random-looking address is the only way to access this document!\n" +
"Share the link to collaborate.\n" +
"Edits are saved in real time.\n" +
"\n" +
"Use Markdown for document structure and $\\LaTeX$ math syntax (see **Help** link above).\n" +
"To edit formulas just enter them with arrow keys.\n" +
// HACK: Pad the editor with a few empty lines so it looks
// more inviting to write in.
"\n" +
"\n"
);
} else {
// Keeping cursor at start (hopefully) reduces CM redrawing as
// syntax highlight and math rendering changes line heights.
editor.setCursor({line: 0, ch: 0});
}
// CM's autofocus option doesn't work with Firepad - seems focused
// but can't type. Focusing here after Firepad init works.
editor.focus();
// Queuing this allows text to appear before math.
MathJax.Hub.Queue(function() {
editor.renderAllMath();
});
});