Skip to content
Permalink
Newer
Older
100644 467 lines (430 sloc) 21.6 KB
1
/* global define, jQuery, commonmark, emoji */
2
/* global require, module */
3
4
(function(factory) {
5
if (typeof define === 'function' && define.amd) {
6
define(['jquery', 'commonmark'], factory);
7
} else if (typeof exports === 'object') {
8
factory(require('jquery'), require('commonmark'));
10
factory(jQuery, commonmark);
12
}(function($, commonmark) {
13
var MarkdownRenderer = function(reader, writer) {
14
if (reader == null) {
15
this.reader = new commonmark.Parser();
16
} else {
17
this.reader = reader;
18
}
19
if (writer == null) {
20
this.writer = new commonmark.HtmlRenderer({safe: true});
21
} else {
22
this.writer = writer;
23
}
24
if (typeof emoji !== 'undefined') {
25
if (window.STATIC_URL) {
26
emoji.sheet_path = window.STATIC_URL +
27
'emoji-data/sheet_apple_64.png';
28
}
29
emoji.use_sheet = true;
30
// Temporary workaround for img_path issue:
31
// https://github.com/iamcal/js-emoji/issues/47
32
emoji.img_sets[emoji.img_set].sheet = emoji.sheet_path;
33
}
34
};
35
36
/**
37
* MarkdownRenderer.render does a few things to its input text:
38
* - Renders the text with CommonMark
39
* - Transforms emojis
40
* - Turns URLs into <a> tags
41
*/
42
MarkdownRenderer.prototype.render = function(text) {
43
var parsed = this.reader.parse(text);
44
var rendered = this.writer.render(parsed);
45
if (typeof window !== 'undefined' &&
46
typeof window.linkifyHtml === 'function'
47
) {
48
rendered = window.linkifyHtml(rendered);
49
}
50
if (typeof emoji !== 'undefined' &&
51
typeof emoji.replace_colons === 'function'
52
) {
53
rendered = emoji.replace_colons(rendered);
54
}
55
return rendered;
56
};
57
58
var MarkdownPreview = function($textarea, $previewArea, $reader, $writer) {
59
this.renderer = new MarkdownRenderer($reader, $writer);
60
this.$textarea = $textarea;
61
this.$previewArea = $previewArea;
62
this._startEventHandler();
63
};
64
65
/**
66
* Refresh the markdown preview, given the source text.
67
*/
68
MarkdownPreview.prototype.refresh = function(text) {
69
var rendered = this.renderer.render(text);
70
this.$previewArea.html(rendered);
71
};
72
73
MarkdownPreview.prototype._startEventHandler = function() {
74
var me = this;
75
this.$textarea.on('change keyup', function(e) {
76
var comment = $(e.target).val();
77
me.refresh(comment);
78
});
79
};
80
81
var MarkdownToolbarController = function() {
82
this.prefixLength = null;
83
this.selectionStart = null;
84
this.selectionEnd = null;
85
};
86
87
/**
88
* Given a multiline text string, replace the newlines with
89
* ascending numbers to make an ordered list.
90
*/
91
MarkdownToolbarController.prototype.makeOrderedList = function(text) {
92
var lines = text.split(/\r?\n|/);
93
var i;
94
for (i = 0; i < lines.length; i++) {
95
lines[i] = (i + 1) + '. ' + lines[i];
96
if (i > 0) {
97
lines[i] = '\n' + lines[i];
98
}
99
}
100
return lines.join('');
101
};
102
103
MarkdownToolbarController.prototype.render = function(
104
d, selectionStart, selectionEnd, text
105
) {
106
var selectedText = text.substr(selectionStart, selectionEnd - selectionStart);
107
if (d.prefix === '# ' && selectionStart !== 0 && text.substr(selectionStart -2, 1) === '#') {
108
d.prefix = '#';
109
selectionStart -= 2;
110
}
111
var suffixdiff = 0;
112
var prefixdiff = 0;
113
if (selectedText.match(/\n/) &&
114
d.blockPrefix &&
115
d.blockSuffix
116
) {
117
if (d.blockPrefix) {
118
text = this.renderBlockPrefix(
119
selectionStart, selectionEnd, d, text);
120
prefixdiff += d.blockPrefix.length + 1;
121
}
122
123
if (d.blockSuffix) {
124
text = this.renderBlockSuffix(
125
selectionStart, selectionEnd, d.blockPrefix.length,
127
suffixdiff += d.blockSuffix.length + 1;
128
}
129
} else {
130
if (d.prefix) {
131
text = this.renderPrefix(
132
selectionStart, selectionEnd, d, text);
133
prefixdiff += d.prefix.length;
134
}
135
136
if (d.suffix) {
137
text = this.renderSuffix(
138
selectionStart, selectionEnd, this.prefixLength,
139
d, text);
140
suffixdiff += d.suffix.length;
Nov 18, 2018
144
if (d.prefix === '#' && text.substr(selectionStart, 1) === '#') {
145
selectionStart += 2;
146
}
147
148
if (d.prefix === '![](url)') {
149
this.selectionStart = selectionEnd + 4;
150
this.selectionEnd = selectionEnd + 7;
151
} else if (d.multiline && selectedText.match(/\n/)) {
152
this.selectionStart = selectionStart;
153
this.selectionEnd = selectionEnd + (prefixdiff + suffixdiff) * (selectedText.match(/\n/g).length + 1);
155
this.selectionStart = selectionStart + prefixdiff;
156
this.selectionEnd = selectionEnd + prefixdiff;
157
}
158
159
return text;
160
};
161
162
MarkdownToolbarController.prototype.renderPrefix = function(
163
selectionStart, selectionEnd, d, text
164
) {
165
this.prefixLength = d.prefix.length;
166
var s;
167
168
if (d.multiline) {
169
var before = text.substr(0, selectionStart);
170
var snippet = text.substr(selectionStart, selectionEnd - selectionStart);
171
var after = text.substr(selectionEnd, text.length - selectionEnd);
172
if (d.prefix === '1. ') {
173
// Create the numbered list
174
snippet = this.makeOrderedList(snippet);
175
} else {
176
snippet = snippet.replace(/^/, d.prefix);
177
snippet = snippet.replace(/\n/g, '\n' + d.prefix);
178
}
179
s = before + snippet + after;
180
} else {
181
s = text.substr(0, selectionStart);
182
s += d.prefix;
183
s += text.substr(selectionStart, text.length - selectionStart);
184
}
185
return s;
186
};
187
188
MarkdownToolbarController.prototype.renderSuffix = function(
189
selectionStart, selectionEnd, prefixLength, d, text
190
) {
191
selectionEnd += prefixLength;
192
var s = text.substr(0, selectionEnd);
193
s += d.suffix;
194
s += text.substr(selectionEnd, text.length - selectionEnd);
195
return s;
196
};
197
198
MarkdownToolbarController.prototype.renderBlockPrefix = function(
199
selectionStart, selectionEnd, d, text
200
) {
201
this.prefixLength = d.blockPrefix.length + 1;
202
var s = text.substr(0, selectionStart);
203
s += d.blockPrefix + '\n';
204
s += text.substr(selectionStart, text.length - selectionStart);
205
return s;
206
};
207
208
MarkdownToolbarController.prototype.renderBlockSuffix = function(
209
selectionStart, selectionEnd, blockPrefixLength, d, text
210
) {
211
selectionEnd += blockPrefixLength + 1;
212
var s = text.substr(0, selectionEnd);
213
s += '\n' + d.blockSuffix;
214
s += text.substr(selectionEnd, text.length - selectionEnd);
215
return s;
216
};
217
218
var MarkdownToolbar = function($toolbar, $textarea, markdownPreview) {
219
this.$toolbar = $toolbar;
220
this.$textarea = $textarea;
221
this.markdownPreview = markdownPreview;
222
this.lastHotkey = null;
223
this.lastText = null;
224
this.lastStart = null;
225
this.lastEnd = null;
226
this.init();
227
};
228
229
MarkdownToolbar.prototype.init = function() {
230
var me = this;
231
232
this.$toolbar.find('button.js-toolbar-item').on('click', function() {
233
var $this = $(this);
234
235
// Get data from button element
236
var buttonData = $this.data();
237
238
// Get cursor position and textarea's text
239
buttonData.selectionStart = me.$textarea[0].selectionStart;
240
buttonData.selectionEnd = me.$textarea[0].selectionEnd;
241
var text = me.$textarea.val();
242
243
if (buttonData.hotkey === 'p') {
244
if (me.markdownPreview) {
245
me.markdownPreview.refresh(me.$textarea.val());
246
if (me.markdownPreview.$previewArea.attr('auto_preview') === true) {
247
me.markdownPreview.$previewArea.show();
Jul 15, 2019
248
me.markdownPreview.$previewArea.attr('auto_preview', false);
249
} else {
250
me.markdownPreview.$previewArea.toggle();
251
}
252
me.markdownPreview.$previewArea.width(me.$textarea.outerWidth());
253
}
254
return;
255
} else if (undoMarkdown(me, buttonData)) {
256
var diff = text.length - me.lastText.length;
257
if (buttonData.multiline) {
258
buttonData.selectionEnd -= diff;
259
} else {
260
buttonData.selectionStart -= diff / 2;
261
buttonData.selectionEnd -= diff / 2;
263
text = me.lastText;
264
me.lastStart = buttonData.selectionStart;
265
me.lastEnd = buttonData.selectionEnd;
266
me.lastHotkey = null;
267
} else {
268
var mtc = new MarkdownToolbarController();
269
me.lastText = text;
270
text = mtc.render(
271
buttonData, buttonData.selectionStart, buttonData.selectionEnd, text);
272
me.lastStart = mtc.selectionStart;
273
me.lastEnd = mtc.selectionEnd;
274
me.lastHotkey = buttonData.hotkey;
275
}
276
277
me.$textarea.val(text);
278
279
// Reset cursor to original state
280
me.$textarea.focus();
281
me.$textarea[0].setSelectionRange(me.lastStart, me.lastEnd);
283
// Refresh the preview view if it exists.
284
if (me.markdownPreview &&
285
typeof me.markdownPreview.refresh === 'function'
286
) {
287
me.markdownPreview.refresh(me.$textarea.val());
288
me.markdownPreview.$previewArea.width(me.$textarea.outerWidth());
292
function undoMarkdown(me, buttonData) {
293
return (buttonData.hotkey === me.lastHotkey &&
294
buttonData.hotkey !== 'h' && me.lastText !== null &&
295
buttonData.selectionStart == me.lastStart &&
296
buttonData.selectionEnd == me.lastEnd);
297
}
298
299
this.$textarea.on('keyup', function() {
300
me.lastHotkey = null;
301
});
302
303
// Handle a resize of the textarea - 'resize' event doesn't work
304
// store init (default) state
305
this.$textarea.data('x', this.$textarea.outerWidth());
306
this.$textarea.data('y', this.$textarea.outerHeight());
307
308
this.$textarea.mouseup(function(){
309
var $this = jQuery(this);
310
311
if ( $this.outerWidth() != $this.data('x')
312
|| $this.outerHeight() != $this.data('y') )
313
{
314
// Resize Action Here
315
me.markdownPreview.$previewArea.width(me.$textarea.outerWidth());
316
}
317
318
// store new height/width
319
$this.data('x', $this.outerWidth());
320
$this.data('y', $this.outerHeight());
321
});
322
};
323
324
var toolbarMarkup = '<div class="markdown-toolbar">' +
325
'<div class="toolbar-group">' +
326
'<div class="toolbar-item dropdown js-menu-container">' +
327
'</div>' +
328
'<button type="button"' +
329
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
330
'title="Add header text"' +
331
'tabindex="-1"' +
332
'data-prefix="# "' +
333
'data-hotkey="h"' +
334
'data-ga-click="Markdown Toolbar, click, heading"' +
335
'data-surround-with-newlines="true">' +
336
'<svg class="octicon octicon-text-size" viewBox="0 0 18 16" version="1.1" width="18" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M13.62 9.08L12.1 3.66h-.06l-1.5 5.42h3.08zM5.7 10.13S4.68 6.52 4.53 6.02h-.08l-1.13 4.11H5.7zM17.31 14h-2.25l-.95-3.25h-4.07L9.09 14H6.84l-.69-2.33H2.87L2.17 14H0l3.3-9.59h2.5l2.17 6.34L10.86 2h2.52l3.94 12h-.01z"></path></svg>' +
337
'</button>' +
338
'<button type="button"' +
339
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
340
'title="Add bold text"' +
341
'tabindex="-1"' +
342
'data-prefix="**"' +
343
'data-suffix="**"' +
344
'data-hotkey="b"' +
345
'data-ga-click="Markdown Toolbar, click, bold">' +
346
'<svg aria-hidden="true" class="octicon octicon-bold" height="16" role="img" version="1.1" viewBox="0 0 10 16" width="10"><path d="M0 2h3.83c2.48 0 4.3 0.75 4.3 2.95 0 1.14-0.63 2.23-1.67 2.61v0.06c1.33 0.3 2.3 1.23 2.3 2.86 0 2.39-1.97 3.52-4.61 3.52H0V2z m3.66 4.95c1.67 0 2.38-0.66 2.38-1.69 0-1.17-0.78-1.61-2.34-1.61H2.13v3.3h1.53z m0.27 5.39c1.77 0 2.75-0.64 2.75-1.98 0-1.27-0.95-1.81-2.75-1.81H2.13v3.8h1.8z"></path></svg>' +
347
'</button>' +
348
'<button type="button"' +
349
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
350
'title="Add italic text"' +
351
'tabindex="-1"' +
352
'data-prefix="_"' +
353
'data-suffix="_"' +
354
'data-hotkey="i"' +
355
'data-ga-click="Markdown Toolbar, click, italic">' +
356
'<svg aria-hidden="true" class="octicon octicon-italic" height="16" role="img" version="1.1" viewBox="0 0 6 16" width="6"><path d="M2.81 5h1.98L3 14H1l1.81-9z m0.36-2.7c0-0.7 0.58-1.3 1.33-1.3 0.56 0 1.13 0.38 1.13 1.03 0 0.75-0.59 1.3-1.33 1.3-0.58 0-1.13-0.38-1.13-1.03z"></path></svg>' +
357
'</button>' +
358
'</div>' +
359
'<div class="toolbar-group">' +
360
'<button type="button"' +
361
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
362
'title="Insert a quote"' +
363
'tabindex="-1"' +
364
'data-prefix="> "' +
365
'data-hotkey="q"' +
366
'data-multiline="true"' +
367
'data-ga-click="Markdown Toolbar, click, quote"' +
368
'data-surround-with-newlines="true">' +
369
'<svg aria-hidden="true" class="octicon octicon-quote" height="16" role="img" version="1.1" viewBox="0 0 14 16" width="14"><path d="M6.16 3.17C3.73 4.73 2.55 6.34 2.55 9.03c0.16-0.05 0.3-0.05 0.44-0.05 1.27 0 2.5 0.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61C1.09 14 0 12.48 0 9.75 0 5.95 1.75 3.22 5.02 1.33l1.14 1.84z m7 0C10.73 4.73 9.55 6.34 9.55 9.03c0.16-0.05 0.3-0.05 0.44-0.05 1.27 0 2.5 0.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.89 0-2.98-1.52-2.98-4.25 0-3.8 1.75-6.53 5.02-8.42l1.14 1.84z"></path></svg>' +
370
'</button>' +
371
'<button type="button"' +
372
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
373
'title="Insert code" tabindex="-1"' +
374
'data-prefix="`"' +
375
'data-suffix="`"' +
376
'data-hotkey="c"' +
377
'data-block-prefix="```"' +
378
'data-block-suffix="```"' +
379
'data-ga-click="Markdown Toolbar, click, code">' +
380
'<svg aria-hidden="true" class="octicon octicon-code" height="16" role="img" version="1.1" viewBox="0 0 14 16" width="14"><path d="M9.5 3l-1.5 1.5 3.5 3.5L8 11.5l1.5 1.5 4.5-5L9.5 3zM4.5 3L0 8l4.5 5 1.5-1.5L2.5 8l3.5-3.5L4.5 3z"></path></svg>' +
381
'</button>' +
382
'<button type="button"' +
383
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
384
'title="Add a bulleted list"' +
385
'tabindex="-1"' +
386
'data-multiline="true"' +
387
'data-prefix="- "' +
388
'data-hotkey="u"' +
389
'data-ga-click="Markdown Toolbar, click, unordered list"' +
390
'data-surround-with-newlines="true">' +
391
'<svg aria-hidden="true" class="octicon octicon-list-unordered" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M2 13c0 0.59 0 1-0.59 1H0.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h0.81c0.59 0 0.59 0.41 0.59 1z m2.59-9h6.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1H4.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1zM1.41 7H0.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1h0.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1z m0-5H0.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1h0.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1z m10 5H4.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1h6.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1z m0 5H4.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1h6.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1z"></path></svg>' +
392
'</button>' +
393
'<button type="button"' +
394
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
395
'title="Add a numbered list"' +
396
'tabindex="-1"' +
397
'data-prefix="1. "' +
398
'data-hotkey="o"' +
399
'data-multiline="true"' +
400
'data-ga-click="Markdown Toolbar, click, ordered list"' +
401
'data-ordered-list="true">' +
402
'<svg aria-hidden="true" class="octicon octicon-list-ordered" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 13c0 0.59 0 1-0.59 1H4.59c-0.59 0-0.59-0.41-0.59-1s0-1 0.59-1h6.81c0.59 0 0.59 0.41 0.59 1zM4.59 4h6.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1H4.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1z m6.81 3H4.59c-0.59 0-0.59 0.41-0.59 1s0 1 0.59 1h6.81c0.59 0 0.59-0.41 0.59-1s0-1-0.59-1zM2 1H1.28C0.98 1.19 0.7 1.25 0.25 1.34v0.66h0.75v2.14H0.16v0.86h2.84v-0.86h-1V1z m0.25 8.13c-0.17 0-0.45 0.03-0.66 0.06 0.53-0.56 1.14-1.25 1.14-1.89-0.02-0.78-0.56-1.3-1.36-1.3-0.59 0-0.97 0.2-1.38 0.64l0.58 0.58c0.19-0.19 0.38-0.38 0.64-0.38 0.28 0 0.48 0.16 0.48 0.52 0 0.53-0.77 1.2-1.7 2.06v0.58h3l-0.09-0.88h-0.66z m-0.08 3.78v-0.03c0.44-0.19 0.64-0.47 0.64-0.86 0-0.7-0.56-1.11-1.44-1.11-0.48 0-0.89 0.19-1.28 0.52l0.55 0.64c0.25-0.2 0.44-0.31 0.69-0.31 0.27 0 0.42 0.13 0.42 0.36 0 0.27-0.2 0.44-0.86 0.44v0.75c0.83 0 0.98 0.17 0.98 0.47 0 0.25-0.23 0.38-0.58 0.38-0.28 0-0.56-0.14-0.81-0.38L0 14.44c0.3 0.36 0.77 0.56 1.41 0.56 0.83 0 1.53-0.41 1.53-1.16 0-0.5-0.31-0.81-0.77-0.94z"></path></svg>' +
403
'</button>' +
404
'</div>' +
405
'<div class="toolbar-group">' +
406
'<button type="button"' +
407
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
408
'title="Add a link" tabindex="-1"' +
409
'data-prefix="["' +
410
'data-suffix="](url)"' +
411
'data-replace-next="url"' +
412
'data-hotkey="k"' +
413
'data-scan-for="https?://"' +
414
'data-ga-click="Markdown Toolbar, click, link">' +
415
'<svg aria-hidden="true" class="octicon octicon-link" height="16" role="img" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1h-1c-1.5 0-3-1.69-3-3.5s1.55-3.5 3-3.5h4c1.45 0 3 1.69 3 3.5 0 1.41-0.91 2.72-2 3.25v-1.16c0.58-0.45 1-1.27 1-2.09 0-1.28-1.02-2.5-2-2.5H4c-0.98 0-2 1.22-2 2.5s1 2.5 2 2.5z m9-3h-1v1h1c1 0 2 1.22 2 2.5s-1.02 2.5-2 2.5H9c-0.98 0-2-1.22-2-2.5 0-0.83 0.42-1.64 1-2.09v-1.16c-1.09 0.53-2 1.84-2 3.25 0 1.81 1.55 3.5 3 3.5h4c1.45 0 3-1.69 3-3.5s-1.5-3.5-3-3.5z"></path></svg>' +
416
'</button>' +
417
'<button type="button"' +
418
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
419
'title="Add an image" tabindex="-1"' +
420
'data-prefix="![](url)"' +
421
'data-replace-next="url"' +
422
'data-hotkey="f"' +
423
'data-ga-click="Markdown Toolbar, click, image">' +
424
'<svg aria-hidden="true" class="octicon octicon-file-media" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M6 5h2v2H6V5zm6-.5V14c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V2c0-.55.45-1 1-1h7.5L12 4.5zM11 5L8 2H1v11l3-5 2 4 2-2 3 3V5z"></path></svg>' +
425
'</button>' +
426
'</div>' +
427
'<div class="toolbar-group">' +
428
'<button type="button"' +
429
'class="js-toolbar-item toolbar-item tooltipped tooltipped-n"' +
430
'title="Toggle Preview"' +
431
'tabindex="-1"' +
432
'data-hotkey="p"' +
433
'data-ga-click="Markdown Toolbar, click, toggle preview"' +
434
'>' +
435
'<svg class="octicon octicon-eye" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"></path></svg>' +
436
'</button>' +
437
'</div>' +
438
'</div>';
439
if (typeof $.fn !== 'undefined') {
440
$.fn.markdownToolbar = function(auto_preview, reader, writer) {
441
var $this = $(this);
442
var $toolbar = $(toolbarMarkup);
443
$this.before($toolbar);
444
var $preview = $('<div class="markdown-preview"></div>');
445
if (auto_preview === false) {
446
$preview.hide();
447
} else {
448
auto_preview = true;
449
}
450
$preview.attr('auto_preview', auto_preview);
451
$this.after($preview);
452
var markdownPreview = undefined;
453
markdownPreview = new MarkdownPreview($this, $preview, reader, writer);
454
455
new MarkdownToolbar($toolbar, $this, markdownPreview);
456
};
457
458
$.fn.markdownToolbar.version = '1.0.0';
459
}
460
461
if (typeof module !== 'undefined') {
462
module.exports = {
463
MarkdownRenderer: MarkdownRenderer,
464
MarkdownToolbarController: MarkdownToolbarController
465
};