@tryghost/kg-simplemde 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2046 @@
1
+ /*global require,module*/
2
+ "use strict";
3
+ var CodeMirror = require("codemirror");
4
+ require("codemirror/addon/edit/continuelist.js");
5
+ require("./codemirror/tablist");
6
+ require("codemirror/addon/display/fullscreen.js");
7
+ require("codemirror/mode/markdown/markdown.js");
8
+ require("codemirror/addon/mode/overlay.js");
9
+ require("codemirror/addon/display/placeholder.js");
10
+ require("codemirror/addon/selection/mark-selection.js");
11
+ require("codemirror/mode/gfm/gfm.js");
12
+ require("codemirror/mode/xml/xml.js");
13
+ var CodeMirrorSpellChecker = require("codemirror-spell-checker");
14
+
15
+ // disable marked to reduce filesize - Ghost uses it's own renderer
16
+ // var marked = require("marked");
17
+ var marked;
18
+
19
+
20
+ // Platform/Browser detection
21
+ // borrowed from https://github.com/codemirror/CodeMirror/blob/master/src/util/browser.js
22
+ var userAgent = navigator.userAgent;
23
+ var platform = navigator.platform;
24
+ var edge = /Edge\/(\d+)/.exec(userAgent);
25
+ var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
26
+ var mac = ios || /Mac/.test(platform);
27
+ var windows = /win/i.test(platform);
28
+
29
+ // Mapping of actions that can be bound to keyboard shortcuts or toolbar buttons
30
+ var bindings = {
31
+ "toggleBold": toggleBold,
32
+ "toggleItalic": toggleItalic,
33
+ "drawLink": drawLink,
34
+ "toggleHeadingSmaller": toggleHeadingSmaller,
35
+ "toggleHeadingBigger": toggleHeadingBigger,
36
+ "drawImage": drawImage,
37
+ "toggleBlockquote": toggleBlockquote,
38
+ "toggleOrderedList": toggleOrderedList,
39
+ "toggleUnorderedList": toggleUnorderedList,
40
+ "toggleCodeBlock": toggleCodeBlock,
41
+ "togglePreview": togglePreview,
42
+ "toggleStrikethrough": toggleStrikethrough,
43
+ "toggleHeading1": toggleHeading1,
44
+ "toggleHeading2": toggleHeading2,
45
+ "toggleHeading3": toggleHeading3,
46
+ "cleanBlock": cleanBlock,
47
+ "drawTable": drawTable,
48
+ "drawHorizontalRule": drawHorizontalRule,
49
+ "undo": undo,
50
+ "redo": redo,
51
+ "toggleSideBySide": toggleSideBySide,
52
+ "toggleFullScreen": toggleFullScreen
53
+ };
54
+
55
+ var shortcuts = {
56
+ "toggleBold": "Cmd-B",
57
+ "toggleItalic": "Cmd-I",
58
+ "drawLink": "Cmd-K",
59
+ "toggleHeadingSmaller": "Cmd-H",
60
+ "toggleHeadingBigger": "Shift-Cmd-H",
61
+ "cleanBlock": "Cmd-E",
62
+ "drawImage": "Cmd-Alt-I",
63
+ "toggleBlockquote": "Cmd-'",
64
+ "toggleOrderedList": "Cmd-Alt-L",
65
+ "toggleUnorderedList": "Cmd-L",
66
+ "toggleCodeBlock": "Cmd-Alt-C",
67
+ "togglePreview": "Cmd-P",
68
+ "toggleSideBySide": "F9",
69
+ "toggleFullScreen": "F11"
70
+ };
71
+
72
+ var getBindingName = function(f) {
73
+ for(var key in bindings) {
74
+ if(bindings[key] === f) {
75
+ return key;
76
+ }
77
+ }
78
+ return null;
79
+ };
80
+
81
+ var isMobile = function() {
82
+ var check = false;
83
+ (function(a) {
84
+ if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
85
+ })(navigator.userAgent || navigator.vendor || window.opera);
86
+ return check;
87
+ };
88
+
89
+
90
+ /**
91
+ * Fix shortcut. Mac use Command, others use Ctrl.
92
+ */
93
+ function fixShortcut(name) {
94
+ if(mac) {
95
+ name = name.replace("Ctrl", "Cmd");
96
+ } else {
97
+ name = name.replace("Cmd", "Ctrl");
98
+ }
99
+ return name;
100
+ }
101
+
102
+
103
+ /**
104
+ * Create icon element for toolbar.
105
+ */
106
+ function createIcon(options, enableTooltips, shortcuts) {
107
+ options = options || {};
108
+ var el = document.createElement("a");
109
+ enableTooltips = (enableTooltips == undefined) ? true : enableTooltips;
110
+
111
+ if(options.title && enableTooltips) {
112
+ el.title = createTootlip(options.title, options.action, shortcuts);
113
+
114
+ if(mac && !options.useCtrlOnMac) {
115
+ el.title = el.title.replace("Ctrl", "⌘");
116
+ }
117
+
118
+ if(mac) {
119
+ el.title = el.title.replace("Alt", "⌥");
120
+ }
121
+ }
122
+
123
+ el.tabIndex = -1;
124
+ el.className = options.className;
125
+ return el;
126
+ }
127
+
128
+ function createSep() {
129
+ var el = document.createElement("i");
130
+ el.className = "separator";
131
+ el.innerHTML = "|";
132
+ return el;
133
+ }
134
+
135
+ function createTootlip(title, action, shortcuts) {
136
+ var actionName;
137
+ var tooltip = title;
138
+
139
+ if(action) {
140
+ actionName = getBindingName(action);
141
+ if(shortcuts[actionName]) {
142
+ tooltip += " (" + fixShortcut(shortcuts[actionName]) + ")";
143
+ }
144
+ }
145
+
146
+ return tooltip;
147
+ }
148
+
149
+ /**
150
+ * The state of CodeMirror at the given position.
151
+ */
152
+ function getState(cm, pos) {
153
+ pos = pos || cm.getCursor("start");
154
+ var stat = cm.getTokenAt(pos);
155
+ if(!stat.type) return {};
156
+
157
+ var types = stat.type.split(" ");
158
+
159
+ var ret = {},
160
+ data, text;
161
+ for(var i = 0; i < types.length; i++) {
162
+ data = types[i];
163
+ if(data === "strong") {
164
+ ret.bold = true;
165
+ } else if(data === "variable-2") {
166
+ text = cm.getLine(pos.line);
167
+ if(/^\s*\d+\.\s/.test(text)) {
168
+ ret["ordered-list"] = true;
169
+ } else {
170
+ ret["unordered-list"] = true;
171
+ }
172
+ } else if(data === "atom") {
173
+ ret.quote = true;
174
+ } else if(data === "em") {
175
+ ret.italic = true;
176
+ } else if(data === "quote") {
177
+ ret.quote = true;
178
+ } else if(data === "strikethrough") {
179
+ ret.strikethrough = true;
180
+ } else if(data === "comment") {
181
+ ret.code = true;
182
+ } else if(data === "link") {
183
+ ret.link = true;
184
+ } else if(data === "tag") {
185
+ ret.image = true;
186
+ } else if(data.match(/^header(\-[1-6])?$/)) {
187
+ ret[data.replace("header", "heading")] = true;
188
+ }
189
+ }
190
+ return ret;
191
+ }
192
+
193
+
194
+ // Saved overflow setting
195
+ var saved_overflow = "";
196
+
197
+ /**
198
+ * Toggle full screen of the editor.
199
+ */
200
+ function toggleFullScreen(editor) {
201
+ // Set fullscreen
202
+ var cm = editor.codemirror;
203
+ cm.setOption("fullScreen", !cm.getOption("fullScreen"));
204
+
205
+
206
+ // Prevent scrolling on body during fullscreen active
207
+ if(cm.getOption("fullScreen")) {
208
+ saved_overflow = document.body.style.overflow;
209
+ document.body.style.overflow = "hidden";
210
+ } else {
211
+ document.body.style.overflow = saved_overflow;
212
+ }
213
+
214
+
215
+ // Update toolbar class
216
+ var wrap = cm.getWrapperElement();
217
+
218
+ if(!/fullscreen/.test(wrap.previousSibling.className)) {
219
+ wrap.previousSibling.className += " fullscreen";
220
+ } else {
221
+ wrap.previousSibling.className = wrap.previousSibling.className.replace(/\s*fullscreen\b/, "");
222
+ }
223
+
224
+
225
+ // Update toolbar button
226
+ var toolbarButton = editor.toolbarElements.fullscreen;
227
+
228
+ if(!/active/.test(toolbarButton.className)) {
229
+ toolbarButton.className += " active";
230
+ } else {
231
+ toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
232
+ }
233
+
234
+
235
+ // Hide side by side if needed
236
+ var sidebyside = cm.getWrapperElement().nextSibling;
237
+ if(/editor-preview-active-side/.test(sidebyside.className))
238
+ toggleSideBySide(editor);
239
+ }
240
+
241
+
242
+ /**
243
+ * Action for toggling bold.
244
+ */
245
+ function toggleBold(editor) {
246
+ _toggleBlock(editor, "bold", editor.options.blockStyles.bold);
247
+ }
248
+
249
+
250
+ /**
251
+ * Action for toggling italic.
252
+ */
253
+ function toggleItalic(editor) {
254
+ _toggleBlock(editor, "italic", editor.options.blockStyles.italic);
255
+ }
256
+
257
+
258
+ /**
259
+ * Action for toggling strikethrough.
260
+ */
261
+ function toggleStrikethrough(editor) {
262
+ _toggleBlock(editor, "strikethrough", "~~");
263
+ }
264
+
265
+ /**
266
+ * Action for toggling code block.
267
+ */
268
+ function toggleCodeBlock(editor) {
269
+ var fenceCharsToInsert = editor.options.blockStyles.code;
270
+
271
+ function fencing_line(line) {
272
+ /* return true, if this is a ``` or ~~~ line */
273
+ if(typeof line !== "object") {
274
+ throw "fencing_line() takes a 'line' object (not a line number, or line text). Got: " + typeof line + ": " + line;
275
+ }
276
+ return line.styles && line.styles[2] && line.styles[2].indexOf("formatting-code-block") !== -1;
277
+ }
278
+
279
+ function token_state(token) {
280
+ // base goes an extra level deep when mode backdrops are used, e.g. spellchecker on
281
+ return token.state.base.base || token.state.base;
282
+ }
283
+
284
+ function code_type(cm, line_num, line, firstTok, lastTok) {
285
+ /*
286
+ * Return "single", "indented", "fenced" or false
287
+ *
288
+ * cm and line_num are required. Others are optional for efficiency
289
+ * To check in the middle of a line, pass in firstTok yourself.
290
+ */
291
+ line = line || cm.getLineHandle(line_num);
292
+ firstTok = firstTok || cm.getTokenAt({
293
+ line: line_num,
294
+ ch: 1
295
+ });
296
+ lastTok = lastTok || (!!line.text && cm.getTokenAt({
297
+ line: line_num,
298
+ ch: line.text.length - 1
299
+ }));
300
+ var types = firstTok.type ? firstTok.type.split(" ") : [];
301
+ if(lastTok && token_state(lastTok).indentedCode) {
302
+ // have to check last char, since first chars of first line aren"t marked as indented
303
+ return "indented";
304
+ } else if(types.indexOf("comment") === -1) {
305
+ // has to be after "indented" check, since first chars of first indented line aren"t marked as such
306
+ return false;
307
+ } else if(token_state(firstTok).fencedChars || token_state(lastTok).fencedChars || fencing_line(line)) {
308
+ return "fenced";
309
+ } else {
310
+ return "single";
311
+ }
312
+ }
313
+
314
+ function insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert) {
315
+ var start_line_sel = cur_start.line + 1,
316
+ end_line_sel = cur_end.line + 1,
317
+ sel_multi = cur_start.line !== cur_end.line,
318
+ repl_start = fenceCharsToInsert + "\n",
319
+ repl_end = "\n" + fenceCharsToInsert;
320
+ if(sel_multi) {
321
+ end_line_sel++;
322
+ }
323
+ // handle last char including \n or not
324
+ if(sel_multi && cur_end.ch === 0) {
325
+ repl_end = fenceCharsToInsert + "\n";
326
+ end_line_sel--;
327
+ }
328
+ _replaceSelection(cm, false, [repl_start, repl_end]);
329
+ cm.setSelection({
330
+ line: start_line_sel,
331
+ ch: 0
332
+ }, {
333
+ line: end_line_sel,
334
+ ch: 0
335
+ });
336
+ }
337
+
338
+ var cm = editor.codemirror,
339
+ cur_start = cm.getCursor("start"),
340
+ cur_end = cm.getCursor("end"),
341
+ tok = cm.getTokenAt({
342
+ line: cur_start.line,
343
+ ch: cur_start.ch || 1
344
+ }), // avoid ch 0 which is a cursor pos but not token
345
+ line = cm.getLineHandle(cur_start.line),
346
+ is_code = code_type(cm, cur_start.line, line, tok);
347
+ var block_start, block_end, lineCount;
348
+
349
+ if(is_code === "single") {
350
+ // similar to some SimpleMDE _toggleBlock logic
351
+ var start = line.text.slice(0, cur_start.ch).replace("`", ""),
352
+ end = line.text.slice(cur_start.ch).replace("`", "");
353
+ cm.replaceRange(start + end, {
354
+ line: cur_start.line,
355
+ ch: 0
356
+ }, {
357
+ line: cur_start.line,
358
+ ch: 99999999999999
359
+ });
360
+ cur_start.ch--;
361
+ if(cur_start !== cur_end) {
362
+ cur_end.ch--;
363
+ }
364
+ cm.setSelection(cur_start, cur_end);
365
+ cm.focus();
366
+ } else if(is_code === "fenced") {
367
+ if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
368
+ // use selection
369
+
370
+ // find the fenced line so we know what type it is (tilde, backticks, number of them)
371
+ for(block_start = cur_start.line; block_start >= 0; block_start--) {
372
+ line = cm.getLineHandle(block_start);
373
+ if(fencing_line(line)) {
374
+ break;
375
+ }
376
+ }
377
+ var fencedTok = cm.getTokenAt({
378
+ line: block_start,
379
+ ch: 1
380
+ });
381
+ var fence_chars = token_state(fencedTok).fencedChars;
382
+ var start_text, start_line;
383
+ var end_text, end_line;
384
+ // check for selection going up against fenced lines, in which case we don't want to add more fencing
385
+ if(fencing_line(cm.getLineHandle(cur_start.line))) {
386
+ start_text = "";
387
+ start_line = cur_start.line;
388
+ } else if(fencing_line(cm.getLineHandle(cur_start.line - 1))) {
389
+ start_text = "";
390
+ start_line = cur_start.line - 1;
391
+ } else {
392
+ start_text = fence_chars + "\n";
393
+ start_line = cur_start.line;
394
+ }
395
+ if(fencing_line(cm.getLineHandle(cur_end.line))) {
396
+ end_text = "";
397
+ end_line = cur_end.line;
398
+ if(cur_end.ch === 0) {
399
+ end_line += 1;
400
+ }
401
+ } else if(cur_end.ch !== 0 && fencing_line(cm.getLineHandle(cur_end.line + 1))) {
402
+ end_text = "";
403
+ end_line = cur_end.line + 1;
404
+ } else {
405
+ end_text = fence_chars + "\n";
406
+ end_line = cur_end.line + 1;
407
+ }
408
+ if(cur_end.ch === 0) {
409
+ // full last line selected, putting cursor at beginning of next
410
+ end_line -= 1;
411
+ }
412
+ cm.operation(function() {
413
+ // end line first, so that line numbers don't change
414
+ cm.replaceRange(end_text, {
415
+ line: end_line,
416
+ ch: 0
417
+ }, {
418
+ line: end_line + (end_text ? 0 : 1),
419
+ ch: 0
420
+ });
421
+ cm.replaceRange(start_text, {
422
+ line: start_line,
423
+ ch: 0
424
+ }, {
425
+ line: start_line + (start_text ? 0 : 1),
426
+ ch: 0
427
+ });
428
+ });
429
+ cm.setSelection({
430
+ line: start_line + (start_text ? 1 : 0),
431
+ ch: 0
432
+ }, {
433
+ line: end_line + (start_text ? 1 : -1),
434
+ ch: 0
435
+ });
436
+ cm.focus();
437
+ } else {
438
+ // no selection, search for ends of this fenced block
439
+ var search_from = cur_start.line;
440
+ if(fencing_line(cm.getLineHandle(cur_start.line))) { // gets a little tricky if cursor is right on a fenced line
441
+ if(code_type(cm, cur_start.line + 1) === "fenced") {
442
+ block_start = cur_start.line;
443
+ search_from = cur_start.line + 1; // for searching for "end"
444
+ } else {
445
+ block_end = cur_start.line;
446
+ search_from = cur_start.line - 1; // for searching for "start"
447
+ }
448
+ }
449
+ if(block_start === undefined) {
450
+ for(block_start = search_from; block_start >= 0; block_start--) {
451
+ line = cm.getLineHandle(block_start);
452
+ if(fencing_line(line)) {
453
+ break;
454
+ }
455
+ }
456
+ }
457
+ if(block_end === undefined) {
458
+ lineCount = cm.lineCount();
459
+ for(block_end = search_from; block_end < lineCount; block_end++) {
460
+ line = cm.getLineHandle(block_end);
461
+ if(fencing_line(line)) {
462
+ break;
463
+ }
464
+ }
465
+ }
466
+ cm.operation(function() {
467
+ cm.replaceRange("", {
468
+ line: block_start,
469
+ ch: 0
470
+ }, {
471
+ line: block_start + 1,
472
+ ch: 0
473
+ });
474
+ cm.replaceRange("", {
475
+ line: block_end - 1,
476
+ ch: 0
477
+ }, {
478
+ line: block_end,
479
+ ch: 0
480
+ });
481
+ });
482
+ cm.focus();
483
+ }
484
+ } else if(is_code === "indented") {
485
+ if(cur_start.line !== cur_end.line || cur_start.ch !== cur_end.ch) {
486
+ // use selection
487
+ block_start = cur_start.line;
488
+ block_end = cur_end.line;
489
+ if(cur_end.ch === 0) {
490
+ block_end--;
491
+ }
492
+ } else {
493
+ // no selection, search for ends of this indented block
494
+ for(block_start = cur_start.line; block_start >= 0; block_start--) {
495
+ line = cm.getLineHandle(block_start);
496
+ if(line.text.match(/^\s*$/)) {
497
+ // empty or all whitespace - keep going
498
+ continue;
499
+ } else {
500
+ if(code_type(cm, block_start, line) !== "indented") {
501
+ block_start += 1;
502
+ break;
503
+ }
504
+ }
505
+ }
506
+ lineCount = cm.lineCount();
507
+ for(block_end = cur_start.line; block_end < lineCount; block_end++) {
508
+ line = cm.getLineHandle(block_end);
509
+ if(line.text.match(/^\s*$/)) {
510
+ // empty or all whitespace - keep going
511
+ continue;
512
+ } else {
513
+ if(code_type(cm, block_end, line) !== "indented") {
514
+ block_end -= 1;
515
+ break;
516
+ }
517
+ }
518
+ }
519
+ }
520
+ // if we are going to un-indent based on a selected set of lines, and the next line is indented too, we need to
521
+ // insert a blank line so that the next line(s) continue to be indented code
522
+ var next_line = cm.getLineHandle(block_end + 1),
523
+ next_line_last_tok = next_line && cm.getTokenAt({
524
+ line: block_end + 1,
525
+ ch: next_line.text.length - 1
526
+ }),
527
+ next_line_indented = next_line_last_tok && token_state(next_line_last_tok).indentedCode;
528
+ if(next_line_indented) {
529
+ cm.replaceRange("\n", {
530
+ line: block_end + 1,
531
+ ch: 0
532
+ });
533
+ }
534
+
535
+ for(var i = block_start; i <= block_end; i++) {
536
+ cm.indentLine(i, "subtract"); // TODO: this doesn't get tracked in the history, so can't be undone :(
537
+ }
538
+ cm.focus();
539
+ } else {
540
+ // insert code formatting
541
+ var no_sel_and_starting_of_line = (cur_start.line === cur_end.line && cur_start.ch === cur_end.ch && cur_start.ch === 0);
542
+ var sel_multi = cur_start.line !== cur_end.line;
543
+ if(no_sel_and_starting_of_line || sel_multi) {
544
+ insertFencingAtSelection(cm, cur_start, cur_end, fenceCharsToInsert);
545
+ } else {
546
+ _replaceSelection(cm, false, ["`", "`"]);
547
+ }
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Action for toggling blockquote.
553
+ */
554
+ function toggleBlockquote(editor) {
555
+ var cm = editor.codemirror;
556
+ _toggleLine(cm, "quote");
557
+ }
558
+
559
+ /**
560
+ * Action for toggling heading size: normal -> h1 -> h2 -> h3 -> h4 -> h5 -> h6 -> normal
561
+ */
562
+ function toggleHeadingSmaller(editor) {
563
+ var cm = editor.codemirror;
564
+ _toggleHeading(cm, "smaller");
565
+ }
566
+
567
+ /**
568
+ * Action for toggling heading size: normal -> h6 -> h5 -> h4 -> h3 -> h2 -> h1 -> normal
569
+ */
570
+ function toggleHeadingBigger(editor) {
571
+ var cm = editor.codemirror;
572
+ _toggleHeading(cm, "bigger");
573
+ }
574
+
575
+ /**
576
+ * Action for toggling heading size 1
577
+ */
578
+ function toggleHeading1(editor) {
579
+ var cm = editor.codemirror;
580
+ _toggleHeading(cm, undefined, 1);
581
+ }
582
+
583
+ /**
584
+ * Action for toggling heading size 2
585
+ */
586
+ function toggleHeading2(editor) {
587
+ var cm = editor.codemirror;
588
+ _toggleHeading(cm, undefined, 2);
589
+ }
590
+
591
+ /**
592
+ * Action for toggling heading size 3
593
+ */
594
+ function toggleHeading3(editor) {
595
+ var cm = editor.codemirror;
596
+ _toggleHeading(cm, undefined, 3);
597
+ }
598
+
599
+
600
+ /**
601
+ * Action for toggling ul.
602
+ */
603
+ function toggleUnorderedList(editor) {
604
+ var cm = editor.codemirror;
605
+ _toggleLine(cm, "unordered-list");
606
+ }
607
+
608
+
609
+ /**
610
+ * Action for toggling ol.
611
+ */
612
+ function toggleOrderedList(editor) {
613
+ var cm = editor.codemirror;
614
+ _toggleLine(cm, "ordered-list");
615
+ }
616
+
617
+ /**
618
+ * Action for clean block (remove headline, list, blockquote code, markers)
619
+ */
620
+ function cleanBlock(editor) {
621
+ var cm = editor.codemirror;
622
+ _cleanBlock(cm);
623
+ }
624
+
625
+ /**
626
+ * Action for drawing a link.
627
+ */
628
+ function drawLink(editor) {
629
+ var cm = editor.codemirror;
630
+ var stat = getState(cm);
631
+ var options = editor.options;
632
+ var url = "http://";
633
+ if(options.promptURLs) {
634
+ url = prompt(options.promptTexts.link);
635
+ if(!url) {
636
+ return false;
637
+ }
638
+ }
639
+ _replaceSelection(cm, stat.link, options.insertTexts.link, url);
640
+ }
641
+
642
+ /**
643
+ * Action for drawing an img.
644
+ */
645
+ function drawImage(editor) {
646
+ var cm = editor.codemirror;
647
+ var stat = getState(cm);
648
+ var options = editor.options;
649
+ var url = "http://";
650
+ if(options.promptURLs) {
651
+ url = prompt(options.promptTexts.image);
652
+ if(!url) {
653
+ return false;
654
+ }
655
+ }
656
+ _replaceSelection(cm, stat.image, options.insertTexts.image, url);
657
+ }
658
+
659
+ /**
660
+ * Action for drawing a table.
661
+ */
662
+ function drawTable(editor) {
663
+ var cm = editor.codemirror;
664
+ var stat = getState(cm);
665
+ var options = editor.options;
666
+ _replaceSelection(cm, stat.table, options.insertTexts.table);
667
+ }
668
+
669
+ /**
670
+ * Action for drawing a horizontal rule.
671
+ */
672
+ function drawHorizontalRule(editor) {
673
+ var cm = editor.codemirror;
674
+ var stat = getState(cm);
675
+ var options = editor.options;
676
+ _replaceSelection(cm, stat.image, options.insertTexts.horizontalRule);
677
+ }
678
+
679
+
680
+ /**
681
+ * Undo action.
682
+ */
683
+ function undo(editor) {
684
+ var cm = editor.codemirror;
685
+ cm.undo();
686
+ cm.focus();
687
+ }
688
+
689
+
690
+ /**
691
+ * Redo action.
692
+ */
693
+ function redo(editor) {
694
+ var cm = editor.codemirror;
695
+ cm.redo();
696
+ cm.focus();
697
+ }
698
+
699
+
700
+ /**
701
+ * Toggle side by side preview
702
+ */
703
+ function toggleSideBySide(editor) {
704
+ var cm = editor.codemirror;
705
+ var wrapper = cm.getWrapperElement();
706
+ var preview = wrapper.nextSibling;
707
+ var toolbarButton = editor.toolbarElements["side-by-side"];
708
+ var useSideBySideListener = false;
709
+ if(/editor-preview-active-side/.test(preview.className)) {
710
+ preview.className = preview.className.replace(
711
+ /\s*editor-preview-active-side\s*/g, ""
712
+ );
713
+ toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
714
+ wrapper.className = wrapper.className.replace(/\s*CodeMirror-sided\s*/g, " ");
715
+ } else {
716
+ // When the preview button is clicked for the first time,
717
+ // give some time for the transition from editor.css to fire and the view to slide from right to left,
718
+ // instead of just appearing.
719
+ setTimeout(function() {
720
+ if(!cm.getOption("fullScreen"))
721
+ toggleFullScreen(editor);
722
+ preview.className += " editor-preview-active-side";
723
+ }, 1);
724
+ toolbarButton.className += " active";
725
+ wrapper.className += " CodeMirror-sided";
726
+ useSideBySideListener = true;
727
+ }
728
+
729
+ // Hide normal preview if active
730
+ var previewNormal = wrapper.lastChild;
731
+ if(/editor-preview-active/.test(previewNormal.className)) {
732
+ previewNormal.className = previewNormal.className.replace(
733
+ /\s*editor-preview-active\s*/g, ""
734
+ );
735
+ var toolbar = editor.toolbarElements.preview;
736
+ var toolbar_div = wrapper.previousSibling;
737
+ toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
738
+ toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
739
+ }
740
+
741
+ var sideBySideRenderingFunction = function() {
742
+ preview.innerHTML = editor.options.previewRender(editor.value(), preview);
743
+ };
744
+
745
+ if(!cm.sideBySideRenderingFunction) {
746
+ cm.sideBySideRenderingFunction = sideBySideRenderingFunction;
747
+ }
748
+
749
+ if(useSideBySideListener) {
750
+ preview.innerHTML = editor.options.previewRender(editor.value(), preview);
751
+ cm.on("update", cm.sideBySideRenderingFunction);
752
+ } else {
753
+ cm.off("update", cm.sideBySideRenderingFunction);
754
+ }
755
+
756
+ // Refresh to fix selection being off (#309)
757
+ cm.refresh();
758
+ }
759
+
760
+
761
+ /**
762
+ * Preview action.
763
+ */
764
+ function togglePreview(editor) {
765
+ var cm = editor.codemirror;
766
+ var wrapper = cm.getWrapperElement();
767
+ var toolbar_div = wrapper.previousSibling;
768
+ var toolbar = editor.options.toolbar ? editor.toolbarElements.preview : false;
769
+ var preview = wrapper.lastChild;
770
+ if(!preview || !/editor-preview/.test(preview.className)) {
771
+ preview = document.createElement("div");
772
+ preview.className = "editor-preview";
773
+ wrapper.appendChild(preview);
774
+ }
775
+ if(/editor-preview-active/.test(preview.className)) {
776
+ preview.className = preview.className.replace(
777
+ /\s*editor-preview-active\s*/g, ""
778
+ );
779
+ if(toolbar) {
780
+ toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
781
+ toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
782
+ }
783
+ } else {
784
+ // When the preview button is clicked for the first time,
785
+ // give some time for the transition from editor.css to fire and the view to slide from right to left,
786
+ // instead of just appearing.
787
+ setTimeout(function() {
788
+ preview.className += " editor-preview-active";
789
+ }, 1);
790
+ if(toolbar) {
791
+ toolbar.className += " active";
792
+ toolbar_div.className += " disabled-for-preview";
793
+ }
794
+ }
795
+ preview.innerHTML = editor.options.previewRender(editor.value(), preview);
796
+
797
+ // Turn off side by side if needed
798
+ var sidebyside = cm.getWrapperElement().nextSibling;
799
+ if(/editor-preview-active-side/.test(sidebyside.className))
800
+ toggleSideBySide(editor);
801
+ }
802
+
803
+ function _replaceSelection(cm, active, startEnd, url) {
804
+ if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
805
+ return;
806
+
807
+ var text;
808
+ var start = startEnd[0];
809
+ var end = startEnd[1];
810
+ var startPoint = cm.getCursor("start");
811
+ var endPoint = cm.getCursor("end");
812
+ if(url) {
813
+ end = end.replace("#url#", url);
814
+ }
815
+ if(active) {
816
+ text = cm.getLine(startPoint.line);
817
+ start = text.slice(0, startPoint.ch);
818
+ end = text.slice(startPoint.ch);
819
+ cm.replaceRange(start + end, {
820
+ line: startPoint.line,
821
+ ch: 0
822
+ });
823
+ } else {
824
+ text = cm.getSelection();
825
+ cm.replaceSelection(start + text + end);
826
+
827
+ startPoint.ch += start.length;
828
+ if(startPoint !== endPoint) {
829
+ endPoint.ch += start.length;
830
+ }
831
+ }
832
+ cm.setSelection(startPoint, endPoint);
833
+ cm.focus();
834
+ }
835
+
836
+
837
+ function _toggleHeading(cm, direction, size) {
838
+ if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
839
+ return;
840
+
841
+ var startPoint = cm.getCursor("start");
842
+ var endPoint = cm.getCursor("end");
843
+ for(var i = startPoint.line; i <= endPoint.line; i++) {
844
+ (function(i) {
845
+ var text = cm.getLine(i);
846
+ var currHeadingLevel = text.search(/[^#]/);
847
+
848
+ if(direction !== undefined) {
849
+ if(currHeadingLevel <= 0) {
850
+ if(direction == "bigger") {
851
+ text = "###### " + text;
852
+ } else {
853
+ text = "# " + text;
854
+ }
855
+ } else if(currHeadingLevel == 6 && direction == "smaller") {
856
+ text = text.substr(7);
857
+ } else if(currHeadingLevel == 1 && direction == "bigger") {
858
+ text = text.substr(2);
859
+ } else {
860
+ if(direction == "bigger") {
861
+ text = text.substr(1);
862
+ } else {
863
+ text = "#" + text;
864
+ }
865
+ }
866
+ } else {
867
+ if(size == 1) {
868
+ if(currHeadingLevel <= 0) {
869
+ text = "# " + text;
870
+ } else if(currHeadingLevel == size) {
871
+ text = text.substr(currHeadingLevel + 1);
872
+ } else {
873
+ text = "# " + text.substr(currHeadingLevel + 1);
874
+ }
875
+ } else if(size == 2) {
876
+ if(currHeadingLevel <= 0) {
877
+ text = "## " + text;
878
+ } else if(currHeadingLevel == size) {
879
+ text = text.substr(currHeadingLevel + 1);
880
+ } else {
881
+ text = "## " + text.substr(currHeadingLevel + 1);
882
+ }
883
+ } else {
884
+ if(currHeadingLevel <= 0) {
885
+ text = "### " + text;
886
+ } else if(currHeadingLevel == size) {
887
+ text = text.substr(currHeadingLevel + 1);
888
+ } else {
889
+ text = "### " + text.substr(currHeadingLevel + 1);
890
+ }
891
+ }
892
+ }
893
+
894
+ cm.replaceRange(text, {
895
+ line: i,
896
+ ch: 0
897
+ }, {
898
+ line: i,
899
+ ch: 99999999999999
900
+ });
901
+ })(i);
902
+ }
903
+ cm.focus();
904
+ }
905
+
906
+
907
+ function _toggleLine(cm, name) {
908
+ if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
909
+ return;
910
+
911
+ var stat = getState(cm);
912
+ var startPoint = cm.getCursor("start");
913
+ var endPoint = cm.getCursor("end");
914
+ var repl = {
915
+ "quote": /^(\s*)\>\s+/,
916
+ "unordered-list": /^(\s*)(\*|\-|\+)\s+/,
917
+ "ordered-list": /^(\s*)\d+\.\s+/
918
+ };
919
+ var map = {
920
+ "quote": "> ",
921
+ "unordered-list": "* ",
922
+ "ordered-list": "1. "
923
+ };
924
+ for(var i = startPoint.line; i <= endPoint.line; i++) {
925
+ (function(i) {
926
+ var text = cm.getLine(i);
927
+ if(stat[name]) {
928
+ text = text.replace(repl[name], "$1");
929
+ } else {
930
+ text = map[name] + text;
931
+ }
932
+ cm.replaceRange(text, {
933
+ line: i,
934
+ ch: 0
935
+ }, {
936
+ line: i,
937
+ ch: 99999999999999
938
+ });
939
+ })(i);
940
+ }
941
+ cm.focus();
942
+ }
943
+
944
+ function _toggleBlock(editor, type, start_chars, end_chars) {
945
+ if(/editor-preview-active/.test(editor.codemirror.getWrapperElement().lastChild.className))
946
+ return;
947
+
948
+ end_chars = (typeof end_chars === "undefined") ? start_chars : end_chars;
949
+ var cm = editor.codemirror;
950
+ var stat = getState(cm);
951
+
952
+ var text;
953
+ var start = start_chars;
954
+ var end = end_chars;
955
+
956
+ var startPoint = cm.getCursor("start");
957
+ var endPoint = cm.getCursor("end");
958
+
959
+ if(stat[type]) {
960
+ text = cm.getLine(startPoint.line);
961
+ start = text.slice(0, startPoint.ch);
962
+ end = text.slice(startPoint.ch);
963
+ if(type == "bold") {
964
+ start = start.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/, "");
965
+ end = end.replace(/(\*\*|__)/, "");
966
+ } else if(type == "italic") {
967
+ start = start.replace(/(\*|_)(?![\s\S]*(\*|_))/, "");
968
+ end = end.replace(/(\*|_)/, "");
969
+ } else if(type == "strikethrough") {
970
+ start = start.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/, "");
971
+ end = end.replace(/(\*\*|~~)/, "");
972
+ }
973
+ cm.replaceRange(start + end, {
974
+ line: startPoint.line,
975
+ ch: 0
976
+ }, {
977
+ line: startPoint.line,
978
+ ch: 99999999999999
979
+ });
980
+
981
+ if(type == "bold" || type == "strikethrough") {
982
+ startPoint.ch -= 2;
983
+ if(startPoint !== endPoint) {
984
+ endPoint.ch -= 2;
985
+ }
986
+ } else if(type == "italic") {
987
+ startPoint.ch -= 1;
988
+ if(startPoint !== endPoint) {
989
+ endPoint.ch -= 1;
990
+ }
991
+ }
992
+ } else {
993
+ text = cm.getSelection();
994
+ if(type == "bold") {
995
+ text = text.split("**").join("");
996
+ text = text.split("__").join("");
997
+ } else if(type == "italic") {
998
+ text = text.split("*").join("");
999
+ text = text.split("_").join("");
1000
+ } else if(type == "strikethrough") {
1001
+ text = text.split("~~").join("");
1002
+ }
1003
+ cm.replaceSelection(start + text + end);
1004
+
1005
+ startPoint.ch += start_chars.length;
1006
+ endPoint.ch = startPoint.ch + text.length;
1007
+ }
1008
+
1009
+ cm.setSelection(startPoint, endPoint);
1010
+ cm.focus();
1011
+ }
1012
+
1013
+ function _cleanBlock(cm) {
1014
+ if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
1015
+ return;
1016
+
1017
+ var startPoint = cm.getCursor("start");
1018
+ var endPoint = cm.getCursor("end");
1019
+ var text;
1020
+
1021
+ for(var line = startPoint.line; line <= endPoint.line; line++) {
1022
+ text = cm.getLine(line);
1023
+ text = text.replace(/^[ ]*([# ]+|\*|\-|[> ]+|[0-9]+(.|\)))[ ]*/, "");
1024
+
1025
+ cm.replaceRange(text, {
1026
+ line: line,
1027
+ ch: 0
1028
+ }, {
1029
+ line: line,
1030
+ ch: 99999999999999
1031
+ });
1032
+ }
1033
+ }
1034
+
1035
+ // Merge the properties of one object into another.
1036
+ function _mergeProperties(target, source) {
1037
+ for(var property in source) {
1038
+ if(source.hasOwnProperty(property)) {
1039
+ if(source[property] instanceof Array) {
1040
+ target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []);
1041
+ } else if(
1042
+ source[property] !== null &&
1043
+ typeof source[property] === "object" &&
1044
+ source[property].constructor === Object
1045
+ ) {
1046
+ target[property] = _mergeProperties(target[property] || {}, source[property]);
1047
+ } else {
1048
+ target[property] = source[property];
1049
+ }
1050
+ }
1051
+ }
1052
+
1053
+ return target;
1054
+ }
1055
+
1056
+ // Merge an arbitrary number of objects into one.
1057
+ function extend(target) {
1058
+ for(var i = 1; i < arguments.length; i++) {
1059
+ target = _mergeProperties(target, arguments[i]);
1060
+ }
1061
+
1062
+ return target;
1063
+ }
1064
+
1065
+ /* The right word count in respect for CJK. */
1066
+ function wordCount(data) {
1067
+ var pattern = /[a-zA-Z0-9_\u0392-\u03c9\u0410-\u04F9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
1068
+ var m = data.match(pattern);
1069
+ var count = 0;
1070
+ if(m === null) return count;
1071
+ for(var i = 0; i < m.length; i++) {
1072
+ if(m[i].charCodeAt(0) >= 0x4E00) {
1073
+ count += m[i].length;
1074
+ } else {
1075
+ count += 1;
1076
+ }
1077
+ }
1078
+ return count;
1079
+ }
1080
+
1081
+ var toolbarBuiltInButtons = {
1082
+ "bold": {
1083
+ name: "bold",
1084
+ action: toggleBold,
1085
+ className: "fa fa-bold",
1086
+ title: "Bold",
1087
+ default: true
1088
+ },
1089
+ "italic": {
1090
+ name: "italic",
1091
+ action: toggleItalic,
1092
+ className: "fa fa-italic",
1093
+ title: "Italic",
1094
+ default: true
1095
+ },
1096
+ "strikethrough": {
1097
+ name: "strikethrough",
1098
+ action: toggleStrikethrough,
1099
+ className: "fa fa-strikethrough",
1100
+ title: "Strikethrough"
1101
+ },
1102
+ "heading": {
1103
+ name: "heading",
1104
+ action: toggleHeadingSmaller,
1105
+ className: "fa fa-header",
1106
+ title: "Heading",
1107
+ default: true
1108
+ },
1109
+ "heading-smaller": {
1110
+ name: "heading-smaller",
1111
+ action: toggleHeadingSmaller,
1112
+ className: "fa fa-header fa-header-x fa-header-smaller",
1113
+ title: "Smaller Heading"
1114
+ },
1115
+ "heading-bigger": {
1116
+ name: "heading-bigger",
1117
+ action: toggleHeadingBigger,
1118
+ className: "fa fa-header fa-header-x fa-header-bigger",
1119
+ title: "Bigger Heading"
1120
+ },
1121
+ "heading-1": {
1122
+ name: "heading-1",
1123
+ action: toggleHeading1,
1124
+ className: "fa fa-header fa-header-x fa-header-1",
1125
+ title: "Big Heading"
1126
+ },
1127
+ "heading-2": {
1128
+ name: "heading-2",
1129
+ action: toggleHeading2,
1130
+ className: "fa fa-header fa-header-x fa-header-2",
1131
+ title: "Medium Heading"
1132
+ },
1133
+ "heading-3": {
1134
+ name: "heading-3",
1135
+ action: toggleHeading3,
1136
+ className: "fa fa-header fa-header-x fa-header-3",
1137
+ title: "Small Heading"
1138
+ },
1139
+ "separator-1": {
1140
+ name: "separator-1"
1141
+ },
1142
+ "code": {
1143
+ name: "code",
1144
+ action: toggleCodeBlock,
1145
+ className: "fa fa-code",
1146
+ title: "Code"
1147
+ },
1148
+ "quote": {
1149
+ name: "quote",
1150
+ action: toggleBlockquote,
1151
+ className: "fa fa-quote-left",
1152
+ title: "Quote",
1153
+ default: true
1154
+ },
1155
+ "unordered-list": {
1156
+ name: "unordered-list",
1157
+ action: toggleUnorderedList,
1158
+ className: "fa fa-list-ul",
1159
+ title: "Generic List",
1160
+ default: true
1161
+ },
1162
+ "ordered-list": {
1163
+ name: "ordered-list",
1164
+ action: toggleOrderedList,
1165
+ className: "fa fa-list-ol",
1166
+ title: "Numbered List",
1167
+ default: true
1168
+ },
1169
+ "clean-block": {
1170
+ name: "clean-block",
1171
+ action: cleanBlock,
1172
+ className: "fa fa-eraser fa-clean-block",
1173
+ title: "Clean block"
1174
+ },
1175
+ "separator-2": {
1176
+ name: "separator-2"
1177
+ },
1178
+ "link": {
1179
+ name: "link",
1180
+ action: drawLink,
1181
+ className: "fa fa-link",
1182
+ title: "Create Link",
1183
+ default: true
1184
+ },
1185
+ "image": {
1186
+ name: "image",
1187
+ action: drawImage,
1188
+ className: "fa fa-picture-o",
1189
+ title: "Insert Image",
1190
+ default: true
1191
+ },
1192
+ "table": {
1193
+ name: "table",
1194
+ action: drawTable,
1195
+ className: "fa fa-table",
1196
+ title: "Insert Table"
1197
+ },
1198
+ "horizontal-rule": {
1199
+ name: "horizontal-rule",
1200
+ action: drawHorizontalRule,
1201
+ className: "fa fa-minus",
1202
+ title: "Insert Horizontal Line"
1203
+ },
1204
+ "separator-3": {
1205
+ name: "separator-3"
1206
+ },
1207
+ "preview": {
1208
+ name: "preview",
1209
+ action: togglePreview,
1210
+ className: "fa fa-eye no-disable",
1211
+ title: "Toggle Preview",
1212
+ default: true
1213
+ },
1214
+ "side-by-side": {
1215
+ name: "side-by-side",
1216
+ action: toggleSideBySide,
1217
+ className: "fa fa-columns no-disable no-mobile",
1218
+ title: "Toggle Side by Side",
1219
+ default: true
1220
+ },
1221
+ "fullscreen": {
1222
+ name: "fullscreen",
1223
+ action: toggleFullScreen,
1224
+ className: "fa fa-arrows-alt no-disable no-mobile",
1225
+ title: "Toggle Fullscreen",
1226
+ default: true
1227
+ },
1228
+ "separator-4": {
1229
+ name: "separator-4"
1230
+ },
1231
+ "guide": {
1232
+ name: "guide",
1233
+ action: "https://simplemde.com/markdown-guide",
1234
+ className: "fa fa-question-circle",
1235
+ title: "Markdown Guide",
1236
+ default: true
1237
+ },
1238
+ "separator-5": {
1239
+ name: "separator-5"
1240
+ },
1241
+ "undo": {
1242
+ name: "undo",
1243
+ action: undo,
1244
+ className: "fa fa-undo no-disable",
1245
+ title: "Undo"
1246
+ },
1247
+ "redo": {
1248
+ name: "redo",
1249
+ action: redo,
1250
+ className: "fa fa-repeat no-disable",
1251
+ title: "Redo"
1252
+ }
1253
+ };
1254
+
1255
+ var insertTexts = {
1256
+ link: ["[", "](#url#)"],
1257
+ image: ["![](", "#url#)"],
1258
+ table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
1259
+ horizontalRule: ["", "\n\n-----\n\n"]
1260
+ };
1261
+
1262
+ var promptTexts = {
1263
+ link: "URL for the link:",
1264
+ image: "URL of the image:"
1265
+ };
1266
+
1267
+ var blockStyles = {
1268
+ "bold": "**",
1269
+ "code": "```",
1270
+ "italic": "*"
1271
+ };
1272
+
1273
+ /**
1274
+ * Interface of SimpleMDE.
1275
+ */
1276
+ function SimpleMDE(options) {
1277
+ // Handle options parameter
1278
+ options = options || {};
1279
+
1280
+
1281
+ // Used later to refer to it"s parent
1282
+ options.parent = this;
1283
+
1284
+
1285
+ // Check if Font Awesome needs to be auto downloaded
1286
+ var autoDownloadFA = true;
1287
+
1288
+ if(options.autoDownloadFontAwesome === false) {
1289
+ autoDownloadFA = false;
1290
+ }
1291
+
1292
+ if(options.autoDownloadFontAwesome !== true) {
1293
+ var styleSheets = document.styleSheets;
1294
+ for(var i = 0; i < styleSheets.length; i++) {
1295
+ if(!styleSheets[i].href)
1296
+ continue;
1297
+
1298
+ if(styleSheets[i].href.indexOf("//maxcdn.bootstrapcdn.com/font-awesome/") > -1) {
1299
+ autoDownloadFA = false;
1300
+ }
1301
+ }
1302
+ }
1303
+
1304
+ if(autoDownloadFA) {
1305
+ var link = document.createElement("link");
1306
+ link.rel = "stylesheet";
1307
+ link.href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css";
1308
+ document.getElementsByTagName("head")[0].appendChild(link);
1309
+ }
1310
+
1311
+
1312
+ // Find the textarea to use
1313
+ if(options.element) {
1314
+ this.element = options.element;
1315
+ } else if(options.element === null) {
1316
+ // This means that the element option was specified, but no element was found
1317
+ console.log("SimpleMDE: Error. No element was found.");
1318
+ return;
1319
+ }
1320
+
1321
+
1322
+ // Handle toolbar
1323
+ if(options.toolbar === undefined) {
1324
+ // Initialize
1325
+ options.toolbar = [];
1326
+
1327
+
1328
+ // Loop over the built in buttons, to get the preferred order
1329
+ for(var key in toolbarBuiltInButtons) {
1330
+ if(toolbarBuiltInButtons.hasOwnProperty(key)) {
1331
+ if(key.indexOf("separator-") != -1) {
1332
+ options.toolbar.push("|");
1333
+ }
1334
+
1335
+ if(toolbarBuiltInButtons[key].default === true || (options.showIcons && options.showIcons.constructor === Array && options.showIcons.indexOf(key) != -1)) {
1336
+ options.toolbar.push(key);
1337
+ }
1338
+ }
1339
+ }
1340
+ }
1341
+
1342
+
1343
+ // Handle status bar
1344
+ if(!options.hasOwnProperty("status")) {
1345
+ options.status = ["autosave", "lines", "words", "cursor"];
1346
+ }
1347
+
1348
+
1349
+ // Add default preview rendering function
1350
+ if(!options.previewRender) {
1351
+ options.previewRender = function(plainText) {
1352
+ // Note: "this" refers to the options object
1353
+ return this.parent.markdown(plainText);
1354
+ };
1355
+ }
1356
+
1357
+
1358
+ // Set default options for parsing config
1359
+ options.parsingConfig = extend({
1360
+ highlightFormatting: true // needed for toggleCodeBlock to detect types of code
1361
+ }, options.parsingConfig || {});
1362
+
1363
+
1364
+ // Merging the insertTexts, with the given options
1365
+ options.insertTexts = extend({}, insertTexts, options.insertTexts || {});
1366
+
1367
+
1368
+ // Merging the promptTexts, with the given options
1369
+ options.promptTexts = promptTexts;
1370
+
1371
+
1372
+ // Merging the blockStyles, with the given options
1373
+ options.blockStyles = extend({}, blockStyles, options.blockStyles || {});
1374
+
1375
+
1376
+ // Merging the shortcuts, with the given options
1377
+ options.shortcuts = extend({}, shortcuts, options.shortcuts || {});
1378
+
1379
+
1380
+ // Change unique_id to uniqueId for backwards compatibility
1381
+ if(options.autosave != undefined && options.autosave.unique_id != undefined && options.autosave.unique_id != "")
1382
+ options.autosave.uniqueId = options.autosave.unique_id;
1383
+
1384
+
1385
+ // Update this options
1386
+ this.options = options;
1387
+
1388
+
1389
+ // Auto render
1390
+ this.render();
1391
+
1392
+
1393
+ // The codemirror component is only available after rendering
1394
+ // so, the setter for the initialValue can only run after
1395
+ // the element has been rendered
1396
+ if(options.initialValue && (!this.options.autosave || this.options.autosave.foundSavedValue !== true)) {
1397
+ this.value(options.initialValue);
1398
+ }
1399
+ }
1400
+
1401
+ /**
1402
+ * Default markdown render.
1403
+ */
1404
+ SimpleMDE.prototype.markdown = function(text) {
1405
+ if(marked) {
1406
+ // Initialize
1407
+ var markedOptions = {};
1408
+
1409
+
1410
+ // Update options
1411
+ if(this.options && this.options.renderingConfig && this.options.renderingConfig.singleLineBreaks === false) {
1412
+ markedOptions.breaks = false;
1413
+ } else {
1414
+ markedOptions.breaks = true;
1415
+ }
1416
+
1417
+ if(this.options && this.options.renderingConfig && this.options.renderingConfig.codeSyntaxHighlighting === true && window.hljs) {
1418
+ markedOptions.highlight = function(code) {
1419
+ return window.hljs.highlightAuto(code).value;
1420
+ };
1421
+ }
1422
+
1423
+
1424
+ // Set options
1425
+ marked.setOptions(markedOptions);
1426
+
1427
+
1428
+ // Return
1429
+ return marked(text);
1430
+ }
1431
+ };
1432
+
1433
+ /**
1434
+ * Render editor to the given element.
1435
+ */
1436
+ SimpleMDE.prototype.render = function(el) {
1437
+ if(!el) {
1438
+ el = this.element || document.getElementsByTagName("textarea")[0];
1439
+ }
1440
+
1441
+ if(this._rendered && this._rendered === el) {
1442
+ // Already rendered.
1443
+ return;
1444
+ }
1445
+
1446
+ this.element = el;
1447
+ var options = this.options;
1448
+
1449
+ var self = this;
1450
+ var keyMaps = {};
1451
+
1452
+ for(var key in options.shortcuts) {
1453
+ // null stands for "do not bind this command"
1454
+ if(options.shortcuts[key] !== null && bindings[key] !== null) {
1455
+ (function(key) {
1456
+ keyMaps[fixShortcut(options.shortcuts[key])] = function() {
1457
+ bindings[key](self);
1458
+ };
1459
+ })(key);
1460
+ }
1461
+ }
1462
+
1463
+ keyMaps["Enter"] = "newlineAndIndentContinueMarkdownList";
1464
+ keyMaps["Tab"] = "tabAndIndentMarkdownList";
1465
+ keyMaps["Shift-Tab"] = "shiftTabAndUnindentMarkdownList";
1466
+ keyMaps["Esc"] = function(cm) {
1467
+ if(cm.getOption("fullScreen")) toggleFullScreen(self);
1468
+ };
1469
+
1470
+ // match Windows Home/End behaviour
1471
+ if(windows) {
1472
+ keyMaps["Home"] = "goLineLeftSmart";
1473
+ keyMaps["End"] = "goLineRight";
1474
+ }
1475
+
1476
+ document.addEventListener("keydown", function(e) {
1477
+ e = e || window.event;
1478
+
1479
+ if(e.keyCode == 27) {
1480
+ if(self.codemirror.getOption("fullScreen")) toggleFullScreen(self);
1481
+ }
1482
+ }, false);
1483
+
1484
+ var mode, backdrop;
1485
+ if(options.spellChecker !== false) {
1486
+ mode = "spell-checker";
1487
+ backdrop = options.parsingConfig;
1488
+ backdrop.name = "gfm";
1489
+ backdrop.gitHubSpice = false;
1490
+
1491
+ CodeMirrorSpellChecker({
1492
+ codeMirrorInstance: CodeMirror
1493
+ });
1494
+ } else {
1495
+ mode = options.parsingConfig;
1496
+ mode.name = "gfm";
1497
+ mode.gitHubSpice = false;
1498
+ }
1499
+
1500
+ this.codemirror = CodeMirror.fromTextArea(el, {
1501
+ mode: mode,
1502
+ backdrop: backdrop,
1503
+ theme: "paper",
1504
+ tabSize: (options.tabSize != undefined) ? options.tabSize : 2,
1505
+ indentUnit: (options.tabSize != undefined) ? options.tabSize : 2,
1506
+ indentWithTabs: (options.indentWithTabs === false) ? false : true,
1507
+ lineNumbers: false,
1508
+ autofocus: (options.autofocus === true) ? true : false,
1509
+ extraKeys: keyMaps,
1510
+ lineWrapping: (options.lineWrapping === false) ? false : true,
1511
+ allowDropFileTypes: ["text/plain"],
1512
+ placeholder: options.placeholder || el.getAttribute("placeholder") || "",
1513
+ styleSelectedText: (options.styleSelectedText != undefined) ? options.styleSelectedText : true
1514
+ });
1515
+
1516
+ if(options.forceSync === true) {
1517
+ var cm = this.codemirror;
1518
+ cm.on("change", function() {
1519
+ cm.save();
1520
+ });
1521
+ }
1522
+
1523
+ this.gui = {};
1524
+
1525
+ if(options.toolbar !== false) {
1526
+ this.gui.toolbar = this.createToolbar();
1527
+ }
1528
+ if(options.status !== false) {
1529
+ this.gui.statusbar = this.createStatusbar();
1530
+ }
1531
+ if(options.autosave != undefined && options.autosave.enabled === true) {
1532
+ this.autosave();
1533
+ }
1534
+
1535
+ this.gui.sideBySide = this.createSideBySide();
1536
+
1537
+ this._rendered = this.element;
1538
+
1539
+
1540
+ // Fixes CodeMirror bug (#344)
1541
+ var temp_cm = this.codemirror;
1542
+ setTimeout(function() {
1543
+ temp_cm.refresh();
1544
+ }.bind(temp_cm), 0);
1545
+ };
1546
+
1547
+ // Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem throw QuotaExceededError. We're going to detect this and set a variable accordingly.
1548
+ function isLocalStorageAvailable() {
1549
+ if(typeof localStorage === "object") {
1550
+ try {
1551
+ localStorage.setItem("smde_localStorage", 1);
1552
+ localStorage.removeItem("smde_localStorage");
1553
+ } catch(e) {
1554
+ return false;
1555
+ }
1556
+ } else {
1557
+ return false;
1558
+ }
1559
+
1560
+ return true;
1561
+ }
1562
+
1563
+ SimpleMDE.prototype.autosave = function() {
1564
+ if(isLocalStorageAvailable()) {
1565
+ var simplemde = this;
1566
+
1567
+ if(this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
1568
+ console.log("SimpleMDE: You must set a uniqueId to use the autosave feature");
1569
+ return;
1570
+ }
1571
+
1572
+ if(simplemde.element.form != null && simplemde.element.form != undefined) {
1573
+ simplemde.element.form.addEventListener("submit", function() {
1574
+ localStorage.removeItem("smde_" + simplemde.options.autosave.uniqueId);
1575
+ });
1576
+ }
1577
+
1578
+ if(this.options.autosave.loaded !== true) {
1579
+ if(typeof localStorage.getItem("smde_" + this.options.autosave.uniqueId) == "string" && localStorage.getItem("smde_" + this.options.autosave.uniqueId) != "") {
1580
+ this.codemirror.setValue(localStorage.getItem("smde_" + this.options.autosave.uniqueId));
1581
+ this.options.autosave.foundSavedValue = true;
1582
+ }
1583
+
1584
+ this.options.autosave.loaded = true;
1585
+ }
1586
+
1587
+ localStorage.setItem("smde_" + this.options.autosave.uniqueId, simplemde.value());
1588
+
1589
+ var el = document.getElementById("autosaved");
1590
+ if(el != null && el != undefined && el != "") {
1591
+ var d = new Date();
1592
+ var hh = d.getHours();
1593
+ var m = d.getMinutes();
1594
+ var dd = "am";
1595
+ var h = hh;
1596
+ if(h >= 12) {
1597
+ h = hh - 12;
1598
+ dd = "pm";
1599
+ }
1600
+ if(h == 0) {
1601
+ h = 12;
1602
+ }
1603
+ m = m < 10 ? "0" + m : m;
1604
+
1605
+ el.innerHTML = "Autosaved: " + h + ":" + m + " " + dd;
1606
+ }
1607
+
1608
+ this.autosaveTimeoutId = setTimeout(function() {
1609
+ simplemde.autosave();
1610
+ }, this.options.autosave.delay || 10000);
1611
+ } else {
1612
+ console.log("SimpleMDE: localStorage not available, cannot autosave");
1613
+ }
1614
+ };
1615
+
1616
+ SimpleMDE.prototype.clearAutosavedValue = function() {
1617
+ if(isLocalStorageAvailable()) {
1618
+ if(this.options.autosave == undefined || this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
1619
+ console.log("SimpleMDE: You must set a uniqueId to clear the autosave value");
1620
+ return;
1621
+ }
1622
+
1623
+ localStorage.removeItem("smde_" + this.options.autosave.uniqueId);
1624
+ } else {
1625
+ console.log("SimpleMDE: localStorage not available, cannot autosave");
1626
+ }
1627
+ };
1628
+
1629
+ SimpleMDE.prototype.createSideBySide = function() {
1630
+ var cm = this.codemirror;
1631
+ var wrapper = cm.getWrapperElement();
1632
+ var preview = wrapper.nextSibling;
1633
+
1634
+ if(!preview || !/editor-preview-side/.test(preview.className)) {
1635
+ preview = document.createElement("div");
1636
+ preview.className = "editor-preview-side";
1637
+ wrapper.parentNode.insertBefore(preview, wrapper.nextSibling);
1638
+ }
1639
+
1640
+ // Syncs scroll editor -> preview
1641
+ var cScroll = false;
1642
+ var pScroll = false;
1643
+ cm.on("scroll", function(v) {
1644
+ if(cScroll) {
1645
+ cScroll = false;
1646
+ return;
1647
+ }
1648
+ pScroll = true;
1649
+ var height = v.getScrollInfo().height - v.getScrollInfo().clientHeight;
1650
+ var ratio = parseFloat(v.getScrollInfo().top) / height;
1651
+ var move = (preview.scrollHeight - preview.clientHeight) * ratio;
1652
+ preview.scrollTop = move;
1653
+ });
1654
+
1655
+ // Syncs scroll preview -> editor
1656
+ preview.onscroll = function() {
1657
+ if(pScroll) {
1658
+ pScroll = false;
1659
+ return;
1660
+ }
1661
+ cScroll = true;
1662
+ var height = preview.scrollHeight - preview.clientHeight;
1663
+ var ratio = parseFloat(preview.scrollTop) / height;
1664
+ var move = (cm.getScrollInfo().height - cm.getScrollInfo().clientHeight) * ratio;
1665
+ cm.scrollTo(0, move);
1666
+ };
1667
+ return preview;
1668
+ };
1669
+
1670
+ SimpleMDE.prototype.createToolbar = function(items) {
1671
+ items = items || this.options.toolbar;
1672
+
1673
+ if(!items || items.length === 0) {
1674
+ return;
1675
+ }
1676
+ var i;
1677
+ for(i = 0; i < items.length; i++) {
1678
+ if(toolbarBuiltInButtons[items[i]] != undefined) {
1679
+ items[i] = toolbarBuiltInButtons[items[i]];
1680
+ }
1681
+ }
1682
+
1683
+ var bar = document.createElement("div");
1684
+ bar.className = "editor-toolbar";
1685
+
1686
+ var self = this;
1687
+
1688
+ var toolbarData = {};
1689
+ self.toolbar = items;
1690
+
1691
+ for(i = 0; i < items.length; i++) {
1692
+ if(items[i].name == "guide" && self.options.toolbarGuideIcon === false)
1693
+ continue;
1694
+
1695
+ if(self.options.hideIcons && self.options.hideIcons.indexOf(items[i].name) != -1)
1696
+ continue;
1697
+
1698
+ // Fullscreen does not work well on mobile devices (even tablets)
1699
+ // In the future, hopefully this can be resolved
1700
+ if((items[i].name == "fullscreen" || items[i].name == "side-by-side") && isMobile())
1701
+ continue;
1702
+
1703
+
1704
+ // Don't include trailing separators
1705
+ if(items[i] === "|") {
1706
+ var nonSeparatorIconsFollow = false;
1707
+
1708
+ for(var x = (i + 1); x < items.length; x++) {
1709
+ if(items[x] !== "|" && (!self.options.hideIcons || self.options.hideIcons.indexOf(items[x].name) == -1)) {
1710
+ nonSeparatorIconsFollow = true;
1711
+ }
1712
+ }
1713
+
1714
+ if(!nonSeparatorIconsFollow)
1715
+ continue;
1716
+ }
1717
+
1718
+
1719
+ // Create the icon and append to the toolbar
1720
+ (function(item) {
1721
+ var el;
1722
+ if(item === "|") {
1723
+ el = createSep();
1724
+ } else {
1725
+ el = createIcon(item, self.options.toolbarTips, self.options.shortcuts);
1726
+ }
1727
+
1728
+ // bind events, special for info
1729
+ if(item.action) {
1730
+ if(typeof item.action === "function") {
1731
+ el.onclick = function(e) {
1732
+ e.preventDefault();
1733
+ item.action(self);
1734
+ };
1735
+ } else if(typeof item.action === "string") {
1736
+ el.href = item.action;
1737
+ el.target = "_blank";
1738
+ }
1739
+ }
1740
+
1741
+ toolbarData[item.name || item] = el;
1742
+ bar.appendChild(el);
1743
+ })(items[i]);
1744
+ }
1745
+
1746
+ self.toolbarElements = toolbarData;
1747
+
1748
+ var cm = this.codemirror;
1749
+ cm.on("cursorActivity", function() {
1750
+ var stat = getState(cm);
1751
+
1752
+ for(var key in toolbarData) {
1753
+ (function(key) {
1754
+ var el = toolbarData[key];
1755
+ if(stat[key]) {
1756
+ el.className += " active";
1757
+ } else if(key != "fullscreen" && key != "side-by-side" && key != "spellcheck" && key != "hemmingway") {
1758
+ el.className = el.className.replace(/\s*active\s*/g, "");
1759
+ }
1760
+ })(key);
1761
+ }
1762
+ });
1763
+
1764
+ var cmWrapper = cm.getWrapperElement();
1765
+ cmWrapper.parentNode.insertBefore(bar, cmWrapper);
1766
+ return bar;
1767
+ };
1768
+
1769
+ SimpleMDE.prototype.createStatusbar = function(status) {
1770
+ // Initialize
1771
+ status = status || this.options.status;
1772
+ var options = this.options;
1773
+ var cm = this.codemirror;
1774
+
1775
+
1776
+ // Make sure the status variable is valid
1777
+ if(!status || status.length === 0)
1778
+ return;
1779
+
1780
+
1781
+ // Set up the built-in items
1782
+ var items = [];
1783
+ var i, onUpdate, defaultValue;
1784
+
1785
+ for(i = 0; i < status.length; i++) {
1786
+ // Reset some values
1787
+ onUpdate = undefined;
1788
+ defaultValue = undefined;
1789
+
1790
+
1791
+ // Handle if custom or not
1792
+ if(typeof status[i] === "object") {
1793
+ items.push({
1794
+ className: status[i].className,
1795
+ defaultValue: status[i].defaultValue,
1796
+ onUpdate: status[i].onUpdate
1797
+ });
1798
+ } else {
1799
+ var name = status[i];
1800
+
1801
+ if(name === "words") {
1802
+ defaultValue = function(el) {
1803
+ el.innerHTML = wordCount(cm.getValue());
1804
+ };
1805
+ onUpdate = function(el) {
1806
+ el.innerHTML = wordCount(cm.getValue());
1807
+ };
1808
+ } else if(name === "lines") {
1809
+ defaultValue = function(el) {
1810
+ el.innerHTML = cm.lineCount();
1811
+ };
1812
+ onUpdate = function(el) {
1813
+ el.innerHTML = cm.lineCount();
1814
+ };
1815
+ } else if(name === "cursor") {
1816
+ defaultValue = function(el) {
1817
+ el.innerHTML = "0:0";
1818
+ };
1819
+ onUpdate = function(el) {
1820
+ var pos = cm.getCursor();
1821
+ el.innerHTML = pos.line + ":" + pos.ch;
1822
+ };
1823
+ } else if(name === "autosave") {
1824
+ defaultValue = function(el) {
1825
+ if(options.autosave != undefined && options.autosave.enabled === true) {
1826
+ el.setAttribute("id", "autosaved");
1827
+ }
1828
+ };
1829
+ }
1830
+
1831
+ items.push({
1832
+ className: name,
1833
+ defaultValue: defaultValue,
1834
+ onUpdate: onUpdate
1835
+ });
1836
+ }
1837
+ }
1838
+
1839
+
1840
+ // Create element for the status bar
1841
+ var bar = document.createElement("div");
1842
+ bar.className = "editor-statusbar";
1843
+
1844
+
1845
+ // Create a new span for each item
1846
+ for(i = 0; i < items.length; i++) {
1847
+ // Store in temporary variable
1848
+ var item = items[i];
1849
+
1850
+
1851
+ // Create span element
1852
+ var el = document.createElement("span");
1853
+ el.className = item.className;
1854
+
1855
+
1856
+ // Ensure the defaultValue is a function
1857
+ if(typeof item.defaultValue === "function") {
1858
+ item.defaultValue(el);
1859
+ }
1860
+
1861
+
1862
+ // Ensure the onUpdate is a function
1863
+ if(typeof item.onUpdate === "function") {
1864
+ // Create a closure around the span of the current action, then execute the onUpdate handler
1865
+ this.codemirror.on("update", (function(el, item) {
1866
+ return function() {
1867
+ item.onUpdate(el);
1868
+ };
1869
+ }(el, item)));
1870
+ }
1871
+
1872
+
1873
+ // Append the item to the status bar
1874
+ bar.appendChild(el);
1875
+ }
1876
+
1877
+
1878
+ // Insert the status bar into the DOM
1879
+ var cmWrapper = this.codemirror.getWrapperElement();
1880
+ cmWrapper.parentNode.insertBefore(bar, cmWrapper.nextSibling);
1881
+ return bar;
1882
+ };
1883
+
1884
+ /**
1885
+ * Get or set the text content.
1886
+ */
1887
+ SimpleMDE.prototype.value = function(val) {
1888
+ if(val === undefined) {
1889
+ return this.codemirror.getValue();
1890
+ } else {
1891
+ this.codemirror.getDoc().setValue(val);
1892
+ return this;
1893
+ }
1894
+ };
1895
+
1896
+
1897
+ /**
1898
+ * Bind static methods for exports.
1899
+ */
1900
+ SimpleMDE.toggleBold = toggleBold;
1901
+ SimpleMDE.toggleItalic = toggleItalic;
1902
+ SimpleMDE.toggleStrikethrough = toggleStrikethrough;
1903
+ SimpleMDE.toggleBlockquote = toggleBlockquote;
1904
+ SimpleMDE.toggleHeadingSmaller = toggleHeadingSmaller;
1905
+ SimpleMDE.toggleHeadingBigger = toggleHeadingBigger;
1906
+ SimpleMDE.toggleHeading1 = toggleHeading1;
1907
+ SimpleMDE.toggleHeading2 = toggleHeading2;
1908
+ SimpleMDE.toggleHeading3 = toggleHeading3;
1909
+ SimpleMDE.toggleCodeBlock = toggleCodeBlock;
1910
+ SimpleMDE.toggleUnorderedList = toggleUnorderedList;
1911
+ SimpleMDE.toggleOrderedList = toggleOrderedList;
1912
+ SimpleMDE.cleanBlock = cleanBlock;
1913
+ SimpleMDE.drawLink = drawLink;
1914
+ SimpleMDE.drawImage = drawImage;
1915
+ SimpleMDE.drawTable = drawTable;
1916
+ SimpleMDE.drawHorizontalRule = drawHorizontalRule;
1917
+ SimpleMDE.undo = undo;
1918
+ SimpleMDE.redo = redo;
1919
+ SimpleMDE.togglePreview = togglePreview;
1920
+ SimpleMDE.toggleSideBySide = toggleSideBySide;
1921
+ SimpleMDE.toggleFullScreen = toggleFullScreen;
1922
+
1923
+ /**
1924
+ * Bind instance methods for exports.
1925
+ */
1926
+ SimpleMDE.prototype.toggleBold = function() {
1927
+ toggleBold(this);
1928
+ };
1929
+ SimpleMDE.prototype.toggleItalic = function() {
1930
+ toggleItalic(this);
1931
+ };
1932
+ SimpleMDE.prototype.toggleStrikethrough = function() {
1933
+ toggleStrikethrough(this);
1934
+ };
1935
+ SimpleMDE.prototype.toggleBlockquote = function() {
1936
+ toggleBlockquote(this);
1937
+ };
1938
+ SimpleMDE.prototype.toggleHeadingSmaller = function() {
1939
+ toggleHeadingSmaller(this);
1940
+ };
1941
+ SimpleMDE.prototype.toggleHeadingBigger = function() {
1942
+ toggleHeadingBigger(this);
1943
+ };
1944
+ SimpleMDE.prototype.toggleHeading1 = function() {
1945
+ toggleHeading1(this);
1946
+ };
1947
+ SimpleMDE.prototype.toggleHeading2 = function() {
1948
+ toggleHeading2(this);
1949
+ };
1950
+ SimpleMDE.prototype.toggleHeading3 = function() {
1951
+ toggleHeading3(this);
1952
+ };
1953
+ SimpleMDE.prototype.toggleCodeBlock = function() {
1954
+ toggleCodeBlock(this);
1955
+ };
1956
+ SimpleMDE.prototype.toggleUnorderedList = function() {
1957
+ toggleUnorderedList(this);
1958
+ };
1959
+ SimpleMDE.prototype.toggleOrderedList = function() {
1960
+ toggleOrderedList(this);
1961
+ };
1962
+ SimpleMDE.prototype.cleanBlock = function() {
1963
+ cleanBlock(this);
1964
+ };
1965
+ SimpleMDE.prototype.drawLink = function() {
1966
+ drawLink(this);
1967
+ };
1968
+ SimpleMDE.prototype.drawImage = function() {
1969
+ drawImage(this);
1970
+ };
1971
+ SimpleMDE.prototype.drawTable = function() {
1972
+ drawTable(this);
1973
+ };
1974
+ SimpleMDE.prototype.drawHorizontalRule = function() {
1975
+ drawHorizontalRule(this);
1976
+ };
1977
+ SimpleMDE.prototype.undo = function() {
1978
+ undo(this);
1979
+ };
1980
+ SimpleMDE.prototype.redo = function() {
1981
+ redo(this);
1982
+ };
1983
+ SimpleMDE.prototype.togglePreview = function() {
1984
+ togglePreview(this);
1985
+ };
1986
+ SimpleMDE.prototype.toggleSideBySide = function() {
1987
+ toggleSideBySide(this);
1988
+ };
1989
+ SimpleMDE.prototype.toggleFullScreen = function() {
1990
+ toggleFullScreen(this);
1991
+ };
1992
+
1993
+ SimpleMDE.prototype.isPreviewActive = function() {
1994
+ var cm = this.codemirror;
1995
+ var wrapper = cm.getWrapperElement();
1996
+ var preview = wrapper.lastChild;
1997
+
1998
+ return /editor-preview-active/.test(preview.className);
1999
+ };
2000
+
2001
+ SimpleMDE.prototype.isSideBySideActive = function() {
2002
+ var cm = this.codemirror;
2003
+ var wrapper = cm.getWrapperElement();
2004
+ var preview = wrapper.nextSibling;
2005
+
2006
+ return /editor-preview-active-side/.test(preview.className);
2007
+ };
2008
+
2009
+ SimpleMDE.prototype.isFullscreenActive = function() {
2010
+ var cm = this.codemirror;
2011
+
2012
+ return cm.getOption("fullScreen");
2013
+ };
2014
+
2015
+ SimpleMDE.prototype.getState = function() {
2016
+ var cm = this.codemirror;
2017
+
2018
+ return getState(cm);
2019
+ };
2020
+
2021
+ SimpleMDE.prototype.toTextArea = function() {
2022
+ var cm = this.codemirror;
2023
+ var wrapper = cm.getWrapperElement();
2024
+
2025
+ if(wrapper.parentNode) {
2026
+ if(this.gui.toolbar) {
2027
+ wrapper.parentNode.removeChild(this.gui.toolbar);
2028
+ }
2029
+ if(this.gui.statusbar) {
2030
+ wrapper.parentNode.removeChild(this.gui.statusbar);
2031
+ }
2032
+ if(this.gui.sideBySide) {
2033
+ wrapper.parentNode.removeChild(this.gui.sideBySide);
2034
+ }
2035
+ }
2036
+
2037
+ cm.toTextArea();
2038
+
2039
+ if(this.autosaveTimeoutId) {
2040
+ clearTimeout(this.autosaveTimeoutId);
2041
+ this.autosaveTimeoutId = undefined;
2042
+ this.clearAutosavedValue();
2043
+ }
2044
+ };
2045
+
2046
+ module.exports = SimpleMDE;